PageSourceSearch

https://www.regiobregenzerwald.at/

html regiobregenzerwald.at collected 2026-10-02 12:50:33 UTC 223,576 bytes, 4,438 lines download raw bytes

1
2    <!DOCTYPE html>
3
4
5    <html lang="de">
6
7<head><title>
8	Bregenzerwald - Startseite
9</title>
10    
11
12    <!-- Free Header -->
13<!-- CORE CSS -->
14<link rel="stylesheet" type="text/css" media="all" href="/system/web/GetDocument.ashx?fileid=998472&amp;cts=1603823288" />
15
16
17<!-- TEST CSS -->
18<!-- link rel="stylesheet" type="text/css" media="all" href="http://localhost:3000/css/main.css " / -->
19
20<style type="text/css">
21span.boxVeranstaltungsvorschauTag {
22    display: none;
23}
24.openinghours-info {
25    width: 90%;
26    border-top: 1px dotted rgba(255,255,255,0.5);
27    padding: 0.5em 0 0;
28    color: #fff;
29}
30.openinghours-info ul {
31    margin: 0;
32    padding-left: 1em
33}
34.openinghours-info p, a {
35    color: #fff;
36    margin: 0;
37}
38.section__info {
39background: none!important;
40}
41span.ris_oz_times {
42    text-align: right;
43}
44.apps .app-container>a .app-image {
45    align-self: center;
46    padding-right: 0.5em;
47}
48.abteilungcmsdetail .abt_img_spacer {
49    padding-top: 1em;
50}
51#main .section__footer .map img {
52    padding-left: 0em;
53    max-width: 55%;
54    margin: 0 auto;
55    display: table;
56}
57.backToTop {
58    border: 1px solid #ccc;
59    border-radius: 0.25em;
60    background: #FFF;
61    padding: 0.25em;
62    margin: 0.5em;
63}
64@media all and (-ms-high-contrast:none) {
65     .megamenu > ul > li.wide {
66          position: inherit!important;
67     }
68}
69</style>
70    <link rel="canonical" href="https://www.regiobregenzerwald.at/" />
71
72    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=5" />
73
74    <link rel="stylesheet" type="text/css" href="/system/statV.1789655742/web/css/riscms_pre.css" />
75<link rel="stylesheet" type="text/css" href="/system/statV.1789655742/Javascript/jquery/jquery-ui-1.8.17.min.css" />
76<link rel="stylesheet" type="text/css" media="screen,print" href="/css/startseite2022__pt.css?cts=1788776812" />
77<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick.min.css" />
78<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-theme.min.css" />
79<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-ris.min.css" />
80<link rel="stylesheet" type="text/css" media="screen,print" href="/cdnstatic/system/CSSz/slick/slick-ris-indiv.min.css" />
81<link rel="stylesheet" type="text/css" media="screen,print" href="/system/statV.1789655742/web/css/extensions/2061.css" />
82<link rel="stylesheet" type="text/css" href="/cdnstatic/system/CSSz/fontawesome/css/all.min.css" />
83
84    
85
86    
86<script type="text/javascript">var envurl = "https://www.regiobregenzerwald.at/";</script>
vendor: 2 bytes, line 86
86
87<script type="text/javascript">var rissprachid = "1";</script>
vendor: 2 bytes, line 87
87
88<script type="text/javascript">var allowTracking = false;</script>
vendor: 2 bytes, line 88
88
89<script src="/system/statV.1789655742/Javascript/Jquery/jquery.min_1.7.2.js" type="text/javascript"></script>
vendor: 2 bytes, line 89
89
90<script src="/system/statV.1789655742/Javascript/AdapterUtils.js" type="text/javascript"></script>
vendor: 2 bytes, line 90
90
91<script src="/system/statV.1789655742/Javascript/jquery/jquery-ui-1.8.17.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 91
91
92<script src="/system/statV.1789655742/Javascript/formular/jquery.validate.js" type="text/javascript"></script>
vendor: 2 bytes, line 92
92
93<script type="text/javascript">$(document).ready(function(){
94                    jQuery.extend(jQuery.validator.messages, {
95                        required: "Dieses Feld ist Pflicht!",
96                        email: "Bitte geben Sie eine korrekte E-Mail Adresse an!",
97                        url: "Bitte geben Sie einen korrekten Link an!",
98                        number: "Bitte geben Sie eine Zahl an!",
99                        maxlength: "Bitte geben Sie nicht mehr als {0} Zeichen ein.",
100                        minlength: "Bitte geben Sie mindestens {0} Zeichen ein.",
101                        max: $.validator.format( "Bitte geben Sie einen Wert kleiner oder gleich {0} ein." ),
102		                min: $.validator.format( "Bitte geben Sie einen Wert größer oder gleich {0} ein." )
103                    });
104	                $('form').each(function() {  
105		                var $frm = $(this);
106                        if($frm.data('validator') == undefined){
107			                $frm.validate( {ignoreTitle: true, errorClass: "risFrmError"});
108			                $('[type="submit"]').click(function(){
109				                var frmid = $(this).data("formonr");
110                                if (typeof frmid !== 'undefined')
111                                {
112					                $(this).closest('form').validate().settings.ignore = ":not([data-formonr='" + frmid + "'])";
113				                }
114			                });
115		                }
116                    });
117                });
118            </script>
vendor: 2 bytes, line 118
118
119<script src="/system/statV.1789655742/Javascript/jquery/jquery.lazy.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 119
119
120<script src="/system/statV.1789655742/Javascript/jquery/jquery.lazy.plugins.min.js" type="text/javascript" async="async"></script>
vendor: 2 bytes, line 120
120
121<script src="/system/statV.1789655742/Javascript/fingerprint.js" type="text/javascript"></script>
vendor: 2 bytes, line 121
121
122<script src="/system/statV.1789655742/JavaScript/MenuAdapter.js" type="text/javascript"></script>
vendor: 2 bytes, line 122
122
123<script src="/cdnstatic/system/Javascript/ris/mobileMenu.js" type="text/javascript"></script>
vendor: 2 bytes, line 123
123
124<script type="text/javascript">initMenu(1, 225047683, [{"sprachid":1,"datei":"german.gif","langlink":"","bez":"deutsch","title":"deutsch"}], 'Startseite', 'Suchbegriffe', 'Suche starten')</script>
vendor: 2 bytes, line 124
124
125<script src="/system/statV.1789655742/Javascript/template.js" type="text/javascript"></script>
vendor: 2 bytes, line 125
125
126<script src="/cdnstatic/system/Javascriptz/slick/slick.min.js" type="text/javascript"></script>
vendor: 2 bytes, line 126
126
127<script type="text/javascript">var mobAppSettings = {"mobileApps":[{"name":"Gem2Go","variants":[{"agent":"Android","install":"market://details?id=WA66F5VEHP.com.ris.Gem2Go","start":null,"landscape":null},{"agent":"iPhone","install":"https://apps.apple.com/at/app/id547223237","start":null,"landscape":null},{"agent":"iPad","install":"https://apps.apple.com/at/app/id547223237","start":null,"landscape":null},{"agent":"Windows Phone","install":"http://www.microsoft.com/de-at/store/apps/gem2go/9wzdncrdr4x5","start":null,"landscape":null}],"addClass":null,"color":"#ffffff","backgroundimage":"statV.0/web/images/loginimages/mobileAppDetector-bg.jpg","image":"https://www.regiobregenzerwald.at/system/statV.0/web/images/loginimages/mobileAppDetector-512.png","imagealt":"App Icon","header":"GEM2GO APP","note":"Nutzen Sie unsere Gemeinde-App!","prompt":"in GEM2GO APP öffnen","landscape":false,"install":null,"urlSchema":"gem2go","start":null,"otherwise":null,"cookietime":30,"hinweistextHidePopup":"Diese Meldung die nächsten 30 Tage nicht mehr anzeigen","closetext":"Installationsaufforderung der GEM2GO APP schließen","text":"In der GEM2GO APP öffnen","gnr":3094,"Id":"mobileapp-gem2go","deeplink":null,"arialabel":"GEM2GO Installationsaufforderung"}]};
128</script>
128
129
130    
131<meta name="author" content="Bregenzerwald" lang="de" />
132<meta name="description" content="Bregenzerwald" lang="de" />
133<meta name="google-site-verification" content="wkOR51duCdgoOZ7XgAphW4YK1liInC_hezFI0G3ogu4" lang="de" />
134<meta name="keywords" content="Bregenzerwald Gemeinde Region Regional Regionales Information System Gemeinde Gemeinden" lang="de" />
135<meta name="title" content="Bregenzerwald - Startseite" lang="de" />
136<meta name="robots" content="index,follow" lang="de" />
137<meta name="revisit-after" content="7 days" lang="de" />
138<meta name="language" content="de-AT" lang="de" />
139<meta property="fb:admins" content="100000414979333" lang="de" />
140<meta property="og:title" content="Bregenzerwald" lang="de" />
141<meta property="og:site_name" content="Bregenzerwald" lang="de" />
142<meta property="og:type" content="website" lang="de" />
143<meta property="og:url" content="https://www.regiobregenzerwald.at/" lang="de" />
144<style type="text/css">
145	.ctl00_ctl00_ctl00_cph_header_ctl02_0 { text-decoration:none; }
146
147</style></head>
148<body >
149    
150    
150<script src="/system/statV.1789655742/Javascript/rismap3/rismap3leaflet.js" type="text/javascript"></script>
vendor: 2 bytes, line 150
150
151<script src="/system/statV.1789655742/web/lightboxJQuery/js/jquery.lightbox-0.5.js" type="text/javascript"></script>
vendor: 2 bytes, line 151
151
152<script src="/system/statV.1789655742/Javascript/socialshare/jquery.socialshareprivacy.js" type="text/javascript"></script>
vendor: 2 bytes, line 152
152
153<script type="text/javascript">
154                var rismap3_global_settings = { 
155                    "clickMessage" : "Klicken Sie hier um die Karte zu laden", 
156                    "showbasemap" : true,
157                    "sgvgisenableorthophoto" : false,
158                    "sgvgisenableaddress" : false,
159                    "sgvgisenablestreet" : false,
160                    "zoom": 16,
161                    "clicktostart": false,
162                    "defaultlayer": "grau",
163                    
164                    "protocol": "https://",
165                    "tilepath": "https://mffiles.gem2go.page/custom/regiobregenzerwald/tiles/",
166                    "streetslbl": "Straßen",
167                    "addresslbl": "Adressen",
168                    "orthofotolbl" : "Orthofoto"
169                }
170            </script>
170
171
172
173    <div id="main" class="show-all defaultcmsliste">
174        <div id="page_top"></div>
175        
176            <div id="accesskeys" class="">
177                
178    <ul class="ris_skiplinkList">
179        <li><a href="#content" accesskey="1" class="ris_skiplink">Hauptinhalt: Kurztaste 1</a></li>
180<li><a href="#ctl00_ctl00_ctl00_cph_header_ctl02" accesskey="2" class="ris_skiplink">Hauptnavigation: Kurztaste 2</a></li>
181<li><a href="#search_225049642" accesskey="4" onclick="event.preventDefault(); document.querySelector(&#39;#search_225049642&#39;)?.focus()" class="ris_skiplink">Suche: Kurztaste 4</a></li>
182
183    </ul>
184
185            </div>
186
187            <div class="header_wrapper" aria-label="Mobilit&#228;ts-Banner" role="banner"><div id="header">
188                
189    <div class="box2042 section section__top"><div class="box2042 wrapper"><div class="box2042 wrapper__search"><div class="home"><a href="/default.aspx" aria-label="Link Startseite"><em class="fi flaticon-home"></em></a>
190
191
192</div><div class="search--einzeilig"><div class="sucheeinzeilig">
193	<form action="/system/web/suche.aspx" id="Form_suche_225049642" method="get">
194		<p><span id="ctl00_ctl00_ctl00_cph_header_ctl01"><input class="text" type="text" id="search_225049642" name="search" title="Suchbegriff" placeholder="Suchbegriff" /></span><input type="submit" class="button" id="searchbtn_225049642" aria-label="Suche" value=">>" /><input type="hidden" name="menuonr" value="225047683" /><input type="hidden" name="detailonr" value="0" /><input type="hidden" name="sprache" value="1" /><input type="hidden" name="mqs" value="0" /><input type="hidden" name="cmd" /></p>
195	</form>
196</div></div></div><div class="navigator navigator--text"><ul><li><a class="extlink" href="https://www.regiobregenzerwald.at/Karte">Karte</a></li><li class="navigator-tel"><a class="extlink" href="https://www.regiobregenzerwald.at/Kontakt">Kontakt</a></li><li>+<a href="tel:+43551226000" title="Regionalplanungsgemeinschaft Bregenzerwald anrufen">43 5512 26000</a></li><li class="navigator-tel"><a href="mailto:[email protected]">[email protected]</a></li></ul></div></div></div><div class="box2042 section section__header"><div class="box2042 section section__name"><div class="mandant__logo"><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/"><img src="/system/web/getImage.ashx?fileid=1348534&amp;mode=T&amp;width=640&amp;height=480&amp;cts=1787063325" class="fr-fil fr-dib width49" alt="Ein Logo mit grünem und grauem Text"></a></p><p><br></p></div><div class="box2042 wrapper"></div></div><div class="box2042 section section__topmenu"><div class="box2042 wrapper"><div class="topmenu">
197		<div class="megamenu" id="ctl00_ctl00_ctl00_cph_header_ctl02"><ul>
198		<li class="mm-menuitem MegaMenu-WithChildren width20  normal"><a href="/Aktuelles">
199			Aktuelles</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Aktuelles/Neuigkeiten">
200				Neuigkeiten</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Aktuelles/Veranstaltungen">
201					Veranstaltungen</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Aktuelles/Veranstaltungen/Veranstaltung_erfassen">
202						Veranstaltung erfassen</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Aktuelles/Veranstaltungen/Veranstaltung_aendern">
203							Veranstaltung ändern</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Karte">
204								Karte</a></h3></li></ul></div></div></div></li>
205								<li class="mm-menuitem MegaMenu-WithChildren width20  wide"><a href="/Themen">
206									Themen</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Leben">
207										Leben</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Baurechtsverwaltung">
208											Baurechtsverwaltung</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://sozialkompass.vorarlberg.at/" target="_blank" rel="noopener" class="extlink extlink" title="Sozialkompass (Öffnet in neuem Fenster - Externer Link)">
209												Sozialkompass</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Kinder_und_Jugend">
210													Kinder und Jugend</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Gesundheit">
211														Gesundheit</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Kultur">
212															Kultur</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Pflege">
213																Pflege</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Klimaschutz">
214																	Klimaschutz</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Bewegen">
215																		Bewegen</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Achtalweg">
216																			Achtalweg</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Fahrradfahren">
217																				Fahrradfahren</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/OePNV">
218																					ÖPNV</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald" target="_blank" rel="noopener" class="extlink extlink" title="Landbus Bregenzerwald (Öffnet in neuem Fenster - Externer Link)">
219																						Landbus Bregenzerwald</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/fahrradbus-2026" target="_blank" rel="noopener" class="extlink extlink" title="Fahrradbus (Öffnet in neuem Fenster - Externer Link)">
220																							Fahrradbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.regiobregenzerwald.at/Festspielbus_Bregenzerwald_2026" target="_blank" rel="noopener" class="extlink extlink" title="Festspielbus (Öffnet in neuem Fenster - Externer Link)">
221																								Festspielbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/wanderbuslinie-497-bequem-ab-damuels-unterwegs" target="_blank" rel="noopener" class="extlink extlink" title="Wanderbus (Öffnet in neuem Fenster - Externer Link)">
222																									Wanderbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf ext-mp1"><a href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/nachtbuslinien-8n1-und-8n2" target="_blank" rel="noopener" class="extlink extlink" title="Nachtbus (Öffnet in neuem Fenster - Externer Link)">
223																										Nachtbus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Carsharing">
224																											Carsharing</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Arbeiten">
225																												Arbeiten</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Bregenzerwald_Gutschein">
226																													Bregenzerwald Gutschein</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/ich_kauf_im_Wald">
227																														ich kauf im Wald</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Tourismus">
228																															Tourismus</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Handwerk">
229																																Handwerk</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Landwirtschaft_1">
230																																	Landwirtschaft</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/KaeseStrasse">
231																																		KäseStrasse</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Bildung">
232																																			Bildung</a></li></ul></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-WithChildren"><h3><a href="/Bewahren">
233																																				Bewahren</a></h3><ul><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/bregenzerwaldarchiv">
234																																					Bregenzerwald Archiv</a><ul class="forceHide"><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/A_Gemeindeverwaltung" title="Bestände der Gemeindeverwaltungen">
235																																						..... A Gemeindeverwaltung
235</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/B_Institutionen" title="Bestände von Institutionen">
236																																							..... B Institutionen</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/C_Nachlaesse" title="Nachlässe des Bregenzerwald Archivs">
237																																								..... C Nachlässe</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/D_Pertinenzbestaende" title="Pertinenzbestände des Archivs">
238																																									..... D Pertinenzbestände</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/E_Pfarrarchive" title="Pfarrarchive des Bregenzerwald Archivs">
239																																										..... E Pfarrarchive</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/F_Vereine" title="Vereinsunterlagen des Bregenzerwald Archivs">
240																																											..... F Vereine</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/G_Firmen" title="Firmenunterlagen des Bregenzerwald Archivs">
241																																												..... G Firmen</a></li></ul></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Alte_Bausubstanz">
242																																													Alte Bausubstanz</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Barockbaumeister">
243																																														Barockbaumeister</a></li><li class="mm-subXmenuitem MegaMenu-Leaf"><a href="/Natura_2000">
244																																															Natura 2000</a></li></ul></li></ul></div></div></div></li>
245																																															<li class="mm-menuitem MegaMenu-WithChildren width20  normal"><a href="/Regio">
246																																																Regio</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Regio/Informationen">
247																																																	Informationen</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Kontakt">
248																																																		Kontakt</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Vorstand">
249																																																			Vorstand</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Team_Regio">
250																																																				Team Regio</a></h3></li></ul></div></div><div class="mm-row mm-rowX"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Team_Baurechtsverwaltung">
251																																																					Team Baurechtsverwaltung</a></h3></li></ul></div></div></div></li>
252																																																					<li class="mm-menuitem MegaMenu-WithChildren width20"><a href="/Gemeinden">
253																																																						Gemeinden</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Gemeinden_1">
254																																																							Gemeinden</a></h3></li></ul></div></div></div></li>
255																																																							<li class="mm-menuitem MegaMenu-WithChildren width20  normal"><a href="/Partner_1">
256																																																								Partner</a><div class="mm-block"><div class="mm-row mm-row1"><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Regio_V">
257																																																									Regio V</a></h3></li></ul></div><div class="mm-col mm-size25"><ul><li class="mm-submenuitem MegaMenu-Leaf"><h3><a href="/Europaeische_Projekte">
258																																																										Europäische Projekte</a></h3></li></ul></div></div></div></li>
259																																																									</ul></div>
260
261																																																								</div></div></div></div>
262
263            </div></div><div class="header2_wrapper" aria-label="Web-Banner" role="banner"><div id="header2">
264                
265    <div class="banner"><div id="slickSlider225104233" class="box2061">
266  <div class="slick-slide-content" data-onr="225466586"><img alt="Fahrrad-Bus_Bregenzerwald_c_Ian_Ehm_-_buero_balanka_Bregenzerwald_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1350925&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1788192864" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1440px;max-height:450px;" /></div>
267  <div class="slick-slide-content" data-onr="225466587">
267<img alt="Radweg_Bregenzerwald_c_Benjamin_Schlachter_-_Bregenzerwald_Tourismus_1_" data-lazy="/system/web/GetImage.ashx?fileid=1350926&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1788192868" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div>
268  <div class="slick-slide-content" data-onr="225466585"><img alt="Bus_am_Bödele_c_Lucas_Tiefenthaler_-_Bregenzerwald_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1350924&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1788192857" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1619px;max-height:450px;" /></div>
269  <div class="slick-slide-content" data-onr="225466592"><img alt="Auf_dem_Weg_zur_Winterstaude_c_Michael_Meusburger_-_witus_eGen" data-lazy="/system/web/GetImage.ashx?fileid=1345559&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1784642417" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div>
270  <div class="slick-slide-content" data-onr="225466593"><img alt="Alpe_Oberdamüls_c_Huber_Images_-_Damüls-Faschina_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1345561&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1784642419" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1618px;max-height:450px;" /></div>
271  <div class="slick-slide-content" data-onr="225460946"><img alt="Bodenvorsä_in_Au_mit_Blick_auf_Zitterklapfen_c_Emanuel_Sutterlüty_-_Au-Schoppernau_Tourismus" data-lazy="/system/web/GetImage.ashx?fileid=1345500&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1784632432" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1620px;max-height:450px;" /></div>
272  <div class="slick-slide-content" data-onr="225460938"><img alt="Mädchen_in_der_Juppe_-_Bregenzerwälder_Tracht_c_Ian_Ehm_-_friendship.is" data-lazy="/system/web/GetImage.ashx?fileid=1345492&amp;mode=T&amp;width=1920&amp;height=450&amp;cropping=CENTER&amp;cts=1784632409" src="/system/statV.1789655742/web/images/dummy.gif" class="slick-slide-img" style="max-width:1440px;max-height:450px;" /></div>
273</div>
274<script type="text/javascript">$("#slickSlider225104233").slick({
275	slidesToShow: 1,
276	slidesToScroll: 1,
277	autoplay: true,
278	autoplaySpeed: 4000,
279	speed: 1000,
280	dots: true,
281        rows: 0,
282        fade: false,
283});</script>
283</div>
284
285            </div></div><div class="columns_wrapper" role="main"><div id="columns">
286                <div class="cols-wrapper">
287                    <div id="ctl00_ctl00_ctl00_col_ab_container" class="float-wrapper">
288																																																									
289                        <div id="col-b" class="sidecol-b">
290																																																										
291                            
292    
293
294                        
295																																																									</div><div id="col-a">
296																																																										
297                            <div class="main-content">
298                                
299
300    
301    <div id="main-content-header"><div class="box2042 section section__breadcrumb"><div class="box2042 wrapper"><div class="breadcrumb"><ul class="item_liste">
302																																																											<li><a  href="/system/web/default.aspx?menuonr=225047665" class="breadcrumb-current">Startseite</a></li>
303																																																										</ul></div></div></div></div>
304
305    <div id="content"></div>
306    <form method="post" action="/system/web/default.aspx?sprache=1" id="aspnetForm">
307																																																										<div class="aspNetHidden">
308																																																										<input type="hidden" name="ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState" id="ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState" value="enennneennnnnnnennnnnnnnnennnnnnneennnnnnnnnnennnnnenennennnn" />
309																																																										<input type="hidden" name="ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode" id="ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode" value="" />
310																																																										<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
311																																																										<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
312																																																										<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUINTY1NjQ1NjNkGAEFHl9fQ29udHJvbHNSZXF1aXJlUG9zdEJhY2tLZXlfXxYBBSJjdGwwMCRjdGwwMCRjdGwwMCRjcGhfaGVhZGVyJGN0bDAy5Wt2XrHguC/pO/Ilzrd18uXGpEs=" />
313																																																										</div>
314																																																										
315<script type="text/javascript">
316//<![CDATA[
317var theForm = document.forms['aspnetForm'];
318																																																										if (!theForm) {
319    theForm = document.aspnetForm;
320}
321																																																										function __doPostBack(eventTarget, eventArgument) {
322    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
323        theForm.__EVENTTARGET.value = eventTarget;
324        theForm.__EVENTARGUMENT.value = eventArgument;
325        theForm.submit();
326    }
327}
328																																																										//]]>
329</script>
329
330
331																																																										
332<script src="/system/WebResource.axd?d=4NbBhsyxI7mn5DiJieNvpkRb5PMUHyWFFYQ2RFfWIHy9e_8yCMnSJbJpxCkWluTC5seyOHuKvXhDDa32ZNrkrXXxB281&amp;t=639245057389592256" type="text/javascript"></script>
332
333
334																																																										
335<script src="/system/WebResource.axd?d=M-Bz-Kz21qb4W7sjbD_RDJcAZpORT9hz630ncoDj-NTxQIw5qMQxkUI0oU2f7zxwJz6FzLLyuQeLgXUYoNh3iY8ZNCk1&amp;t=639245057389592256" type="text/javascript"></script>
vendor: 2 bytes, line 335
335
336<script type="text/javascript">
337//<![CDATA[
338var ctl00_ctl00_ctl00_cph_header_ctl02_Data = null;//]]>
339</script>
339
340
341        
342
343
344
345
346
347    
348
349
350
351<div class="box2042 section section__news"><div class="box2042 wrapper"><div class="titel"><h1>Aktuelle Informationen</h1><span class="titel_seperator"></span></div><div class="news"><div class='newslist'><div class='newsrow'><div class='width99 odd  kat_225391296 float_left'><p class="float_right"> 27.08.2026</p><a  href="/Sperre_des_Achtalwegs_beim_Kraftwerk_Langenegg" title="Sperre des Achtalwegs beim Kraftwerk Langenegg"><img alt="Bauarbeiten Achtalweg" src="/system/web/GetImage.ashx?fileid=1350575&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1787856732" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Sperre_des_Achtalwegs_beim_Kraftwerk_Langenegg">Sperre des Achtalwegs beim Kraftwerk Langenegg</a></span></h2><p>Aufgrund von Leitungsbauarbeiten oberhalb des Kraftwerks Langenegg muss der Achtalweg in diesem Bereich...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even  kat_225391296 float_left'><p class="float_right"> 22.09.2026</p><a  href="/Care_Management_Bregenzerwald-Kleinwalsertal" title="Care Management Bregenzerwald-Kleinwalsertal"><img alt="Eine rote Karte mit weißem Text" src="/system/web/GetImage.ashx?fileid=1354734&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1790068857" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Care_Management_Bregenzerwald-Kleinwalsertal">Care Management Bregenzerwald-Kleinwalsertal</a></span></h2><p>Mit der neuen Care Management-Struktur wird die Betreuung und Pflege älterer Menschen in der Region gemeinsam...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 odd  kat_225391296 float_left'><p class="float_right"> 29.09.2026</p><a  href="/Strassensperre_L_21_Sulzberg_-_Fahl" title="Straßensperre L 21 Sulzberg - Fahl"><img alt="ein Kegel auf einer Oberfläche" src="/system/web/GetImage.ashx?fileid=1356382&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1790692681" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Strassensperre_L_21_Sulzberg_-_Fahl">Straßensperre L 21 Sulzberg - Fahl</a></span></h2><p>Aufgrund von Bauarbeiten kann die Linie 823 von Montag, 5. Oktober 2026, 8:30 Uhr, bis Mittwoch, 7. Oktober...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even  kat_225391296 float_left'><p class="float_right"> 21.09.2026</p><a  href="/Beratungsstelle_fuer_NS-Objekte_2" title="Beratungsstelle für NS-Objekte"><img alt="Eine Person, die alte Fotos hält" src="/system/web/GetImage.ashx?fileid=1354540&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1790000946" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Beratungsstelle_fuer_NS-Objekte_2">Beratungsstelle für NS-Objekte</a></span></h2><p>Im Rahmen der Ausstellung „Baustelle Erinnerung | ,Hitler entsorgen‘“ bietet das vorarlberg museum in...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 odd  kat_225391296 float_left'><p class="float_right"> 21.07.2026</p><a  href="/Nachtbus_Bregenzerwald" title="Nachtbus Bregenzerwald"><img alt="Eine Person und eine Person, die mit einem großen Stofftier für ein Foto posieren" src="/system/web/GetImage.ashx?fileid=1345668&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1784711639" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Nachtbus_Bregenzerwald">Nachtbus Bregenzerwald</a></span></h2><p>Die Nachtbusse 8N1 und 8N2 fahren in der Nacht von Samstag auf Sonntag, außer an Feiertagen.  Die Linie...</p></div></div><div class='clear'></div><div class='newsrow'><div class='width99 even  kat_225391296 float_left'><p class="float_right"> 21.04.2026</p><a  href="/Fahrradbus_2026" title="Fahrradbus 2026"><img alt="Fahrradbus am Bahnhof Egg" src="/system/web/GetImage.ashx?fileid=1329784&amp;mode=T&amp;width=640&amp;height=360&amp;cropping=CENTER&amp;cts=1776771372" class="float_left" style="max-width:640px;max-height:360px;" /></a><h2><span class='news_titel_link'><a  href="/Fahrradbus_2026">Fahrradbus 2026</a></span></h2><p>Die Busse 8R1 und 8R2 fahren vom 14. Mai bis 04. Oktober 2026 jeweils Donnerstag bis Sonntag. Alle Fahrzeiten...</p></div></div><div class='clear'></div></div><p class="cls_weiterenews"><a  href="/Aktuelles/Neuigkeiten">Weitere News...</a></p></div></div></div><div class="box2042 section section__karte"><div class="box2042 wrapper"><div class="titel"><h1>Bregenzerwaldkarte</h1></div><div class="karte"><!-- ============================================================
352     Karte Bregenzerwald – Kulturkarte + Veranstaltungen
353     STARTSEITEN-VARIANTE (Basis: Version 41)
354
355     Fehlerbehebung: Das schwebende Menü wuchs beim Aufklappen
356     unbegrenzt nach unten (kein internes Scrollen), weil
357     #bwk-kartenbox keine eigene Höhe hatte – "max-height:
358     calc(100% - ...)" beim Menü konnte sich dadurch auf nichts
359     Festes beziehen. #bwk-kartenbox hat jetzt dieselbe feste Höhe
360     wie #bwk-karte (am Aussehen ändert sich dadurch nichts), das
361     Menü scrollt jetzt korrekt innerhalb der Kartenbox.
362
363     Unterschiede zur normalen Version:
364       • Kein Filter-Feld über der Karte, keine Werkzeugzeile. Das
365         Menü (Gemeinden + Kategorien) liegt IMMER als schwebendes
366         Feld direkt über der Karte, auf-/zuklappbar über das
367         Ebenen-Icon oben links – genau wie sonst nur im Vollbild.
368       • "Auswahl drucken" (CSV-Export) komplett entfernt.
369       • Alle Kategorien und alle Gemeinden starten aktiv (nicht
370         abgewählt wie in der normalen Version).
371
372     Sonst identisch zu Version 40: Gemeinde-Filter mit echten
373     Gemeindegrenzen, Zeitraum-Dialog bei Veranstaltungen, Farben,
374     Ebenen-Reihenfolge nach uMap-Rang usw. – siehe dortiger
375     Änderungsverlauf.
376
377
378     Neu gegenüber Version 39:
379       • Zeitraum-Dialog hat jetzt oben rechts ein X zum Schließen
380         ohne zu übernehmen (wie Escape/Klick daneben).
381       • "Außerhalb vom Bregenzerwald" hat keine eigene Grenze zum
382         Hinzoomen – die Karte zoomt bei dieser Auswahl jetzt grob
383         auf ganz Vorarlberg statt gar nichts zu tun.
384       • Linien (Radwege usw.) stehen jetzt auch im CSV-Export, mit
385         dem ersten Stützpunkt der Linie als Koordinate. Das war
386         vermutlich auch der Grund, warum ganze Kategorien im Export
387         zu fehlen schienen: eine Ebene wie "Radweg" besteht komplett
388         aus Linien und hatte darum bisher schlicht null Zeilen.
389
390
391     Neu gegenüber Version 38 (drei Fehlerbehebungen):
392       • Datumsfilter wirkungslos: die Von/Bis-Felder waren
393         deaktiviert, solange "Alle Termine anzeigen" angehakt war
394         (Startzustand) – ein deaktiviertes Feld lässt sich gar
395         nicht anklicken. Felder sind jetzt immer bedienbar; wird
396         ein Datum gewählt, hakt "Alle Termine anzeigen" automatisch
397         ab. Knopf heißt jetzt "Filter anwenden".
398       • Dialog blieb im echten Vollbildmodus unsichtbar: er hing an
399         document.body, das der Browser im Vollbild aber gar nicht
400         mehr rendert (nur der Vollbild-Container selbst). Der
401         Dialog hängt jetzt an #bwk-kartenbox.
402       • CSV-Export zeigte nur Veranstaltungen: layer.eachLayer()
403         geht bei den Kultur-Ebenen nicht in die verschachtelte
404         GeoJSON-Gruppe hinein. Neue Hilfsfunktion steigt jetzt in
405         verschachtelte Gruppen hinab. Der Export hat außerdem eine
406         neue Spalte "Kategorie" und sortiert zuerst danach, dann
407         erst alphabetisch nach Name.
408
409
410     Neu gegenüber Version 37:
411       • Gemeinden starten wieder alle abgewählt (wie die
412         Kategorien).
413       • Neuer Zeitraum-Dialog für Veranstaltungen: geht auf,
414         sobald "Veranstaltungen" angehakt wird. Von/Bis wählen
415         oder "Alle Termine anzeigen" ankreuzen – nur Termine im
416         gewählten Zeitraum erscheinen dann auf der Karte
417         (Abschnitt "Termin-Zeitraum-Dialog").
418       • Neuer Knopf "Auswahl drucken" unter dem Filter, über der
419         Karte: lädt eine CSV-Datei mit allen gerade sichtbaren
420         Einträgen herunter (Name, Beschreibung, Koordinaten),
421         alphabetisch sortiert – berücksichtigt automatisch
422         Kategorie-, Gemeinde- und Zeitraum-Filter, weil er direkt
423         von den tatsächlich gezeichneten Markern abliest.
424       • Ändert sich die Gemeinde-Auswahl, bewegt sich die Karte
425         jetzt automatisch dorthin (nutzt die schon geladenen
426         echten Gemeindegrenzen).
427
428     Neu gegenüber Version 36:
429       • Im Vollbild verdeckte das Gemeinden/Kategorien-Menü das
430         Icon zum Ein-/Ausblenden der Ebenen (beide saßen in der
431         gleichen Ecke). Das Menü setzt im Vollbild jetzt weiter
432         unten an (top 14px -> 64px, max-height entsprechend
433         angepasst), damit das Icon frei bleibt.
434
435
436     Neu gegenüber Version 35:
437       • Die neue Rang-Sortierung ist jetzt gegen Fehler abgesichert:
438         schlägt sie fehl, fällt sie auf die Reihenfolge aus der Datei
439         zurück, statt (wie es einmal beobachtet wurde) die komplette
440         Kultur-Ansicht zu leeren.
441
442
443     Neu gegenüber Version 34:
444       • Eine Ebene mit eigens gesetzter Farbe behält diese jetzt,
445         auch wenn ihre Gruppe eine Farbe hat – bisher überschrieb
446         die Gruppenfarbe das immer. Normalfall (keine eigene Farbe
447         gesetzt) bleibt: Ebene erbt die Farbe der Gruppe.
448       • Reihenfolge von Gruppen und Ebenen im Filter richtet sich
449         jetzt nach uMaps eigenem Feld "rank" (die Reihenfolge, in
450         der sie in uMap selbst angeordnet sind), nicht mehr nach
451         der Reihenfolge im Datei-Export.
452
453     Neu gegenüber Version 33:
454       • Der Gemeinde-Filter wirkt jetzt auch auf Linien (Routen wie
455         Radwege). Eine Linie kann mehrere Gemeinden berühren – sie
456         bleibt sichtbar, sobald mindestens eine davon angehakt ist.
457         Flächen sind davon weiter nicht betroffen (kommen in den
458         Kulturdaten bisher nicht vor).
459
460     Neu gegenüber Version 32:
461       • 25. Eintrag im Gemeinde-Filter: "Außerhalb vom
462         Bregenzerwald". Jeder Punkt bekommt jetzt IMMER eine der
463         25 Gemeinden zugewiesen – auch wenn er in keiner der 24
464         echten Grenzen liegt und auch nicht per Text erkannt wird.
465         Damit gibt es keinen Sonderfall "immer sichtbar" mehr, der
466         den Filter wirkungslos gemacht hat.
467       • Veranstaltungen erschienen unabhängig vom Gemeinde-Filter
468         immer: Ursache war ein alter Zwischenspeicher-Eintrag im
469         Browser (aus einer Version ohne Gemeinde-Feld je Punkt).
470         Der Zwischenspeicher-Schlüssel für Veranstaltungen wurde
471         darum angehoben (bwk-termine-v3) – erzwingt beim nächsten
472         Laden einmalig einen frischen Abruf.
473       • Gemeinden starten jetzt wieder alle aktiv (wie zuvor in
474         Version 31), inklusive der neuen 25. Gemeinde.
475       • Die Gemeindegrenzen kommen jetzt aus EINER einzigen
476         Overpass-Abfrage (statt 24 einzelnen Nominatim-Anfragen im
477         Sekundentakt) – der Filter ist dadurch in der Regel nach
478         wenigen statt nach ~30 Sekunden vollständig genau.
479
480     Neu gegenüber Version 31:
481       • Gemeinde-Zuordnung läuft jetzt in erster Linie über die
482         echten Gemeindegrenzen (Polygone von OpenStreetMap),
483         einmalig geladen und im Browser zwischengespeichert, nicht
484         mehr nur über Texterkennung in Adresse oder Name. Die reine
485         Texterkennung bleibt als Rückfallebene, solange die Grenzen
486         noch laden.
487
488     Neu gegenüber Version 30:
489       • Gemeinde-Filter (24 Regio-Gemeinden) oberhalb des
490         Kategorien-Filters. Beide Filter gelten gemeinsam (UND):
491         ein Punkt erscheint nur, wenn seine Kategorie UND seine
492         Gemeinde angehakt sind.
493       • Jeder Punkt bekommt dafür eine Gemeinde zugewiesen –
494         bei Veranstaltungen aus der "Datenquelle" der Karte, bei
495         Kulturpunkten aus Adresse/Name (gleiche Texterkennung wie
496         schon bisher für die Ortssuche). Nicht zuordenbare Punkte
497         bleiben immer sichtbar, statt sie zu verstecken.
498
499     Neu gegenüber Version 29:
500       • Die Seite "Aktuelles > Veranstaltungen" wurde umgebaut
501         (neue Adresse /Aktuelles/Veranstaltungen, Kartenansicht
502         statt Tabelle, Blättern per Formular statt über die URL).
503         Abschnitt 10 (Listenseiten) und die Gruppierung in
504         aktualisiere() wurden entsprechend neu geschrieben.
505       • Koordinaten stehen jetzt oft schon direkt in der Liste
506         (data-lat/data-lon); Nominatim/Detailseite werden nur noch
507         als Rückfallebene gebraucht, wenn diese fehlen.
508       • Nichts wird mehr fest verdrahtet (Formularfelder, das
509         Blätter-Ziel, die Feldnamen): der Code liest das Formular
510         und die Paginierung jedes Mal aus der gerade geladenen
511         Seite, damit spätere Änderungen an der Liste nicht gleich
512         wieder alles zerlegen.
513
514     Farben zentral ändern: der Block --bwk-… ganz oben im
515     Stylesheet. --bwk-akzent ist die Hausfarbe,
516     --bwk-spalte die Breite der Filterspalten.
517
518     Datei aktualisieren:
519       1. uMap -> Bearbeiten -> Erweiterte Aktionen ->
520          Daten herunterladen -> "Alle Daten"
521       2. Datei in der Medienverwaltung hochladen bzw. die
522          bestehende ersetzen
523          (wird .umap/.geojson abgelehnt: in .txt umbenennen)
524       3. Bleibt die fileid gleich, ist am Code nichts zu ändern.
525          Sonst unten KULTUR_FILEID anpassen.
526     ============================================================ -->
527
528<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/leaflet.css" crossorigin="" />
529<script src="https://unpkg.com/[email protected]/dist/leaflet.js" crossorigin=""></script>
529
530
531<style>
532/* ============================================================
533   Farben und Grundwerte
534   Auf allen drei Wurzeln gesetzt, weil die Karte im Vollbild
535   aus #bwk-wrap heraus an den Seitenkörper gehängt wird.
536   ============================================================ */
537#bwk-wrap, #bwk-kartenbox, #bwk-menu{
538  --bwk-tinte:#23241f;
539  --bwk-grau:#6f6a62;
540  --bwk-linie:#e4dfd5;
541  --bwk-linie-fein:#efebe3;
542  --bwk-flaeche:#faf8f4;
543  --bwk-akzent:#2f6b4f;
544  --bwk-akzent-tief:#255840;
545  --bwk-akzent-hell:rgba(47,107,79,.10);
546  --bwk-schatten:0 1px 3px rgba(35,36,31,.06);
547  --bwk-schatten-hoch:0 12px 34px rgba(35,36,31,.20);
548  /* Spaltenbreite von Gruppen und Kästchen im Filter */
549  --bwk-spalte:230px;
550}
551
552#bwk-wrap{
553  margin:26px 0; font-family:inherit; color:var(--bwk-tinte);
554  line-height:1.5; box-sizing:border-box;
555}
556#bwk-wrap *{box-sizing:border-box;}
557
558/* ============================================================
559   Filter über der Karte
560   ============================================================ */
561#bwk-menu{
562  font-family:inherit; color:var(--bwk-tinte); line-height:1.5;
563  border:1px solid var(--bwk-linie); border-radius:16px;
564  background:linear-gradient(180deg, #ffffff 0%, var(--bwk-flaeche) 100%);
565  box-shadow:var(--bwk-schatten);
566  padding:16px 18px 18px; margin:0 0 16px; box-sizing:border-box;
567}
568#bwk-menu *{box-sizing:border-box;}
569
570#bwk-menu .bwk-kopfzeile{display:flex; align-items:center; gap:12px;
571  margin:0 0 4px; padding:0 0 13px; border-bottom:1px solid var(--bwk-linie-fein);}
572#bwk-menu .bwk-ueberschrift{margin:0; flex:1 1 auto;
573  font-size:19px; font-weight:700; line-height:1.25; letter-spacing:-.005em;
574  color:var(--bwk-akzent); text-transform:none;}
575
576#bwk-menu .bwk-alle{font:inherit; font-size:13px; color:var(--bwk-grau);
577  background:#fff; border:1px solid var(--bwk-linie); border-radius:10px;
578  padding:6px 12px; cursor:pointer; white-space:nowrap; text-decoration:none;
579  -webkit-appearance:none; appearance:none;
580  transition:color .15s ease-out, border-color .15s ease-out, box-shadow .15s ease-out;}
581#bwk-menu .bwk-alle:hover{color:var(--bwk-akzent); border-color:var(--bwk-akzent);
582  box-shadow:0 2px 8px rgba(35,36,31,.09);}
583#bwk-menu .bwk-alle:focus-visible{outline:2px solid var(--bwk-akzent); outline-offset:2px;}
584
585#bwk-menu .bwk-inhalt{display:flex; flex-wrap:wrap; gap:18px 26px;
586  align-items:flex-start; padding:15px 0 0;}
587
588/* feste Spaltenbreite: Gruppen und Kästchen stehen bündig */
589#bwk-menu .bwk-gruppe{display:flex; flex-direction:column; gap:9px;
590  width:var(--bwk-spalte); flex:0 0 var(--bwk-spalte); min-width:0; max-width:100%;}
591
592/* Überschrift einer Kategorie: bricht um statt zu kürzen */
593#bwk-menu .bwk-gruppen-kopf{display:flex; align-items:flex-start; gap:9px;
594  width:100%; padding:0 0 2px;}
595#bwk-menu .bwk-gruppen-kopf input[type="checkbox"]{margin-top:2px;}
596#bwk-menu .bwk-gruppen-kopf label{flex:1 1 auto; min-width:0;
597  font-size:12px; font-weight:700; letter-spacing:.09em; text-transform:uppercase;
598  color:var(--bwk-grau); cursor:pointer;
599  white-space:normal; overflow-wrap:break-word; word-break:break-word; hyphens:auto;}
600#bwk-menu .bwk-gruppen-kopf label:hover{color:var(--bwk-tinte);}
601
602/* Ebenen einer Kategorie stehen untereinander */
603#bwk-menu .bwk-gruppen-liste{display:flex; flex-direction:column;
604  align-items:stretch; gap:7px; width:100%;}
605
606/* ---------- Gemeinde-Filter (Chips) ---------- */
607#bwk-menu .bwk-gemeinden{margin:0 0 15px; padding:0 0 15px;
608  border-bottom:1px solid var(--bwk-linie-fein);}
609#bwk-menu .bwk-gemeinde-liste{display:flex; flex-wrap:wrap; gap:8px; padding:13px 0 0;}
610#bwk-menu .bwk-chip{position:relative; display:inline-flex; align-items:center; gap:6px;
611  padding:6px 12px; border-radius:999px; cursor:pointer; user-select:none;
612  background:#fff; border:1px solid var(--bwk-linie);
613  font-size:13px; font-weight:500; line-height:1.3; color:var(--bwk-tinte);
614  transition:border-color .15s ease-out, background-color .15s ease-out,
615             color .15s ease-out, box-shadow .15s ease-out, opacity .15s ease-out;}
616#bwk-menu .bwk-chip:hover{border-color:#cfc8bb; box-shadow:0 2px 8px rgba(35,36,31,.09);}
617#bwk-menu .bwk-chip:focus-within{outline:2px solid var(--bwk-akzent); outline-offset:2px;}
618#bwk-menu .bwk-chip.bwk-an{background:var(--bwk-akzent-hell);
619  border-color:var(--bwk-akzent); color:var(--bwk-akzent-tief);}
620#bwk-menu .bwk-chip.bwk-aus{opacity:.55; border-style:dashed;}
621#bwk-menu .bwk-chip-anzahl{font-size:11px; font-weight:700; color:var(--bwk-grau);
622  font-variant-numeric:tabular-nums; padding:0 5px; border-radius:6px;
623  background:rgba(35,36,31,.06);}
624#bwk-menu .bwk-chip.bwk-an .bwk-chip-anzahl{background:rgba(255,255,255,.65);
625  color:var(--bwk-akzent-tief);}
626#bwk-menu .bwk-chip-anzahl:empty{display:none;}
627
628/* ---------- Kästchen einer Ebene ---------- */
629#bwk-menu .bwk-zeile{position:relative; display:flex; align-items:center;
630  gap:9px; padding:6px 13px 6px 8px; margin:0; cursor:pointer;
631  width:100%; min-width:0;
632  background:#fff; border:1px solid var(--bwk-linie); border-radius:10px;
633  box-shadow:0 1px 2px rgba(35,36,31,.05); font-size:14px; line-height:1.3;
634  transition:border-color .15s ease-out, background-color .15s ease-out,
635             box-shadow .15s ease-out, opacity .15s ease-out;}
636#bwk-menu .bwk-zeile:hover{border-color:#cfc8bb; box-shadow:0 3px 10px rgba(35,36,31,.11);}
637#bwk-menu .bwk-zeile.bwk-an{background:#fff; border-color:var(--bwk-linie);}
638#bwk-menu .bwk-zeile.bwk-aus{background:transparent; border-style:dashed;
639  border-color:var(--bwk-linie); box-shadow:none; opacity:.6;}
640#bwk-menu .bwk-zeile.bwk-aus .bwk-swatch{filter:grayscale(1);}
641#bwk-menu .bwk-zeile.bwk-aus .bwk-name{color:var(--bwk-grau);}
642#bwk-menu .bwk-zeile:focus-within{outline:2px solid var(--bwk-akzent); outline-offset:2px;}
643
644/* Name einer Ebene: bricht um statt zu kürzen */
645#bwk-menu .bwk-name{flex:1 1 auto; min-width:0; font-weight:500;
646  white-space:normal; overflow-wrap:break-word; word-break:break-word; hyphens:auto;}
647#bwk-menu .bwk-anzahl{flex:0 0 auto; margin-left:auto; align-self:center;
648  font-size:11.5px; font-weight:700;
649  color:var(--bwk-grau); font-variant-numeric:tabular-nums;
650  padding:1px 7px; border-radius:6px; background:rgba(35,36,31,.06);}
651#bwk-menu .bwk-anzahl:empty{display:none;}
652
653/* Ankreuzfeld der Kästchen: unsichtbar, aber bedienbar */
654#bwk-menu .bwk-haken{position:absolute !important; opacity:0 !important;
655  width:1px !important; height:1px !important; margin:0 !important;
656  padding:0 !important; pointer-events:none;}
657
658#bwk-menu input[type="checkbox"]{width:17px; height:17px;
659  accent-color:var(--bwk-akzent); cursor:pointer; margin:0; flex:0 0 auto;}
660#bwk-menu input[type="checkbox"]:focus-visible{outline:2px solid var(--bwk-akzent);
661  outline-offset:2px;}
662
663/* ---------- Auf- und Zuklappen ---------- */
664#bwk-menu .bwk-auf{margin-left:auto; display:inline-flex; align-items:center;
665  justify-content:center; width:26px; height:26px; padding:0; flex:0 0 auto;
666  margin-top:-3px;
667  border:0; background:none; color:var(--bwk-grau); cursor:pointer; border-radius:8px;
668  -webkit-appearance:none; appearance:none;}
669#bwk-menu .bwk-auf:hover{background:rgba(35,36,31,.06); color:var(--bwk-tinte);}
670#bwk-menu .bwk-auf svg{display:block; transition:transform .15s ease-out;}
671#bwk-menu .bwk-gruppe.bwk-zugeklappt .bwk-gruppen-liste{display:none;}
672#bwk-menu .bwk-gruppe.bwk-zugeklappt .bwk-auf svg{transform:rotate(-90deg);}
673#bwk-menu .bwk-menu-zu{display:none; align-items:center; justify-content:center;
674  width:30px; height:30px; padding:0; flex:0 0 auto; cursor:pointer;
675  border:1px solid var(--bwk-linie); border-radius:10px; background:#fff;
676  color:var(--bwk-grau); font-size:17px; line-height:1;
677  -webkit-appearance:none; appearance:none;}
678#bwk-menu .bwk-menu-zu:hover{color:var(--bwk-tinte); border-color:var(--bwk-grau);}
679
680/* ---------- Farbtupfer im Filter ---------- */
681.bwk-swatch{display:inline-flex !important; align-items:center; flex:0 0 auto;
682  align-self:center;}
683.bwk-punkt{display:inline-flex !important; align-items:center; justify-content:center;
684  width:22px !important; height:22px !important; flex:0 0 auto;
685  margin:0 !important; padding:0 !important; border:0 !important;
686  background:none !important; overflow:visible !important;}
687.bwk-punkt svg{display:block !important; width:22px !important; height:22px !important;
688  margin:0 !important; padding:0 !important;
689  max-width:none !important; max-height:none !important;
690  min-width:0 !important; min-height:0 !important;}
691
692/* ============================================================
693   Marker im uMap-Stil
694   Tropfen, Piktogramm und Beschriftung gehören zum Marker.
695   Die !important-Regeln halten die CMS-Stile von den Maßen fern.
696   ============================================================ */
697.leaflet-marker-icon.bwk-pin-huelle{
698  background:none !important; border:0 !important;
699  margin:0 !important; padding:0 !important;
700  width:32px !important; height:42px !important; overflow:visible !important;}
701.bwk-pin{position:relative !important; display:block !important;
702  width:32px !important; height:42px !important;
703  margin:0 !important; padding:0 !important; overflow:visible !important;}
704.bwk-pin svg.bwk-pin-form{display:block !important;
705  width:32px !important; height:42px !important;
706  margin:0 !important; padding:0 !important;
707  max-width:none !important; max-height:none !important;
708  min-width:0 !important; min-height:0 !important;
709  overflow:visible !important;
710  transform-origin:50% 100%;
711  transition:transform .12s ease-out;
712  filter:drop-shadow(0 1px 2px rgba(35,36,31,.35));}
713.bwk-pin:hover svg.bwk-pin-form{transform:scale(1.12);}
714
715/* Beschriftung: hängt fest unter der Nadelspitze */
716.bwk-pin-name{position:absolute !important; left:50% !important; top:100% !important;
717  transform:translateX(-50%) !important;
718  padding:3px 8px !important; border-radius:4px !important;
719  background:#fff !important; border:1px solid #d9d5cd !important;
720  color:#23241f !important; font-family:inherit !important;
721  font-size:12px !important; font-weight:600 !important; line-height:1.35 !important;
722  white-space:nowrap !important; letter-spacing:0 !important;
723  box-shadow:0 2px 7px rgba(35,36,31,.20) !important;
724  opacity:0; visibility:hidden; pointer-events:none !important;
725  transition:opacity .12s ease-out; z-index:2;}
726.bwk-pin:hover .bwk-pin-name, .bwk-pin-name.bwk-immer{opacity:1; visibility:visible;}
727  
728  /* Beschriftung der Linien beim Überfahren */
729.leaflet-tooltip.bwk-linien-name{
730  margin:0; padding:3px 9px; border:1px solid #d9d5cd; border-radius:5px;
731  background:#fff; color:#23241f; font-family:inherit;
732  font-size:12px; font-weight:600; line-height:1.35;
733  box-shadow:0 2px 8px rgba(35,36,31,.20); white-space:nowrap;}
734.leaflet-tooltip.bwk-linien-name::before{display:none !important;}
735
736/* ============================================================
737   Popups
738   ============================================================ */
739.leaflet-popup-content-wrapper{padding:0 !important; overflow:hidden;
740  border-radius:14px !important; box-shadow:var(--bwk-schatten-hoch) !important;
741  background:#fff;}
742.leaflet-popup-content{margin:0 !important; font-family:inherit; font-size:14px;
743  line-height:1.5; color:#23241f;}
744.leaflet-popup-tip{box-shadow:none;}
745.leaflet-popup-close-button{top:5px !important; right:6px !important;
746  width:22px !important; height:22px !important; font-size:18px !important;
747  line-height:20px !important; color:#a49d92 !important; border-radius:50%;}
748.leaflet-popup-close-button:hover{color:#23241f !important;
749  background:rgba(35,36,31,.06) !important;}
750/* Leaflet blendet bei zu hohem Inhalt diese Klasse ein und
751   fängt das Mausrad selbst ab – nur senkrecht scrollen.      */
752.leaflet-popup-scrolled{overflow-x:hidden !important;
753  border-top:0 !important; border-bottom:0 !important;
754  overscroll-behavior:contain;}
755
756.bwk-pop{min-width:190px; max-width:100%; overflow-wrap:anywhere;}
757/* feine Farbleiste als Zeichen der Kategorie */
758.bwk-pop-balken{height:3px; background:var(--bwk-pop-farbe);}
759.bwk-pop-kopf{padding:11px 34px 0 16px;}
760.bwk-pop-titel{margin:0; font-size:16px; font-weight:700; line-height:1.3;
761  color:#23241f; letter-spacing:-.01em;}
762.bwk-pop-adresse{display:flex; align-items:flex-start; gap:6px;
763  margin:4px 0 0; font-size:12.5px; line-height:1.4; color:#6f6a62;}
764.bwk-pop-adresse svg{flex:0 0 auto; margin-top:2px; color:var(--bwk-pop-text);
765  opacity:.75;}
766/* auslaufende Haarlinie statt harter Kante */
767.bwk-pop-trenner{height:1px; margin:10px 16px 0; border:0;
768  background:linear-gradient(90deg,
769    var(--bwk-pop-linie) 0%, rgba(35,36,31,.10) 45%, rgba(35,36,31,0) 100%);}
770.bwk-pop-koerper{padding:10px 16px 12px;}
771.bwk-pop-text{margin:0;}
772.bwk-pop-text a{color:var(--bwk-pop-text); font-weight:600;
773  text-decoration:underline; text-underline-offset:2px;
774  text-decoration-color:var(--bwk-pop-linie); overflow-wrap:anywhere;}
775.bwk-pop-text a:hover{text-decoration-color:currentColor;}
776
777.bwk-pop-marke{display:block; margin:0 0 7px; font-size:10.5px; font-weight:700;
778  letter-spacing:.11em; text-transform:uppercase; color:#a49d92;}
779.bwk-pop-koerper .bwk-pop-text + .bwk-pop-marke{margin-top:13px; padding-top:11px;
780  border-top:1px solid #f2eee7;}
781
782/* ---------- Terminliste ---------- */
783.bwk-pop-liste{margin:0; padding:0; list-style:none;}
784.bwk-pop-liste li{display:flex; align-items:flex-start; gap:10px;
785  padding:9px 0; border-top:1px solid #f2eee7;}
786.bwk-pop-liste li:first-child{border-top:0; padding-top:1px;}
787.bwk-termin-icon{flex:0 0 auto; margin-top:2px; color:#b0a99e;}
788.bwk-termin-icon svg{display:block;}
789.bwk-termin-text{flex:1 1 auto; min-width:0;}
790.bwk-termin-datum{display:block; margin:0 0 3px; font-size:12px; font-weight:700;
791  line-height:1.35; color:#5f5a52; font-variant-numeric:tabular-nums;}
792.bwk-termin-zeit{font-weight:600; color:#948d83; white-space:nowrap;}
793.bwk-termin-titel{display:block; font-size:14px; line-height:1.4;
794  font-weight:600; color:#23241f; overflow-wrap:anywhere;}
795a.bwk-termin-titel{text-decoration:none;}
796a.bwk-termin-titel:hover{color:var(--bwk-pop-text);
797  text-decoration:underline; text-underline-offset:2px;}
798
799/* ============================================================
800   Schaltflächen in der Karte
801   ============================================================ */
802.leaflet-touch .leaflet-bar, .leaflet-bar{border:0 !important;
803  border-radius:11px !important; overflow:hidden;
804  box-shadow:0 2px 10px rgba(35,36,31,.18) !important;}
805.leaflet-bar a{background:#fff; color:var(--bwk-tinte);
806  border-bottom:1px solid var(--bwk-linie-fein) !important;
807  transition:background-color .15s ease-out, color .15s ease-out;}
808.leaflet-bar a:last-child{border-bottom:0 !important;}
809
810/* Zoom: grüner Grund, weißes Zeichen beim Überfahren */
811.leaflet-control-zoom a{font-size:19px; font-weight:600; text-decoration:none !important;}
812.leaflet-control-zoom a:hover, .leaflet-control-zoom a:focus{
813  background:var(--bwk-akzent) !important; color:#fff !important;
814  text-decoration:none !important;}
815
816.bwk-knopf a{display:flex !important; align-items:center; justify-content:center;
817  width:34px; height:34px;}
818.bwk-knopf a svg{display:block;}
819
820/* Vollbild: weiß mit grünem Zeichen, beim Überfahren umgekehrt;
821   im Vollbild grün gefüllt, beim Überfahren wieder weiß         */
822.bwk-vollbildknopf a{background:#fff !important; color:var(--bwk-akzent) !important;}
823.bwk-vollbildknopf a:hover{background:var(--bwk-akzent) !important; color:#fff !important;}
824.bwk-vollbildknopf.bwk-aktiv a{background:var(--bwk-akzent) !important; color:#fff !important;}
825.bwk-vollbildknopf.bwk-aktiv a:hover{background:#fff !important;
826  color:var(--bwk-akzent) !important;}
827
828.bwk-ebenenknopf{display:block !important;}
829.bwk-ebenenknopf a{background:#fff !important; color:var(--bwk-akzent) !important;}
830.bwk-ebenenknopf a:hover{background:var(--bwk-akzent) !important; color:#fff !important;}
831
832/* ============================================================
833   Karte und Hinweiszeile
834   ============================================================ */
835/* Feste Höhe hier ist der eigentliche Trick: ohne sie hat die
836   Kartenbox nur eine "automatische" Höhe (die sich aus dem Inhalt
837   ergibt), und dann kann "max-height: calc(100% - ...)" beim
838   schwebenden Menü nicht berechnet werden – das Menü würde beim
839   Aufklappen unbegrenzt nach unten wachsen statt intern zu
840   scrollen. Gleicher Wert wie #bwk-karte, damit sich am Aussehen
841   nichts ändert. */
842#bwk-kartenbox{position:relative; height:clamp(460px, 72vh, 780px);}
843#bwk-karte{width:100%; height:clamp(460px, 72vh, 780px);
844  border:1px solid var(--bwk-linie); border-radius:16px; background:#e8e6e1;
845  position:relative; z-index:0; isolation:isolate; overflow:hidden;}
846#bwk-karte.bwk-zweifinger{touch-action:pan-y !important;}
847#bwk-hinweis{position:absolute; inset:0; margin:0; z-index:1000;
848  display:flex; align-items:center; justify-content:center; text-align:center;
849  padding:0 24px; border-radius:16px;
850  background:rgba(25,25,22,.5); color:#fff; font-size:16px; font-weight:600;
851  opacity:0; visibility:hidden; transition:opacity .18s ease-out;
852  pointer-events:none;}
853#bwk-hinweis.bwk-sichtbar{opacity:1; visibility:visible;}
854
855#bwk-status{margin:11px 2px 0; font-size:12.5px; font-weight:400;
856  line-height:1.5; color:var(--bwk-grau);}
857#bwk-status:empty{display:none;}
858
859/* ============================================================
860   Termin-Zeitraum-Dialog (öffnet sich beim Aktivieren von
861   "Veranstaltungen"). Fest an document.body gehängt, damit er
862   in Vollbild und normaler Ansicht gleichermaßen funktioniert.
863   ============================================================ */
864#bwk-tf-hinter{position:fixed; inset:0; z-index:2147483647;
865  background:rgba(25,25,22,.55);
866  display:flex; align-items:center; justify-content:center; padding:20px;}
867#bwk-tf-hinter[hidden]{display:none;}
868.bwk-tf-box{position:relative; width:min(360px, 100%); background:#fff;
869  border-radius:16px; padding:22px 22px 18px; box-shadow:0 20px 50px rgba(35,36,31,.35);
870  font-family:inherit; color:var(--bwk-tinte);}
871.bwk-tf-schliessen{position:absolute; top:12px; right:12px; width:28px; height:28px;
872  display:flex; align-items:center; justify-content:center; padding:0;
873  border:0; background:none; border-radius:50%; cursor:pointer;
874  color:var(--bwk-grau); font-size:20px; line-height:1;
875  -webkit-appearance:none; appearance:none;}
876.bwk-tf-schliessen:hover{background:rgba(35,36,31,.06); color:var(--bwk-tinte);}
877.bwk-tf-titel{margin:0 26px 16px 0; font-size:17px; font-weight:700;
878  color:var(--bwk-akzent);}
879.bwk-tf-zeile{display:flex; gap:12px; margin:0 0 14px;}
880.bwk-tf-zeile label{flex:1 1 auto; display:flex; flex-direction:column; gap:5px;
881  font-size:12.5px; font-weight:600; color:var(--bwk-grau);}
882.bwk-tf-zeile input[type="date"]{font:inherit; font-size:14px; color:var(--bwk-tinte);
883  border:1px solid var(--bwk-linie); border-radius:8px; padding:7px 8px;
884  background:#fff;}
885.bwk-tf-zeile input[type="date"]:disabled{opacity:.5;}
886.bwk-tf-haken{display:flex; align-items:center; gap:8px; font-size:14px;
887  font-weight:500; margin:0 0 18px; cursor:pointer;}
888.bwk-tf-haken input{width:17px; height:17px; accent-color:var(--bwk-akzent);
889  cursor:pointer; margin:0;}
890.bwk-tf-knoepfe{display:flex; justify-content:flex-end;}
891.bwk-tf-anwenden{font:inherit; font-size:14px; font-weight:600; color:#fff;
892  background:var(--bwk-akzent); border:0; border-radius:10px; padding:9px 18px;
893  cursor:pointer; transition:background-color .15s ease-out;}
894.bwk-tf-anwenden:hover{background:var(--bwk-akzent-tief);}
895
896/* ============================================================
897   Vollbild
898   ============================================================ */
899html.bwk-vollbild-aktiv, html.bwk-vollbild-aktiv body{overflow:hidden !important;}
900#bwk-kartenbox.bwk-vollbild{
901  position:fixed !important; left:0 !important; top:0 !important;
902  right:0 !important; bottom:0 !important;
903  width:100vw !important; height:100vh !important; height:100dvh !important;
904  margin:0 !important; padding:0 !important; z-index:2147483000;
905  background:#e8e6e1;}
906#bwk-kartenbox.bwk-vollbild #bwk-karte{
907  width:100% !important; height:100% !important;
908  border:0 !important; border-radius:0 !important;}
909#bwk-kartenbox.bwk-vollbild #bwk-hinweis{border-radius:0;}
910/* Das Filtermenü liegt auf der Startseiten-Karte IMMER als
911   schwebendes Feld über der Karte (nicht nur im Vollbild) – über
912   das Ebenen-Icon auf- und zuklappbar. Dieselben Regeln, die sonst
913   nur für .bwk-vollbild gelten, gelten hier immer. */
914#bwk-kartenbox #bwk-menu{
915  position:absolute; z-index:100; left:14px; top:64px;
916  width:min(350px, calc(100vw - 28px)); max-height:calc(100% - 78px);
917  overflow:auto; -webkit-overflow-scrolling:touch;
918  margin:0; padding:14px; border-radius:16px;
919  background:rgba(255,255,255,.97);
920  box-shadow:0 10px 34px rgba(35,36,31,.30);}
921#bwk-kartenbox #bwk-menu .bwk-inhalt{flex-direction:column; gap:12px;}
922#bwk-kartenbox #bwk-menu .bwk-gruppe{
923  width:100%; flex:0 0 auto; min-width:0; gap:9px;
924  border:1px solid var(--bwk-linie-fein); border-radius:12px;
925  background:var(--bwk-flaeche); padding:10px 12px 12px;}
926#bwk-kartenbox #bwk-menu .bwk-menu-zu{display:inline-flex;}
927#bwk-kartenbox #bwk-menu.bwk-zu{display:none;}
928
929@media (max-width:700px){
930  #bwk-menu .bwk-gruppe{width:100%; flex:0 0 100%;}
931  #bwk-karte{height:440px;}
932  #bwk-kartenbox{height:440px;}
933}
934</style>
935
936<div id="bwk-wrap">
937  <div id="bwk-kartenbox">
938    <div id="bwk-menu" class="bwk-zu" aria-label="Kategorien"></div>
939    <div id="bwk-karte"></div>
940    <p id="bwk-hinweis" aria-hidden="true"></p>
941  </div>
942  <p id="bwk-status"></p>
943</div>
944
945<script>
946(function () {
947  "use strict";
948
949  /* =========================================================
950     1) KONFIGURATION
951     ========================================================= */
952
953  var START = { lat: 47.4568, lng: 9.96, zoom: 12 };
954
955  // Startseiten-Variante: zum Start alle Kategorien eingeschaltet
956  var START_ALLE_AUS = false;
957
958  // Alle Ebenen einer Gruppe in der Farbe der Gruppe zeichnen
959  var GRUPPENFARBE = true;
960
961  // Beschriftung dauerhaft anzeigen statt nur beim Überfahren
962  var BESCHRIFTUNG_IMMER = false;
963
964  // Abstand der Beschriftung unter der Nadelspitze (Pixel)
965  var BESCHRIFTUNG_ABSTAND = 5;
966  
967    // Linien (Radwege): sichtbare Stärke, Stärke beim Überfahren
968  // und Breite des unsichtbaren Streifens zum Anklicken
969  var LINIEN_BREITE       = 4;
970  var LINIEN_BREITE_HOVER = 7;
971  var KLICK_BREITE        = 22;
972
973  // Maße der Popups
974  var POPUP_BREITE_MAX = 380;
975  var POPUP_BREITE_MIN = 230;
976  var POPUP_HOEHE_MAX  = 360;   // darüber scrollt Leaflet im Popup
977
978  // Überschrift des Filters
979  var FILTER_TITEL = "Kategorien";
980
981  // Kleiner Hinweis unter der Karte
982  var TERMIN_HINWEIS = "Es kann einen Moment dauern, bis alle " +
983                       "Veranstaltungstermine auf der Karte erscheinen.";
984
985  // Mausrad: "immer" | "strg" (nur mit Strg/⌘) | "klick" (nach Klick in die Karte)
986  var MAUSRAD = "immer";
987
988  // Auf Touchgeräten die Karte nur mit zwei Fingern verschieben,
989  // damit ein Finger weiterhin die Seite scrollt
990  var ZWEI_FINGER_MOBIL = true;
991
992  // Vollbild-Schaltfläche anzeigen
993  var VOLLBILD_KNOPF = true;
994
995  // Gruppen im Vollbild zu Beginn zugeklappt zeigen
996  var VOLLBILD_GRUPPEN_ZU = false;
997
998  // ID der uMap-Datei in der Medienverwaltung. Leer lassen =
999  // keine Kulturebenen, nur Veranstaltungen.
1000  var KULTUR_FILEID = "1355173";
1001
1002  // Adressmuster des RIS für Dokumente aus der Bibliothek
1003  var KULTUR_URL_MUSTER = "/system/web/GetDocument.ashx?fileid={id}";
1004
1005  // Verhindert, dass der Browser eine alte Fassung der Datei anzeigt
1006  var DATEI_FRISCH_LADEN = true;
1007
1008  // Original-Piktogramm von uMap verwenden, sofern es erreichbar
1009  // ist. false = gar kein Zugriff auf umap.openstreetmap.de,
1010  // es erscheinen dann ausschließlich die eingebauten Symbole.
1011  var PIKTOGRAMME_VON_UMAP = true;
1012
1013  // Diagnose in der Konsole: Übersicht der Ebenen und Bilanz,
1014  // welche Bildadressen erreichbar waren
1015  var SYMBOL_BERICHT = true;
1016
1017  // Ab dieser Helligkeit der Ebenenfarbe (0 = schwarz, 1 = weiß)
1018  // wird das Piktogramm schwarz statt weiß gezeichnet
1019  var HELLE_FARBE_AB = 0.62;
1020
1021  // Server der Piktogramme; der erste wird nach Möglichkeit aus
1022  // der Datei übernommen.
1023  var UMAP_SERVER = "https://umap.openstreetmap.de";
1024  var UMAP_ERSATZSERVER = [
1025    "https://umap.openstreetmap.de",
1026    "https://umap.openstreetmap.fr"
1027  ];
1028
1029  // Startseite der Veranstaltungsliste (öffentliche, "freundliche" Adresse).
1030  // Von dort liest der Code das Formular und die Paginierung jedes Mal
1031  // frisch aus – Feldnamen und Blätter-Ziel werden nicht fest verdrahtet.
1032  var VA_URL = "/Aktuelles/Veranstaltungen";
1033
1034  // Sicherheitsobergrenze, damit ein kaputtes "nächste Seite"-Attribut
1035  // nie zu einer Endlosschleife führt.
1036  var VA_MAX_SEITEN = 20;
1037
1038  var DETAIL_PARALLEL = 4;
1039
1040  var CACHE_STUNDEN     = 6;
1041  var ORT_TAGE          = 90;
1042  var FEHLVERSUCH_TAGE  = 7;
1043
1044  // Gemeindegrenzen ändern sich praktisch nie – ruhig lange im
1045  // Browser des Besuchers zwischenspeichern
1046  var GRENZEN_TAGE = 365;
1047  var NEUE_ORTE_PRO_MAL = 40;
1048  var PAUSE_ADRESSSUCHE = 1100;
1049
1050  var BEREICH = { latMin: 47.15, latMax: 47.80, lngMin: 9.55, lngMax: 10.45 };
1051  var NUR_GENAUE_ORTE = true;
1052
1053  var GEMEINDEN = [
1054    "Alberschwende", "Andelsbuch", "Au", "Bezau", "Bizau", "Buch", "Damüls", "Doren",
1055    "Egg", "Hittisau", "Krumbach", "Langen", "Langen bei Bregenz", "Langenegg",
1056    "Lindenberg", "Lingenau", "Mellau", "Reuthe", "Riefensberg", "Schnepfau",
1057    "Schoppernau", "Schröcken", "Schwarzenberg", "Sibratsgfäll", "Sulzberg", "Thal",
1058    "Warth"
1059  ];
1060
1061  // Die 24 Mitgliedsgemeinden der Regio Bregenzerwald – Grundlage
1062  // des Gemeinde-Filters. Absichtlich eine eigene, kürzere Liste
1063  // als GEMEINDEN oben: die brauchen zusätzliche Ortsteile/Varianten
1064  // (z. B. "Thal", "Lindenberg") allein zum Erkennen in Adresstexten.
1065  var GEMEINDE_FILTER = [
1066    "Alberschwende", "Andelsbuch", "Au", "Bezau", "Bizau", "Buch", "Damüls", "Doren",
1067    "Egg", "Hittisau", "Krumbach", "Langen bei Bregenz", "Langenegg", "Lingenau",
1068    "Mellau", "Reuthe", "Riefensberg", "Schnepfau", "Schoppernau", "Schröcken",
1069    "Schwarzenberg", "Sibratsgfäll", "Sulzberg", "Warth"
1070  ];
1071
1072  // Ortsteile/Kurzformen, die keine eigene Gemeinde sind, sondern zu
1073  // einer der obigen 24 gehören (kleingeschrieben, wie erkenneGemeinde
1074  // sie liefert)
1075  var GEMEINDE_ALIAS = {
1076    "langen": "langen bei bregenz",
1077    "lindenberg": "langen bei bregenz",
1078    "thal": "sulzberg"
1079  };
1080
1081  // Auffangbecken für Punkte, die zu keiner der 24 echten Gemeinden
1082  // gehören (weder nach Koordinate noch nach Text) – ein "25. Ort"
1083  // im Filter, statt sie einfach immer anzuzeigen
1084  var GEMEINDE_AUSSERHALB = "Außerhalb vom Bregenzerwald";
1085
1086  // die Liste, die tatsächlich als Filter angezeigt wird (25 Chips).
1087  // GEMEINDE_FILTER selbst bleibt bei den 24 echten Gemeinden, weil
1088  // nur die eine eigene Grenze/einen Namen zum Zuordnen haben.
1089  var GEMEINDE_ANZEIGE = GEMEINDE_FILTER.concat([GEMEINDE_AUSSERHALB]);
1090
1091  var MONATE = ["Jän.", "Feb.", "März", "April", "Mai", "Juni",
1092                "Juli", "Aug.", "Sep.", "Okt.", "Nov.", "Dez."];
1093
1094  var FARBEN = ["#c2410c", "#0e7490", "#15803d", "#7c3aed", "#b91c1c", "#a16207", "#0369a1"];
1095
1096  // Zeitraum-Filter für Veranstaltungen. "alle" = kein Zeitraum
1097  // aktiv, alle Termine werden gezeigt. Wird über den Dialog
1098  // gesetzt, der beim Aktivieren von "Veranstaltungen" aufgeht.
1099  var TERMIN_FILTER = { von: "", bis: "", alle: true };
1100
1101  /* =========================================================
1102     2) EINGEBAUTE PIKTOGRAMME
1103     Inline-SVG im Koordinatenraum 24 x 24. Sie brauchen keine
1104     Netzverbindung und sind darum immer sichtbar.
1105     ========================================================= */
1106
1107  var PIKTOGRAMME = {
1108    punkt:      '<circle cx="12" cy="12" r="5" fill="currentColor" stroke="none"/>',
1109    museum:     '<path d="M3 21h18M5.5 21V10M9.5 21V10M14.5 21V10M18.5 21V10M2.5 9.5 12 4l9.5 5.5"/>',
1110    fahrrad:    '<circle cx="5.5" cy="16.5" r="3.6"/><circle cx="18.5" cy="16.5" r="3.6"/><path d="M5.5 16.5 10 7.5h4.5l4 9M8 7.5h4"/>',
1111    kiosk:      '<path d="M4 9.5h16V20H4zM2.5 9.5 4.5 4.5h15l2 5M9.5 20v-6h5v6"/>',
1112    restaurant: '<path d="M6 3v6a2.5 2.5 0 0 0 5 0V3M8.5 9v12M17.5 3c-1.6 1.2-2.5 3.2-2.5 5.5 0 2 .9 3.5 2.5 3.5v9"/>',
1113    cafe:       '<path d="M4.5 8h12v6a4.5 4.5 0 0 1-4.5 4.5H9A4.5 4.5 0 0 1 4.5 14zM16.5 9.5H18a2.75 2.75 0 0 1 0 5.5h-1.5M3.5 21h14M8 3v2M12 3v2"/>',
1114    hotel:      '<path d="M3 20v-9M3 14h18v6M21 20v-5a3 3 0 0 0-3-3h-6v2"/><circle cx="7" cy="9.5" r="2"/>',
1115    buecherei:  '<path d="M12 6.5C10.5 5 8 4.5 4 4.5V18c4 0 6.5.5 8 2 1.5-1.5 4-2 8-2V4.5c-4 0-6.5.5-8 2zM12 6.5V20"/>',
1116    buehne:     '<path d="M9 17V4l11-2v13"/><circle cx="6" cy="17.5" r="3"/><circle cx="17" cy="15.5" r="3"/>',
1117    kirche:     '<path d="M12 2.5v5M9.5 5h5M6 21v-9.5L12 7l6 4.5V21M10 21v-5h4v5"/>',
1118    info:       '<circle cx="12" cy="12" r="9"/><path d="M12 11v6M12 7.6v.6"/>',
1119    parken:     '<rect x="3.5" y="3.5" width="17" height="17" rx="3.5"/><path d="M9.5 17.5V7h3.4a3.2 3.2 0 0 1 0 6.4H9.5"/>',
1120    aussicht:   '<path d="M3 8.5h4L9 5.5h6l2 3h4V20H3z"/><circle cx="12" cy="13.5" r="3.4"/>',
1121    berg:       '<path d="M2.5 19.5 9 8l4.5 7.5M11 19.5 16.5 10l5 9.5M2.5 19.5h19"/>',
1122    kalender:   '<path d="M8 2.5v3M16 2.5v3M3.5 9.5h17M5 4.5h14a1.5 1.5 0 0 1 1.5 1.5v13a1.5 1.5 0 0 1-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V6A1.5 1.5 0 0 1 5 4.5z"/>',
1123    stern:      '<path d="m12 3.5 2.7 5.6 6 .9-4.4 4.3 1.1 6.1-5.4-2.9-5.4 2.9 1.1-6.1L3.3 10l6-.9z"/>',
1124    handwerk:   '<path d="M14.5 6.5a3.5 3.5 0 0 0 4.6 4.6L21 13l-8 8-2-2 2-2-6-6-2 2-2-2 8-8 1.9 1.9z"/>',
1125    haus:       '<path d="M3.5 10.5 12 3.5l8.5 7M5.5 9.5V20h13V9.5M10 20v-6h4v6"/>',
1126    werkstatt:  '<path d="M3 20.5V9l9-5.5 9 5.5v11.5M3 20.5h18M8 20.5V13h8v7.5"/>',
1127    wasser:     '<path d="M12 3.5c3.5 4.4 5.5 7.4 5.5 10a5.5 5.5 0 0 1-11 0c0-2.6 2-5.6 5.5-10z"/>',
1128    schule:     '<path d="M2.5 8.5 12 4l9.5 4.5L12 13z"/><path d="M6.5 10.5V16c0 1.5 2.5 3 5.5 3s5.5-1.5 5.5-3v-5.5M21.5 8.5V15"/>'
1129  };
1130
1131  // Dateiname des uMap-Symbols -> eingebautes Symbol
1132  // (die Karte nutzt z. B. /static/pictograms/tourism/museum.svg)
1133  var PIKTOGRAMM_ALIASE = {
1134    "museum": "museum", "art-gallery": "museum", "gallery": "museum", "artwork": "museum",
1135    "monument": "museum", "castle": "museum", "attraction": "museum", "heritage": "museum",
1136    "historic": "museum", "archaeological": "museum",
1137    "bicycle": "fahrrad", "bike": "fahrrad", "cycling": "fahrrad",
1138    "bicycle-share": "fahrrad", "cyclist": "fahrrad", "velo": "fahrrad",
1139    "kiosk": "kiosk", "shop": "kiosk", "convenience": "kiosk", "supermarket": "kiosk",
1140    "marketplace": "kiosk", "bakery": "kiosk", "commercial": "kiosk", "grocery": "kiosk",
1141    "clothing-store": "kiosk", "butcher": "kiosk", "greengrocer": "kiosk",
1142    "restaurant": "restaurant", "fast-food": "restaurant", "food": "restaurant",
1143    "fastfood": "restaurant", "pizza": "restaurant", "eat": "restaurant",
1144    "cafe": "cafe", "coffee": "cafe", "bar": "cafe", "pub": "cafe", "beer": "cafe",
1145    "drink": "cafe", "teahouse": "cafe", "ice-cream": "cafe",
1146    "hotel": "hotel", "hostel": "hotel", "motel": "hotel", "lodging": "hotel",
1147    "guest-house": "hotel", "bed": "hotel", "campsite": "hotel", "camping": "hotel",
1148    "shelter": "hotel", "alpinehut": "hotel", "alpine-hut": "hotel",
1149    "library": "buecherei", "book": "buecherei", "books": "buecherei",
1150    "school": "schule", "college": "schule", "university": "schule",
1151    "kindergarten": "schule", "education": "schule",
1152    "theatre": "buehne", "theater": "buehne", "cinema": "buehne", "movie": "buehne",
1153    "music": "buehne", "concert": "buehne", "art": "buehne", "arts-centre": "buehne",
1154    "community-centre": "buehne", "dance": "buehne",
1155    "place-of-worship": "kirche", "church": "kirche", "chapel": "kirche",
1156    "religious-christian": "kirche", "cemetery": "kirche", "worship": "kirche",
1157    "information": "info", "tourist-information": "info", "town-hall": "info",
1158    "townhall": "info", "government": "info", "embassy": "info", "office": "info",
1159    "post": "info", "bank": "info",
1160    "parking": "parken", "car": "parken", "bus": "parken", "rail": "parken",
1161    "train": "parken", "airport": "parken", "fuel": "parken", "charging-station": "parken",
1162    "viewpoint": "aussicht", "camera": "aussicht", "photo": "aussicht",
1163    "telescope": "aussicht", "binoculars": "aussicht",
1164    "mountain": "berg", "peak": "berg", "hiking": "berg", "walking": "berg",
1165    "hike": "berg", "trail": "berg", "park": "berg", "picnic-site": "berg",
1166    "picnic": "berg", "tree": "berg", "forest": "berg", "garden": "berg",
1167    "nature-reserve": "berg", "cave": "berg", "skiing": "berg",
1168    "water": "wasser", "drinking-water": "wasser", "swimming": "wasser",
1169    "waterfall": "wasser", "fountain": "wasser", "lake": "wasser", "spring": "wasser",
1170    "calendar": "kalender", "event": "kalender", "clock": "kalender", "date": "kalender",
1171    "star": "stern", "marker": "stern", "circle": "stern", "square": "stern",
1172    "heart": "stern", "flag": "stern",
1173    "hammer": "handwerk", "tools": "handwerk", "wrench": "handwerk",
1174    "craft": "handwerk", "industrial": "handwerk", "factory": "werkstatt",
1175    "building": "haus", "home": "haus", "house": "haus", "village": "haus",
1176    "farm": "haus", "hut": "haus"
1177  };
1178
1179  // Wörter im Ebenen- oder Punktnamen -> eingebautes Symbol
1180  // (greift, wenn die Datei keine oder eine unbekannte iconUrl hat)
1181  var WORT_SYMBOLE = [
1182    ["museum", "museum"], ["ausstellung", "museum"], ["galerie", "museum"],
1183    ["sammlung", "museum"], ["denkmal", "museum"], ["schauraum", "museum"],
1184    ["büchere", "buecherei"], ["buechere", "buecherei"], ["bibliothek", "buecherei"],
1185    ["archiv", "buecherei"], ["lesen", "buecherei"],
1186    ["kirche", "kirche"], ["kapelle", "kirche"], ["pfarr", "kirche"],
1187    ["kloster", "kirche"], ["friedhof", "kirche"],
1188    ["gasthaus", "restaurant"], ["gasthof", "restaurant"], ["restaurant", "restaurant"],
1189    ["wirtshaus", "restaurant"], ["essen", "restaurant"], ["küche", "restaurant"],
1190    ["kulinarik", "restaurant"], ["jausen", "restaurant"],
1191    ["café", "cafe"], ["cafe", "cafe"], ["kaffee", "cafe"], ["bar", "cafe"],
1192    ["stube", "cafe"], ["konditorei", "cafe"],
1193    ["hotel", "hotel"], ["pension", "hotel"], ["gästehaus", "hotel"],
1194    ["ferienwohnung", "hotel"], ["übernacht", "hotel"], ["unterkunft", "hotel"],
1195    ["camping", "hotel"],
1196    ["fahrradbus", "fahrrad"], ["rad", "fahrrad"], ["bike", "fahrrad"], ["velo", "fahrrad"],
1197    ["haltestelle", "parken"], ["mobilität", "parken"], ["bahnhof", "parken"],
1198    ["bus", "parken"], ["parkplatz", "parken"],
1199    ["wander", "berg"], ["berg", "berg"], ["gipfel", "berg"], ["alpe", "berg"],
1200    ["alm", "berg"], ["natur", "berg"], ["route", "berg"],
1201    ["aussicht", "aussicht"], ["panorama", "aussicht"], ["blick", "aussicht"],
1202    ["bühne", "buehne"], ["buehne", "buehne"], ["theater", "buehne"],
1203    ["konzert", "buehne"], ["musik", "buehne"], ["kino", "buehne"],
1204    ["kultur", "buehne"], ["kunst", "buehne"],
1205    ["info", "info"], ["tourismus", "info"], ["gemeinde", "info"],
1206    ["rathaus", "info"], ["amt", "info"],
1207    ["gutschein", "kiosk"], ["laden", "kiosk"], ["shop", "kiosk"],
1208    ["geschäft", "kiosk"], ["markt", "kiosk"], ["hofladen", "kiosk"],
1209    ["bäcker", "kiosk"], ["metzger", "kiosk"], ["käse", "kiosk"],
1210    ["senner", "kiosk"], ["molkerei", "kiosk"], ["regional", "kiosk"],
1211    ["handwerk", "handwerk"], ["werkstatt", "werkstatt"], ["tischler", "handwerk"],
1212    ["schreiner", "handwerk"], ["zimmerei", "handwerk"], ["betrieb", "handwerk"],
1213    ["partner", "handwerk"], ["produktion", "werkstatt"],
1214    ["schule", "schule"], ["kindergarten", "schule"], ["bildung", "schule"],
1215    ["bad", "wasser"], ["see", "wasser"], ["brunnen", "wasser"],
1216    ["wasser", "wasser"], ["schwimm", "wasser"],
1217    ["veranstaltung", "kalender"], ["termin", "kalender"], ["kalender", "kalender"]
1218  ];
1219
1220  var VA_BILD = { quellen: [], grund: "kalender" };
1221
1222  var ORTE = {
1223    // "dorfbücherei@riefensberg": { name: "Dorfbücherei", adresse: "…", lat: 47.49, lng: 9.90 }
1224  };
1225
1226  var EBENEN = [
1227    { id: "va-kalender", name: "Veranstaltungen", farbe: "#1d4ed8",
1228      bild: VA_BILD, aktiv: !START_ALLE_AUS, punkte: [] }
1229  ];
1230
1231  /* =========================================================
1232     3) GRUNDLAGEN
1233     ========================================================= */
1234
1235  var karte, layerVon = {}
1235, statusFeld, hinweisFeld, hinweisZeit, wartendeZeichnung = null;
1236  var CACHE_ORTE = "bwk-orte-v2", CACHE_TERMINE = "bwk-termine-v3";
1237  var CACHE_GRENZEN = "bwk-grenzen-v2";
1238  var letzteOffene = [], farbZaehler = 0, gruppenZaehler = 0;
1239  var menuInhalt, listeKultur, gruppeFest, kulturEbenen = [], kulturGruppen = [];
1240  var menuBox, menuHeimat, menuAnker, alleGruppen = [], alleKnopf = null;
1241  var kartenbox, kartenHeimat, kartenAnker;
1242  var vollbildAn = false, vollbildErsatz = false, vollbildWechsel = false;
1243  var vollbildKnopf = null;
1244  var SYMBOL_STAND = {}, bilanzZeit = null;
1245  var FERN_CACHE = {}, FERN_WARTEN = {};
1246  var GEMEINDE_STAND = {}, GEMEINDE_ZEILEN = {}, gemeindeAlleKnopf = null;
1247  // Polygone der Gemeindegrenzen (von Nominatim geladen) und ob sie
1248  // schon (zumindest einmal) fertig geladen sind
1249  var GEMEINDE_GRENZEN = {}, GRENZEN_GELADEN = false;
1250
1251  function sicher(name, fn) {
1252    try { fn(); } catch (e) { console.warn("[Karte] " + name + ":", e); }
1253  }
1254  function txt(s) { return (s || "").replace(/\s+/g, " ").trim(); }
1255  function esc(s) {
1256    return String(s == null ? "" : s).replace(/&/g, "&amp;").replace(/</g, "&lt;")
1257      .replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1258  }
1259  function schlafe(ms) { return new Promise(function (r) { setTimeout(r, ms); }); }
1260  function findeEbene(id) {
1261    var t = null;
1261 EBENEN.forEach(function (e) { if (e.id === id) t = e; }); return t;
1262  }
1263  function imBereich(lat, lng) {
1264    return lat > BEREICH.latMin && lat < BEREICH.latMax &&
1265           lng > BEREICH.lngMin && lng < BEREICH.lngMax;
1266  }
1267  function speicherLesen(k) {
1268    try { return JSON.parse(window.localStorage.getItem(k) || "null"); } catch (e) { return null; }
1269  }
1270  function speicherSchreiben(k, d) {
1271    try { window.localStorage.setItem(k, JSON.stringify(d)); } catch (e) { }
1272  }
1273  function normalisiere(s) {
1274    return txt(s).toLowerCase()
1275      .replace(/[.,;:()"'´`]/g, " ")
1276      .replace(/\b(im|in|am|an|der|die|das|dem|den|bei|zum|zur)\b/g, " ")
1277      .replace(/\s+/g, " ").trim();
1278  }
1279  function erkenneGemeinde() {
1280    var quelle = (Array.prototype.join.call(arguments, " ") || "").toLowerCase();
1281    var treffer = "";
1282    GEMEINDEN.forEach(function (g) {
1283      var klein = g.toLowerCase();
1284      var passt = klein.length <= 4
1285        ? new RegExp("(^|[^a-zäöüß])" + klein + "([^a-zäöüß]|$)").test(quelle)
1286        : quelle.indexOf(klein) !== -1;
1287      if (passt && klein.length > treffer.length) treffer = klein;
1288    });
1289    return treffer;
1290  }
1291  function naechsteFarbe() {
1292    var f = FARBEN[farbZaehler % FARBEN.length];
1293    farbZaehler++;
1294    return f;
1295  }
1296
1297  // Rohtreffer von erkenneGemeinde() (klein geschrieben) auf eine der
1298  // 24 Filter-Gemeinden abbilden – über GEMEINDE_ALIAS, sonst direkt
1299  function gemeindeKanonisch(rohTreffer) {
1300    if (!rohTreffer) return "";
1301    var kanon = GEMEINDE_ALIAS[rohTreffer] || rohTreffer;
1302    var treffer = "";
1303    GEMEINDE_FILTER.forEach(function (g) {
1304      if (g.toLowerCase() === kanon) treffer = g;
1305    });
1306    return treffer;
1307  }
1308
1309  // exakter Name (z. B. die "Datenquelle" einer Veranstaltung) auf
1310  // eine der 24 Filter-Gemeinden abbilden
1311  function gemeindeVonName(name) {
1312    var n = txt(name).toLowerCase();
1313    if (!n) return "";
1314    var treffer = "";
1315    GEMEINDE_FILTER.forEach(function (g) {
1316      if (g.toLowerCase() === n) treffer = g;
1317    });
1318    return treffer;
1319  }
1320
1321  // ist die Gemeinde eines Punkts gerade angehakt? Nicht zuordenbare
1322  // Punkte (leerer Name) bleiben immer sichtbar.
1323  function gemeindeSichtbar(gemeinde) {
1324    if (!gemeinde) return true;
1325    return GEMEINDE_STAND[gemeinde] !== false;
1326  }
1327
1328  /* ---------- Gemeindegrenzen (Polygone von Nominatim) ----------
1329     Genauer als die Texterkennung oben, vor allem bei Kulturpunkten,
1330     deren Adresse nicht immer den Gemeindenamen enthält. Wird einmal
1331     pro Browser geladen (24 Anfragen, ca. 1 pro Sekunde wie an
1332     anderer Stelle im Code schon üblich) und lange zwischengespeichert,
1333     da sich Gemeindegrenzen praktisch nie ändern. Bis die Grenzen da
1334     sind bzw. wenn ein Punkt in keiner Grenze liegt, greift weiter
1335     die Texterkennung von oben. ---------- */
1336
1337  // Punkt-in-Polygon nach dem Ray-Casting-Verfahren.
1338  // ring: Liste von [lng, lat]-Paaren (GeoJSON-Reihenfolge)
1339  function punktInRing(lat, lng, ring) {
1340    var innen = false;
1341    for (var i = 0, j = ring.length - 1; i < ring.length; j = i++) {
1342      var xi = ring[i][0], yi = ring[i][1];
1343      var xj = ring[j][0], yj = ring[j][1];
1344      var schneidet = ((yi > lat) !== (yj > lat)) &&
1345        (lng < (xj - xi) * (lat - yi) / (yj - yi) + xi);
1346      if (schneidet) innen = !innen;
1347    }
1348    return innen;
1349  }
1350
1351  // polygon: [ äußererRing, Loch1, Loch2, … ] (GeoJSON "Polygon")
1352  function punktInPolygon(lat, lng, polygon) {
1353    if (!polygon || !polygon.length) return false;
1354    if (!punktInRing(lat, lng, polygon[0])) return false;
1355    for (var i = 1; i < polygon.length; i++) {
1356      if (punktInRing(lat, lng, polygon[i])) return false;   // liegt in einem Loch
1357    }
1358    return true;
1359  }
1360
1361  function punktInGeometrie(lat, lng, geometrie) {
1362    if (!geometrie) return false;
1363    if (geometrie.type === "Polygon") return punktInPolygon(lat, lng, geometrie.coordinates);
1364    if (geometrie.type === "MultiPolygon") {
1365      return geometrie.coordinates.some(function (poly) { return punktInPolygon(lat, lng, poly); });
1366    }
1367    return false;
1368  }
1369
1370  // welche der 24 Filter-Gemeinden enthält diese Koordinate?
1371  function gemeindeAusKoordinaten(lat, lng) {
1372    if (typeof lat !== "number" || typeof lng !== "number") return "";
1373    if (isNaN(lat) || isNaN(lng)) return "";
1374    var treffer = "";
1375    GEMEINDE_FILTER.forEach(function (g) {
1376      if (treffer) return;
1377      if (punktInGeometrie(lat, lng, GEMEINDE_GRENZEN[g])) treffer = g;
1378    });
1379    return treffer;
1380  }
1381
1382  /* ---------- Grenzen laden: eine einzige Sammelabfrage ----------
1383     Statt 24 einzelner Nominatim-Anfragen im Sekundentakt (dauerte
1384     rund 30 Sekunden) holt eine einzige Overpass-Abfrage alle
1385     Gemeindegrenzen im Kartenausschnitt auf einmal. Das ist in der
1386     Regel nach wenigen Sekunden fertig. Overpass liefert je Gemeinde
1387     eine Relation aus mehreren Wegstücken (Rollen "outer"/"inner"),
1388     die hier zu geschlossenen Ringen zusammengesetzt werden. ---------- */
1389
1390  function koordinatenGleich(a, b) {
1391    return Math.abs(a[0] - b[0]) < 1e-7 && Math.abs(a[1] - b[1]) < 1e-7;
1392  }
1393
1394  // setzt die Wegstücke einer Rolle ("outer" bzw. "inner") zu
1395  // geschlossenen Ringen zusammen ([lng,lat]-Listen)
1396  function ringeAusMembers(members, rolle) {
1397    var segmente = (members || [])
1398      .filter(function (m) { return m.type === "way" && m.role === rolle && m.geometry && m.geometry.length > 1; })
1399      .map(function (m) { return m.geometry.map(function (p) { return [p.lon, p.lat]; }); });
1400
1401    var ringe = [];
1402    while (segmente.length) {
1403      var ring = segmente.shift().slice();
1404      var versuche = segmente.length + 1;
1405      while (!koordinatenGleich(ring[0], ring[ring.length - 1]) && versuche-- > 0) {
1406        var ende = ring[ring.length - 1], gefunden = -1, dreh = false;
1407        for (var i = 0; i < segmente.length; i++) {
1408          if (koordinatenGleich(segmente[i][0], ende)) { gefunden = i; dreh = false; break; }
1409          if (koordinatenGleich(segmente[i][segmente[i].length - 1], ende)) { gefunden = i; dreh = true; break; }
1410        }
1411        if (gefunden === -1) break;   // keine Fortsetzung gefunden – Ring bleibt wie er ist
1412        var teil = segmente.splice(gefunden, 1)[0];
1413        if (dreh) teil = teil.slice().reverse();
1414        ring = ring.concat(teil.slice(1));
1415      }
1416      if (ring.length > 3) ringe.push(ring);
1417    }
1418    return ringe;
1419  }
1420
1421  // eine Overpass-Relation (eine Gemeinde) in GeoJSON-Geometrie
1422  // übersetzen
1423  function geometrieAusRelation(relation) {
1424    var aussen = ringeAusMembers(relation.members, "outer");
1425    if (!aussen.length) return null;
1426    var innen = ringeAusMembers(relation.members, "inner");
1427    if (aussen.length === 1) {
1428      return { type: "Polygon", coordinates: [aussen[0]].concat(innen) };
1429    }
1430    // mehrere Außenringe (z. B. Exklaven): jeder für sich, Löcher
1431    // vereinfachend ignoriert (in der Praxis bei diesen Gemeinden
1432    // ohne Belang)
1433    return { type: "MultiPolygon", coordinates: aussen.map(function (r) { return [r]; }) };
1434  }
1435
1436  // lädt (bzw. liest aus dem Zwischenspeicher) alle 24 Grenzen auf
1437  // einmal und zeichnet danach neu
1438  function ladeGemeindeGrenzen() {
1439    var cache = speicherLesen(CACHE_GRENZEN);
1440    var jetzt = Date.now();
1441    if (cache && cache.zeit && cache.grenzen &&
1442        (jetzt - cache.zeit) < GRENZEN_TAGE * 86400000) {
1443      GEMEINDE_GRENZEN = cache.grenzen;
1444      GRENZEN_GELADEN = true;
1445      neuZeichnenAlle();
1446      console.info("[Karte] Gemeindegrenzen aus dem Zwischenspeicher: " +
1447        Object.keys(GEMEINDE_GRENZEN).length + " von " + GEMEINDE_FILTER.length);
1448      return;
1449    }
1450
1451    var abfrage = "[out:json][timeout:25];" +
1452      "relation[\"boundary\"=\"administrative\"][\"admin_level\"=\"8\"]" +
1453      "(" + BEREICH.latMin + "," + BEREICH.lngMin + "," +
1454            BEREICH.latMax + "," + BEREICH.lngMax + ");" +
1455      "out geom;";
1456    var url = "https://overpass-api.de/api/interpreter?data=" + encodeURIComponent(abfrage);
1457
1458    fetch(url).then(function (r) { return r.json(); }).then(function (daten) {
1459      var gefunden = {};
1460      (daten.elements || []).forEach(function (el) {
1461        if (el.type !== "relation" || !el.tags || !el.tags.name) return;
1462        var name = gemeindeVonName(el.tags.name);
1463        if (!name || gefunden[name]) return;
1464        var geo = geometrieAusRelation(el);
1465        if (geo) gefunden[name] = geo;
1466      });
1467      GEMEINDE_GRENZEN = gefunden;
1468      GRENZEN_GELADEN = true;
1469      speicherSchreiben(CACHE_GRENZEN, { zeit: Date.now(), grenzen: gefunden });
1470      neuZeichnenAlle();
1471      console.info("[Karte] Gemeindegrenzen geladen: " +
1472        Object.keys(gefunden).length + " von " + GEMEINDE_FILTER.length);
1473    }).catch(function (fehler) {
1474      console.warn("[Karte] Gemeindegrenzen konnten nicht geladen werden – " +
1475        "Zuordnung läuft weiter über Textabgleich:", fehler);
1476    });
1477  }
1478
1479  // Eigenschaft aus einem uMap-Objekt holen (Ebene oder einzelner Punkt).
1480  // _storage_options kommt in älteren Exporten vor.
1481  function opt(o, schluessel, ersatz) {
1482    if (!o) return ersatz;
1483    var quellen = [
1484      o._umap_options,
1485      o._storage_options,
1486      o.properties && o.properties._umap_options,
1487      o.properties && o.properties._storage_options,
1488      o.properties,
1489      o
1490    ];
1491    for (var i = 0; i < quellen.length; i++) {
1492      var q = quellen[i];
1493      if (q && q[schluessel] !== undefined && q[schluessel] !== null && q[schluessel] !== "") {
1494        return q[schluessel];
1495      }
1496    }
1497    return ersatz;
1498  }
1499  function nameAus(o, ersatz) { return opt(o, "name", ersatz); }
1500  function farbeAus(o, ersatz) { return opt(o, "color", ersatz); }
1501
1502  /* =========================================================
1503     4) FARBEN
1504     ========================================================= */
1505
1506  function farbTeile(farbe) {
1507    var s = txt(farbe).replace(/^#/, "");
1508    if (s.length === 3) s = s[0] + s[0] + s[1] + s[1] + s[2] + s[2];
1509    if (!/^[0-9a-f]{6}$/i.test(s)) return null;
1510    return [parseInt(s.slice(0, 2), 16), parseInt(s.slice(2, 4), 16), parseInt(s.slice(4, 6), 16)];
1511  }
1512  // Helligkeit einer Farbe (0 = schwarz, 1 = weiß)
1513  function helligkeit(farbe) {
1514    var t = farbTeile(farbe);
1515    if (!t) return 0.3;   // Farbnamen: als dunkel behandeln
1516    return (0.2126 * t[0] + 0.7152 * t[1] + 0.0722 * t[2]) / 255;
1517  }
1518  // Piktogrammfarbe: weiß auf dunklem, schwarz auf hellem Marker
1519  function symbolFarbe(farbe) {
1520    return helligkeit(farbe) > HELLE_FARBE_AB ? "#1a1a18" : "#ffffff";
1521  }
1522  function istDunkelSymbol(farbe) { return symbolFarbe(farbe) !== "#ffffff"; }
1523
1524  function rgba(farbe, deckung) {
1525    var t = farbTeile(farbe);
1526    if (!t) return "rgba(47,107,79," + deckung + ")";
1527    return "rgba(" + t[0] + "," + t[1] + "," + t[2] + "," + deckung + ")";
1528  }
1529  function abdunkeln(farbe, anteil) {
1530    var t = farbTeile(farbe);
1531    if (!t) return "#2f6b4f";
1532    return "#" + t.map(function (v) {
1533      var n = Math.round(v * anteil);
1534      return (n < 16 ? "0" : "") + n.toString(16);
1535    }).join("");
1536  }
1537  // helle Ebenenfarben sind als Schriftfarbe unlesbar: abdunkeln
1538  function lesbar(farbe) {
1539    var h = helligkeit(farbe);
1540    if (h > 0.72) return abdunkeln(farbe, 0.42);
1541    if (h > 0.55) return abdunkeln(farbe, 0.62);
1542    return farbe || "#2f6b4f";
1543  }
1544
1545  /* =========================================================
1546     5) PIKTOGRAMME
1547     ========================================================= */
1548
1549  function serverListe() {
1550    var raus = [];
1551    [UMAP_SERVER].concat(UMAP_ERSATZSERVER).forEach(function (s) {
1552      s = txt(s).replace(/\/+$/, "").replace(/^http:/i, "https:");
1553      if (s && raus.indexOf(s) === -1) raus.push(s);
1554    });
1555    return raus;
1556  }
1557
1558  // alle Adressen, unter denen das Original-Piktogramm versucht wird
1559  function bildAdressen(roh) {
1560    roh = txt(roh).replace(/["'()<>\\]/g, "");
1561    if (!roh) return [];
1562    if (/^data:/i.test(roh)) return [roh];
1563
1564    var liste = [], pfad = "";
1565
1566    if (/^https?:\/\//i.test(roh) || roh.indexOf("//") === 0) {
1567      var voll = roh.indexOf("//") === 0 ? "https:" + roh : roh.replace(/^http:/i, "https:");
1568      liste.push(voll);
1569      try { pfad = new URL(voll).pathname; } catch (e) { pfad = ""; }
1570    } else if (roh.indexOf("/") !== -1 || /\.[a-z0-9]{2,4}$/i.test(roh)) {
1571      pfad = roh.charAt(0) === "/" ? roh : "/" + roh;
1572    }
1573
1574    if (pfad) {
1575      serverListe().forEach(function (server) {
1576        var u = server + pfad;
1577        if (liste.indexOf(u) === -1) liste.push(u);
1578      });
1579    }
1580    return liste;
1581  }
1582
1583  // "/static/pictograms/tourism/museum.svg" -> "museum"
1584  function symbolAusDatei(u) {
1585    var teil = txt(u).split("?")[0].split("#")[0].split("/").pop() || "";
1586    var n = teil.replace(/\.[a-z0-9]+$/i, "").toLowerCase();
1587    if (!n) return "";
1588
1589    var stufen = [n, n.replace(/[-_]?\d+$/, ""), n.replace(/[-_](15|24|18|11)$/, "")];
1590    for (var i = 0; i < stufen.length; i++) {
1591      var s = stufen[i];
1592      if (!s) continue;
1593      if (PIKTOGRAMME[s]) return s;
1594      if (PIKTOGRAMM_ALIASE[s] && PIKTOGRAMME[PIKTOGRAMM_ALIASE[s]]) {
1595        return PIKTOGRAMM_ALIASE[s];
1596      }
1597    }
1598    var ganz = txt(u).toLowerCase(), treffer = "";
1599    Object.keys(PIKTOGRAMM_ALIASE).forEach(function (k) {
1600      if (k.length > 3 && ganz.indexOf(k) !== -1 && k.length > treffer.length) treffer = k;
1601    });
1602    return treffer ? PIKTOGRAMM_ALIASE[treffer] : "";
1603  }
1604
1605  // Symbol aus einem Klartext (Ebenen- oder Punktname) ableiten
1606  function symbolAusText(text) {
1607    var s = txt(text).toLowerCase();
1608    if (!s) return "";
1609    var name = "", laenge = 0;
1610    WORT_SYMBOLE.forEach(function (paar) {
1611      if (s.indexOf(paar[0]) !== -1 && paar[0].length > laenge) {
1612        laenge = paar[0].length; name = paar[1];
1613      }
1614    });
1615    return PIKTOGRAMME[name] ? name : "";
1616  }
1617
1618  // vereinheitlicht Bildangaben zu { quellen: [ … ], grund: "…", fern: "…" }
1619  function alsBild(x) {
1620    if (!x) return null;
1621    if (typeof x === "string") return { quellen: [x], grund: "punkt" };
1622    if (Array.isArray(x)) return x.length ? { quellen: x.slice(), grund: "punkt" } : null;
1623    if (x.quellen || x.grund) {
1624      return { quellen: (x.quellen || []).slice(), grund: x.grund || "punkt", fern: x.fern };
1625    }
1626    if (x.quelle) {
1627      var l = [x.quelle];
1628      if (x.ersatz) l.push(x.ersatz);
1629      return { quellen: l, grund: "punkt" };
1630    }
1631    return null;
1632  }
1633
1634  // liefert { quellen: [ … ], grund: "…" }
1635  function iconInfo(o, vorgabe, hinweisText) {
1636    var roh = txt(opt(o, "iconUrl", ""));
1637
1638    if (!roh) {
1639      var v = alsBild(vorgabe);
1640      if (v) return v;
1641      return { quellen: [], grund: symbolAusText(hinweisText) || "punkt" };
1642    }
1643
1644    var grund = symbolAusDatei(roh) || symbolAusText(hinweisText) || "punkt";
1645    var quellen;
1646    if (/^data:/i.test(roh)) quellen = [roh];
1647    else quellen = PIKTOGRAMME_VON_UMAP ? bildAdressen(roh) : [];
1648
1649    return { quellen: quellen, grund: grund };
1650  }
1651
1652  /* ---------- Original-Piktogramme vorab prüfen ----------
1653     Erst wenn eine Adresse nachweislich geladen wurde, wandert
1654     sie in den Marker. So ist nie ein leerer Tropfen zu sehen. */
1655
1656  function fernLaden(quellen, fertig) {
1657    var liste = (quellen || []).filter(Boolean);
1658    if (!liste.length) { fertig(""); return; }
1659    if (/^data:/i.test(liste[0])) { fertig(liste[0]); return; }
1660    if (!PIKTOGRAMME_VON_UMAP) { fertig(""); return; }
1661
1662    var schluessel = liste[0];
1663    if (FERN_CACHE[schluessel] !== undefined) { fertig(FERN_CACHE[schluessel]); return; }
1664    if (FERN_WARTEN[schluessel]) { FERN_WARTEN[schluessel].push(fertig); return; }
1665    FERN_WARTEN[schluessel] = [fertig];
1666
1667    var i = 0;
1668    function ende(adresse) {
1669      FERN_CACHE[schluessel] = adresse;
1670      (FERN_WARTEN[schluessel] || []).forEach(function (f) {
1671        try { f(adresse); } catch (e) { }
1672      });
1673      delete FERN_WARTEN[schluessel];
1674    }
1675    (function versuch() {
1676      if (i >= liste.length) { ende(""); return; }
1677      var adresse = liste[i++];
1678      var pruef = new Image();
1679      pruef.referrerPolicy = "no-referrer";
1680      pruef.onload  = function () { symbolNotiz(adresse, "geladen"); ende(adresse); };
1681      pruef.onerror = function () { symbolNotiz(adresse, "fehlt"); versuch(); };
1682      pruef.src = adresse;
1683    })();
1684  }
1685
1686  // holt das Original nach und meldet sich, sobald es da ist
1687  function fernNachladen(bild, fertig) {
1688    if (!bild || bild.fern !== undefined) return;
1689    if (!bild.quellen || !bild.quellen.length) return;
1690    bild.fern = undefined;
1691    fernLaden(bild.quellen, function (adresse) {
1692      bild.fern = adresse || "";
1693      if (adresse) { try { fertig(); } catch (e) { } }
1694    });
1695  }
1696
1697  /* ---------- Diagnose der Bildadressen ---------- */
1698
1699  function symbolNotiz(adresse, zustand) {
1700    if (!SYMBOL_BERICHT || !adresse || /^data:/i.test(adresse)) return;
1701    if (SYMBOL_STAND[adresse] === "geladen") return;
1702    var neu = !SYMBOL_STAND[adresse];
1703    SYMBOL_STAND[adresse] = zustand;
1704    if (zustand === "fehlt" && neu) {
1705      console.warn("[Karte] Piktogramm nicht erreichbar: " + adresse);
1706    }
1707    clearTimeout(bilanzZeit);
1708    bilanzZeit = setTimeout(symbolBilanz, 2500);
1709  }
1710
1711  function symbolBilanz() {
1712    var adressen = Object.keys(SYMBOL_STAND);
1713    if (!adressen.length) return;
1714    var zeilen = adressen.map(function (a) {
1715      return { Adresse: a, Zustand: SYMBOL_STAND[a] };
1716    });
1717    var ok = zeilen.filter(function (z) { return z.Zustand === "geladen"; }).length;
1718    console.info("[Karte] Piktogramme von uMap: " + ok + " von " + zeilen.length +
1719      " Adressen geladen" + (ok ? "." :
1720      " – es werden die eingebauten Symbole gezeigt."));
1721    if (console.table) console.table(zeilen); else console.log(zeilen);
1722  }
1723
1724  /* ---------- Symbol als SVG-Bestandteil ----------
1725     Wird in das SVG des Markers bzw. des Filterpunkts
1726     hineingezeichnet: kein eigenes Element, keine Positionierung
1727     über CSS, damit die CMS-Stile nichts verschieben können.   */
1728
1729  function symbolSvg(bild, farbe, groesse, x, y) {
1730    bild = alsBild(bild);
1731    var f = symbolFarbe(farbe);
1732
1733    if (bild && bild.fern) {
1734      return '<image href="' + esc(bild.fern) + '" x="' + x + '" y="' + y + '" ' +
1735        'width="' + groesse + '" height="' + groesse + '" ' +
1736        'preserveAspectRatio="xMidYMid meet" ' +
1737        'style="filter:' + (istDunkelSymbol(farbe) ? "brightness(0)" : "brightness(0) invert(1)") +
1738        '"/>';
1739    }
1740
1741    var name = (bild && bild.grund) || "punkt";
1742    var inhalt = PIKTOGRAMME[name] || PIKTOGRAMME.punkt;
1743    var skala = (groesse / 24).toFixed(4);
1744    return '<g transform="translate(' + x + ',' + y + ') scale(' + skala + ')" ' +
1745      'fill="none" stroke="' + f + '" stroke-width="2" stroke-linecap="round" ' +
1746      'stroke-linejoin="round" style="color:' + f + '">' + inhalt + "</g>";
1747  }
1748
1749  // uMap-Beschreibungen: [[Adresse|Text]], nackte Adressen und
1750  // Zeilenumbrüche in sauberes HTML übersetzen
1751  function verweis(adresse, beschriftungText) {
1752    return '<a href="' + esc(adresse) + '" target="_blank" rel="noopener">' +
1753           esc(beschriftungText) + "</a>";
1754  }
1755  function beschreibungHtml(roh) {
1756    if (!roh) return "";
1757    var merker = [], s = String(roh);
1758
1759    s = s.replace(/\[\[([^\]|]+)\|([^\]]*)\]\]/g, function (_, a, b) {
1760      merker.push(verweis(txt(a), txt(b) || txt(a)));
1761      return "\u0000" + (merker.length - 1) + "\u0000";
1762    });
1763    s = s.replace(/\[\[([^\]]+)\]\]/g, function (_, a) {
1764      merker.push(verweis(txt(a), txt(a)));
1765      return "\u0000" + (merker.length - 1) + "\u0000";
1766    });
1767
1768    s = esc(s);
1769    s = s.replace(/https?:\/\/[^\s<]+/g, function (u) {
1770      return '<a href="' + u + '" target="_blank" rel="noopener">' + u + "</a>";
1771    });
1772    s = s.replace(/\u0000(\d+)\u0000/g, function (_, i) { return merker[+i]; });
1773    return s.replace(/\r?\n/g, "<br>");
1774  }
1775
1776  /* =========================================================
1777     6) MARKER, FILTERPUNKT UND POPUP
1778     ========================================================= */
1779
1780  var PIN_PFAD = "M16 40.6C16 40.6 30.4 25.6 30.4 15.9 30.4 8 24 1.6 16 1.6S1.6 8 1.6 15.9" +
1781                 "C1.6 25.6 16 40.6 16 40.6Z";
1782
1783  var PIN_KLEIN = '<svg viewBox="0 0 24 24" width="12" height="12" fill="none" ' +
1784    'stroke="currentColor" stroke-width="2.2" stroke-linecap="round" ' +
1785    'stroke-linejoin="round" aria-hidden="true">' +
1786    '<path d="M12 21.5S19 14.6 19 9.8A7 7 0 0 0 5 9.8c0 4.8 7 11.7 7 11.7Z"/>' +
1787    '<circle cx="12" cy="9.8" r="2.4"/></svg>';
1788
1789  var KALENDER_KLEIN = '<svg viewBox="0 0 24 24" width="15" height="15" fill="none" ' +
1790    'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
1791    'stroke-linejoin="round" aria-hidden="true">' +
1792    '<path d="M8 2.5v3M16 2.5v3M3.5 9.5h17M5 4.5h14a1.5 1.5 0 0 1 1.5 1.5v13a1.5 1.5 0 0 1' +
1793    '-1.5 1.5H5A1.5 1.5 0 0 1 3.5 19V6A1.5 1.5 0 0 1 5 4.5z"/></svg>';
1794
1795  // Tropfen, Piktogramm und Beschriftung in einem Element.
1796  // Die Beschriftung sitzt unter der Nadelspitze (top:100%).
1797  function pinHtml(farbe, bild, name, immer) {
1798    var f = esc(farbe || "#2f6b4f");
1799    var html = '<span class="bwk-pin">' +
1800      '<svg class="bwk-pin-form" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 42" ' +
1801      'width="32" height="42" aria-hidden="true">' +
1802      '<path d="' + PIN_PFAD + '" fill="' + f + '" stroke="#ffffff" stroke-width="1.5"/>' +
1803      symbolSvg(bild, farbe, 16, 8, 8) +
1804      "</svg>";
1805
1806    if (txt(name)) {
1807      html += '<span class="bwk-pin-name' + (immer ? " bwk-immer" : "") +
1808        '" style="margin-top:' + BESCHRIFTUNG_ABSTAND + 'px">' + esc(txt(name)) + "</span>";
1809    }
1810    return html + "</span>";
1811  }
1812
1813  function pinIcon(farbe, bild, name, immer) {
1814    return L.divIcon({
1815      className: "bwk-pin-huelle",
1816      html: pinHtml(farbe, bild, name, immer),
1817      iconSize: [32, 42],
1818      iconAnchor: [16, 41],
1819      popupAnchor: [0, -37]
1820    });
1821  }
1822
1823  function punktMarker(latlng, farbe, bild, name, immer) {
1824    var marker = L.marker(latlng, {
1825      icon: pinIcon(farbe, bild, name, immer),
1826      riseOnHover: true,
1827      title: txt(name) || undefined
1828    });
1829    // Original-Piktogramm nachreichen, sobald es geprüft ist
1830    fernNachladen(bild, function () {
1831      try { marker.setIcon(pinIcon(farbe, bild, name, immer)); } catch (e) { }
1832    });
1833    return marker;
1834  }
1835
1836  function popupOptionen() {
1837    return {
1838      maxWidth: POPUP_BREITE_MAX,
1839      minWidth: POPUP_BREITE_MIN,
1840      maxHeight: POPUP_HOEHE_MAX,   // Leaflet scrollt den Inhalt selbst
1841      autoPanPadding: [24, 24]
1842    };
1843  }
1844
1845  function swatchHtml(farbe, bild) {
1846    var f = esc(farbe || "#2f6b4f");
1847    return '<span class="bwk-punkt">' +
1848      '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" ' +
1849      'width="22" height="22" aria-hidden="true">' +
1850      '<circle cx="11" cy="11" r="10.4" fill="' + f + '" ' +
1851      'stroke="rgba(0,0,0,.12)" stroke-width="1"/>' +
1852      symbolSvg(bild, farbe, 14, 4, 4) +
1853      "</svg></span>";
1854  }
1855
1856  /* ---------- Termine ---------- */
1857
1858  // "12.09.2026" -> "12. Sep. 2026"
1859  function kurzDatum(s) {
1860    var m = String(s).match(/(\d{1,2})\.(\d{1,2})\.(\d{2,4})/);
1861    if (!m) return txt(s);
1862    var monat = MONATE[parseInt(m[2], 10) - 1] || m[2] + ".";
1863    var jahr = m[3].length === 2 ? "20" + m[3] : m[3];
1864    return m[1].replace(/^0/, "") + ". " + monat + " " + jahr;
1865  }
1866
1867  // ein Termin: Kalendersymbol, Datumszeile, Titel
1868  function terminHtml(t) {
1869    var roh = txt(t.datum);
1870
1871    // Datumsangaben einsammeln und Dubletten entfernen
1872    // (die Liste nennt Beginn und Ende oft mit demselben Tag)
1873    var funde = roh.match(/\d{1,2}\.\d{1,2}\.\d{2,4}/g) || [];
1874    var tage = [];
1875    funde.forEach(function (f) {
1876      var k = kurzDatum(f);
1877      if (tage.indexOf(k) === -1) tage.push(k);
1878    });
1879
1880    // was ohne die Datumsangaben übrig bleibt
1881    var rest = roh;
1882    funde.forEach(function (f) { rest = rest.split(f).join(" "); });
1883    rest = txt(rest).replace(/^[\s,;:.–-]+/, "").replace(/[\s,;:.–-]+$/, "");
1884
1885    // Uhrzeiten sauber setzen
1886    var zeit = "";
1887    var uhr = rest.match(/\d{1,2}[:.]\d{2}/g);
1888    if (uhr) {
1889      var liste = [];
1890      uhr.forEach(function (z) {
1891        var n = z.replace(".", ":");
1892        if (liste.indexOf(n) === -1) liste.push(n);
1893      });
1894      zeit = liste.slice(0, 2).join(" – ") + " Uhr";
1895    } else if (rest) {
1896      zeit = rest;
1897    }
1898
1899    var datum = tage.length ? tage.slice(0, 2).join(" – ") : roh;
1900
1901    var html = '<li><span class="bwk-termin-icon">' + KALENDER_KLEIN + "</span>";
1902    html += '<span class="bwk-termin-text">';
1903    if (datum || zeit) {
1904      html += '<span class="bwk-termin-datum">' + esc(datum);
1905      if (zeit) html += ' <span class="bwk-termin-zeit">· ' + esc(zeit) + "</span>";
1906      html += "</span>";
1907    }
1908    html += t.link
1909      ? '<a class="bwk-termin-titel" href="' + esc(t.link) + '">' + esc(t.titel) + "</a>"
1910      : '<span class="bwk-termin-titel">' + esc(t.titel) + "</span>";
1911    return html + "</span></li>";
1912  }
1913
1914  function popupInhalt(p, farbe) {
1915    var f = farbe || "#2f6b4f";
1916    var html = '<div class="bwk-pop" style="--bwk-pop-farbe:' + esc(f) +
1917      ";--bwk-pop-text:" + esc(lesbar(f)) +
1918      ";--bwk-pop-linie:" + rgba(f, .45) +
1919      ";--bwk-pop-hell:" + rgba(f, .12) + '">';
1920
1921    // Kopf: Titel, darunter die Adresse
1922    html += '<div class="bwk-pop-balken"></div>';
1923    html += '<div class="bwk-pop-kopf"><p class="bwk-pop-titel">' + esc(p.name) + "</p>";
1924    if (p.adresse) {
1925      html += '<p class="bwk-pop-adresse">' + PIN_KLEIN + "<span>" + esc(p.adresse) + "</span></p>";
1926    }
1927    html += "</div>";
1928
1929    // Körper: Beschreibung und darunter alle Termine
1930    var koerper = "";
1931    if (p.info) koerper += '<div class="bwk-pop-text">' + beschreibungHtml(p.info) + "</div>";
1932
1933    if (p.termine && p.termine.length) {
1934      koerper += '<span class="bwk-pop-marke">' +
1935        (p.termine.length === 1 ? "Termin" : p.termine.length + " Termine") + "</span>";
1936      koerper += '<ul class="bwk-pop-liste">';
1937      p.termine.forEach(function (t) { koerper += terminHtml(t); });
1938      koerper += "</ul>";
1939    }
1940
1941    if (koerper) {
1942      html += '<div class="bwk-pop-trenner"></div>';
1943      html += '<div class="bwk-pop-koerper">' + koerper + "</div>";
1944    } else {
1945      html += '<div style="height:12px"></div>';
1946    }
1947    return html + "</div>";
1948  }
1949
1950  /* =========================================================
1951     7) KARTE UND BEDIENUNG
1952     ========================================================= */
1953
1954  function hinweis(text) {
1955    if (!hinweisFeld || !text) return;
1956    hinweisFeld.textContent = text;
1957    hinweisFeld.classList.add("bwk-sichtbar");
1958    clearTimeout(hinweisZeit);
1959    hinweisZeit = setTimeout(function () {
1960      hinweisFeld.classList.remove("bwk-sichtbar");
1961    }, 1800);
1962  }
1963  function hinweisWeg() {
1964    if (!hinweisFeld) return;
1965    clearTimeout(hinweisZeit);
1966    hinweisFeld.classList.remove("bwk-sichtbar");
1967  }
1968
1969  function bedienung(box) {
1970    // ----- Mausrad -----
1971    if (MAUSRAD === "strg") {
1972      karte.scrollWheelZoom.disable();
1973      var mitTaste = function (e) {
1974        if (e.ctrlKey || e.metaKey) karte.scrollWheelZoom.enable();
1975      };
1976      var ohneTaste = function () { if (!vollbildAn) karte.scrollWheelZoom.disable(); };
1977      document.addEventListener("keydown", mitTaste);
1978      document.addEventListener("keyup", ohneTaste);
1979      window.addEventListener("blur", ohneTaste);
1980      box.addEventListener("wheel", function (e) {
1981        if (!vollbildAn && !e.ctrlKey && !e.metaKey) hinweis("Zum Zoomen Strg + Mausrad benutzen");
1982      }, { passive: true });
1983
1984    } else if (MAUSRAD === "klick") {
1985      karte.scrollWheelZoom.disable();
1986      karte.on("click", function () { karte.scrollWheelZoom.enable(); hinweisWeg(); });
1987      karte.on("mouseout", function () { if (!vollbildAn) karte.scrollWheelZoom.disable(); });
1988      box.addEventListener("wheel", function () {
1989        if (!karte.scrollWheelZoom.enabled()) hinweis("Zum Zoomen in die Karte klicken");
1990      }, { passive: true });
1991    }
1992    // "immer": bereits beim Anlegen der Karte eingeschaltet
1993
1994    // ----- Touchgeräte: zwei Finger zum Verschieben -----
1995    if (ZWEI_FINGER_MOBIL && L.Browser.touch && L.Browser.mobile) {
1996      box.classList.add("bwk-zweifinger");
1997      karte.dragging.disable();
1998
1999      box.addEventListener("touchstart", function (e) {
2000        if (vollbildAn) return;
2001        if (e.touches.length > 1) { karte.dragging.enable(); hinweisWeg(); }
2002      }, { passive: true });
2003
2004      box.addEventListener("touchmove", function (e) {
2005        if (vollbildAn) return;
2006        if (e.touches.length === 1 && !karte.dragging.enabled()) {
2007          hinweis("Zum Verschieben zwei Finger benutzen");
2008        }
2009      }, { passive: true });
2010
2011      box.addEventListener("touchend", function (e) {
2012        if (vollbildAn) return;
2013        if (!e.touches.length) karte.dragging.disable();
2014      }, { passive: true });
2015    }
2016  }
2017
2018  /* ---------- Schaltflächen in der Karte ---------- */
2019
2020  function knopfControl(position, klasse, titel, inhalt, aktion) {
2021    var Knopf = L.Control.extend({
2022      options: { position: position },
2023      onAdd: function () {
2024        var box = L.DomUtil.create("div", "leaflet-bar bwk-knopf " + klasse);
2025        var a = L.DomUtil.create("a", "", box);
2026        a.href = "#";
2027        a.title = titel;
2028        a.setAttribute("role", "button");
2029        a.setAttribute("aria-label", titel);
2030        a.innerHTML = inhalt;
2031        this._knopf = a;
2032        L.DomEvent.disableClickPropagation(box);
2033        L.DomEvent.on(a, "click", function (e) {
2034          L.DomEvent.preventDefault(e);
2035          L.DomEvent.stopPropagation(e);
2036          aktion(a);
2037        });
2038        return box;
2039      }
2040    });
2041    return new Knopf();
2042  }
2043
2044  function svgKnopf(pfade) {
2045    return '<svg viewBox="0 0 24 24" width="18" height="18" fill="none" ' +
2046      'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
2047      'stroke-linejoin="round" aria-hidden="true">' + pfade + "</svg>";
2048  }
2049  var SVG_AUFZIEHEN = svgKnopf('<path d="M8 3H3v5M16 3h5v5M21 16v5h-5M3 16v5h5"/>');
2050  var SVG_ZUZIEHEN  = svgKnopf('<path d="M8 3v5H3M16 3v5h5M16 21v-5h5M8 21v-5H3"/>');
2051  var SVG_EBENEN    = svgKnopf('<path d="m12 3 9 5-9 5-9-5 9-5Z"/><path d="m3 13 9 5 9-5"/>');
2052  function pfeilSvg() {
2053    return '<svg viewBox="0 0 20 20" width="16" height="16" fill="none" ' +
2054      'stroke="currentColor" stroke-width="2" stroke-linecap="round" ' +
2055      'stroke-linejoin="round" aria-hidden="true"><path d="M5 7.5 10 12.5 15 7.5"/></svg>';
2056  }
2057
2058  /* ---------- Vollbild ---------- */
2059
2060  function vollbildAnfordern(el) {
2061    var f = el.requestFullscreen || el.webkitRequestFullscreen ||
2062            el.msRequestFullscreen || el.mozRequestFullScreen;
2063    if (!f) return Promise.reject(new Error("kein Vollbild"));
2064    try {
2065      var p = f.call(el);
2066      return (p && p.then) ? p : Promise.resolve();
2067    } catch (e) { return Promise.reject(e); }
2068  }
2069  function vollbildBeenden() {
2070    var f = document.exitFullscreen || document.webkitExitFullscreen ||
2071            document.msExitFullscreen || document.mozCancelFullScreen;
2072    if (!f) return;
2073    try { f.call(document); } catch (e) { }
2074  }
2075  function nativVollbild() {
2076    var e = document.fullscreenElement || document.webkitFullscreenElement ||
2077            document.msFullscreenElement || document.mozFullScreenElement;
2078    return !!e && (e === kartenbox || (kartenbox && kartenbox.contains(e)));
2079  }
2080
2081  function knopfStand() {
2082    if (!vollbildKnopf) return;
2083    vollbildKnopf.innerHTML = vollbildAn ? SVG_ZUZIEHEN : SVG_AUFZIEHEN;
2084    var titel = vollbildAn ? "Vollbild beenden" : "Vollbild";
2085    vollbildKnopf.title = titel;
2086    vollbildKnopf.setAttribute("aria-label", titel);
2087    var box = vollbildKnopf.parentNode;
2088    if (box && box.classList) box.classList.toggle("bwk-aktiv", vollbildAn);
2089  }
2090
2091  function groesseAuffrischen() {
2092    [0, 80, 300, 700].forEach(function (ms) {
2093      setTimeout(function () { if (karte) karte.invalidateSize(); }, ms);
2094    });
2095  }
2096
2097  function vollbildEin() {
2098    if (vollbildAn || !kartenbox) return;
2099    vollbildWechsel = true;
2100    vollbildAn = true;
2101    vollbildErsatz = false;
2102
2103    // Karte aus dem CMS-Gerüst lösen: transform/overflow der
2104    // Elternelemente würden position:fixed sonst brechen
2105    kartenHeimat = kartenbox.parentNode;
2106    kartenAnker = kartenbox.nextSibling;
2107    document.body.appendChild(kartenbox);
2108    document.documentElement.classList.add("bwk-vollbild-aktiv");
2109    kartenbox.classList.add("bwk-vollbild");
2110
2111    if (menuBox) {
2112      menuBox.classList.remove("bwk-zu");
2113      kartenbox.insertBefore(menuBox, kartenbox.firstChild);
2114      if (VOLLBILD_GRUPPEN_ZU) alleGruppen.forEach(function (gr) { gruppeKlappen(gr, true); });
2115    }
2116
2117    if (karte) {
2118      karte.scrollWheelZoom.enable();
2119      karte.dragging.enable();
2120    }
2121    var kartenFeld = document.getElementById("bwk-karte");
2122    if (kartenFeld) kartenFeld.classList.remove("bwk-zweifinger");
2123
2124    vollbildAnfordern(kartenbox).catch(function () { vollbildErsatz = true; });
2125
2126    knopfStand();
2127    groesseAuffrischen();
2128    setTimeout(function () { vollbildWechsel = false; }, 300);
2129  }
2130
2131  function vollbildAus() {
2132    if (!vollbildAn || !kartenbox) return;
2133    vollbildWechsel = true;
2134    vollbildAn = false;
2135
2136    if (nativVollbild()) vollbildBeenden();
2137    vollbildErsatz = false;
2138
2139    if (menuBox && menuHeimat) menuHeimat.insertBefore(menuBox, menuAnker);
2140    kartenbox.classList.remove("bwk-vollbild");
2141    document.documentElement.classList.remove("bwk-vollbild-aktiv");
2142    if (kartenHeimat) kartenHeimat.insertBefore(kartenbox, kartenAnker);
2143
2144    if (karte) {
2145      if (MAUSRAD !== "immer") karte.scrollWheelZoom.disable();
2146      if (ZWEI_FINGER_MOBIL && L.Browser.touch && L.Browser.mobile) {
2147        karte.dragging.disable();
2148        var kartenFeld = document.getElementById("bwk-karte");
2149        if (kartenFeld) kartenFeld.classList.add("bwk-zweifinger");
2150      }
2151    }
2152
2153    knopfStand();
2154    groesseAuffrischen();
2155    setTimeout(function () { vollbildWechsel = false; }, 300);
2156  }
2157
2158  function vollbildSchalten() {
2159    if (vollbildAn) vollbildAus(); else vollbildEin();
2160  }
2161
2162  function vollbildBeobachten() {
2163    var pruefe = function () {
2164      if (vollbildWechsel) return;
2165      if (vollbildAn && !vollbildErsatz && !nativVollbild()) vollbildAus();
2166    };
2167    ["fullscreenchange", "webkitfullscreenchange", "msfullscreenchange",
2168     "mozfullscreenchange"].forEach(function (n) {
2169      document.addEventListener(n, pruefe);
2170    });
2171    document.addEventListener("keydown", function (e) {
2172      if (!vollbildAn) return;
2173      if (e.key === "Escape" || e.key === "Esc") {
2174        if (!nativVollbild()) { e.preventDefault(); vollbildAus(); }
2175      }
2176    });
2177  }
2178
2179  /* ---------- Start ---------- */
2180
2181  function start() {
2182    if (typeof L === "undefined") { setTimeout(start, 100); return; }
2183    if (karte) return;
2184
2185    statusFeld  = document.getElementById("bwk-status");
2186    hinweisFeld = document.getElementById("bwk-hinweis");
2187    kartenbox   = document.getElementById("bwk-kartenbox");
2188    var box = document.getElementById("bwk-karte");
2189
2190    if (statusFeld) statusFeld.textContent = TERMIN_HINWEIS;
2191
2192    karte = L.map("bwk-karte", {
2193      scrollWheelZoom: MAUSRAD === "immer",
2194      zoomControl: false
2195    }).setView([START.lat, START.lng], START.zoom);
2196
2197    L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
2198      maxZoom: 19,
2199      attribution: '&copy; <a class="extlink" href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
2200    }).addTo(karte);
2201
2202    L.control.zoom({ position: "topright", zoomInTitle: "Größer", zoomOutTitle: "Kleiner" })
2203      .addTo(karte);
2204
2205    sicher("Vollbild", function () {
2206      if (!VOLLBILD_KNOPF) return;
2207      var c = knopfControl("topright", "bwk-vollbildknopf", "Vollbild",
2208        SVG_AUFZIEHEN, function (a) { vollbildKnopf = a; vollbildSchalten(); });
2209      c.addTo(karte);
2210      vollbildKnopf = c._knopf;
2211      knopfStand();
2212
2213      knopfControl("topleft", "bwk-ebenenknopf", FILTER_TITEL + " ein- oder ausblenden",
2214        SVG_EBENEN, function () {
2215          if (menuBox) menuBox.classList.toggle("bwk-zu");
2216        }).addTo(karte);
2217
2218      vollbildBeobachten();
2219    });
2220
2221    sicher("Bedienung", function () { bedienung(box); });
2222
2223    karte.on("popupclose", function () {
2224      if (wartendeZeichnung) { var f = wartendeZeichnung; wartendeZeichnung = null; f(); }
2225    });
2226
2227    sicher("Menü", baueMenu);
2228    sicher("Terminfilter", baueTerminFilterDialog);
2229    sicher("Ebenen", function () {
2230      EBENEN.forEach(function (e) {
2231        ebeneAufbauen(e);
2232        if (e.punkte && e.punkte.length) setzePunkte(e, e.punkte);
2233      });
2234    });
2235    sicher("Kulturdaten", ladeKultur);
2236    sicher("Veranstaltungen", starteTermine);
2237    sicher("Gemeindegrenzen", ladeGemeindeGrenzen);
2238
2239    var n = 0, iv = setInterval(function () {
2240      karte.invalidateSize(); if (++n > 10) clearInterval(iv);
2241    }, 500);
2242    if (window.ResizeObserver) {
2243      new ResizeObserver(function () { karte.invalidateSize(); }).observe(box);
2244    }
2245  }
2246
2247  function ebeneAufbauen(e) {
2248    if (layerVon[e.id]) return;
2249    layerVon[e.id] = L.layerGroup();
2250    if (e.aktiv) layerVon[e.id].addTo(karte);
2251  }
2252
2253  function setzePunkte(e, punkte) {
2254    if (karte && karte._popup && e._gezeichnet) {
2255      wartendeZeichnung = function () { setzePunkte(e, punkte); };
2256      return;
2257    }
2258    e.punkte = punkte || [];
2259    zeichneEbeneMarker(e);
2260  }
2261
2262  // zeichnet e.punkte neu, unter Berücksichtigung des aktuellen
2263  // Gemeinde-Filters, und zählt dabei mit, wie viele Punkte
2264  // (bzw. bei Veranstaltungen: Termine) auf welche Gemeinde entfallen
2265  function zeichneEbeneMarker(e) {
2266    var layer = layerVon[e.id];
2267    if (!layer) return;
2268    layer.clearLayers();
2269
2270    var gemeindeAnzahl = {};
2271    var sichtbare = [];
2272    (e.punkte || []).forEach(function (p) {
2273      // Zeitraum-Filter: nur bei Punkten mit Terminen (Veranstaltungen),
2274      // andere Ebenen über setzePunkte sind davon nicht betroffen
2275      if (p.termine && !TERMIN_FILTER.alle) {
2276        var gefiltert = p.termine.filter(terminPasstInFilter);
2277        if (!gefiltert.length) return;
2278        var kopie = {};
2279        for (var k in p) if (p.hasOwnProperty(k)) kopie[k] = p[k];
2280        kopie.termine = gefiltert;
2281        p = kopie;
2282      }
2283      if (p.gemeinde) {
2284        gemeindeAnzahl[p.gemeinde] = (gemeindeAnzahl[p.gemeinde] || 0) +
2285          (p.termine ? p.termine.length : 1);
2286      }
2287      if (gemeindeSichtbar(p.gemeinde)) sichtbare.push(p);
2288    });
2289
2290    sichtbare.forEach(function (p) {
2291      var farbe = p.farbe || e.farbe;
2292      var marker = punktMarker([p.lat, p.lng], farbe, p.bild || e.bild,
2293                               p.name, BESCHRIFTUNG_IMMER);
2294      marker.bindPopup(popupInhalt(p, farbe), popupOptionen());
2295      layer.addLayer(marker);
2296    });
2297
2298    e._gezeichnet = true;
2299    e._gemeindeAnzahl = gemeindeAnzahl;
2300    zaehlerSetzen(e, sichtbare.length);
2301    gemeindeZaehlerAktualisieren();
2302  }
2303
2304  function zaehlerSetzen(e, anzahl) {
2305    if (e._anzahlFeld) e._anzahlFeld.textContent = anzahl ? anzahl : "";
2306  }
2307
2308  /* =========================================================
2309     8) FILTER (KATEGORIEN)
2310     ========================================================= */
2311
2312  function baueMenu() {
2313    menuBox = document.getElementById("bwk-menu");
2314    menuHeimat = menuBox.parentNode;
2315    menuAnker = menuBox.nextSibling;
2316
2317    menuBox.innerHTML = "";
2318
2319    baueGemeindeFilter(menuBox);
2320
2321    var kopf = document.createElement("div");
2322    kopf.className = "bwk-kopfzeile";
2323
2324    var titel = document.createElement("p");
2325    titel.className = "bwk-ueberschrift";
2326    titel.textContent = FILTER_TITEL;
2327
2328    alleKnopf = document.createElement("button");
2329    alleKnopf.type = "button";
2330    alleKnopf.className = "bwk-alle";
2331    alleKnopf.textContent = START_ALLE_AUS ? "Alle anzeigen" : "Alle ausblenden";
2332    alleKnopf.addEventListener("click", alleSchalten);
2333
2334    var zu = document.createElement("button");
2335    zu.type = "button";
2336    zu.className = "bwk-menu-zu";
2337    zu.title = FILTER_TITEL + " ausblenden";
2338    zu.setAttribute("aria-label", FILTER_TITEL + " ausblenden");
2339    zu.innerHTML = "&times;";
2340    zu.addEventListener("click", function () { menuBox.classList.add("bwk-zu"); });
2341
2342    kopf.appendChild(titel);
2343    kopf.appendChild(alleKnopf);
2344    kopf.appendChild(zu);
2345    menuBox.appendChild(kopf);
2346
2347    menuInhalt = document.createElement("div");
2348    menuInhalt.className = "bwk-inhalt";
2349    menuBox.appendChild(menuInhalt);
2350
2351    listeKultur = document.createElement("div");
2352    listeKultur.style.display = "contents";
2353    menuInhalt.appendChild(listeKultur);
2354
2355    gruppeFest = neueGruppe("Termine", null);
2356    EBENEN.forEach(function (e) { menuZeile(e, gruppeFest); });
2357  }
2358
2359  // "Alle anzeigen" / "Alle ausblenden"
2360  function alleSchalten() {
2361    var an = EBENEN.some(function (e) { return e.aktiv; });
2362    EBENEN.forEach(function (e) {
2363      if (e._cb) e._cb.checked = !an;
2364      schalte(e, !an);
2365    });
2366    alleGruppen.forEach(gruppeStand);
2367    alleStand();
2368  }
2369  function alleStand() {
2370    if (!alleKnopf) return;
2371    var an = EBENEN.some(function (e) { return e.aktiv; });
2372    alleKnopf.textContent = an ? "Alle ausblenden" : "Alle anzeigen";
2373  }
2374
2375  function gruppeKlappen(gr, zu) {
2376    if (!gr || !gr.box) return;
2377    if (zu) gr.box.classList.add("bwk-zugeklappt");
2378    else gr.box.classList.remove("bwk-zugeklappt");
2379    if (gr.auf) gr.auf.setAttribute("aria-expanded", zu ? "false" : "true");
2380  }
2381
2382  function neueGruppe(name, behaelter) {
2383    var box = document.createElement("div");
2384    box.className = "bwk-gruppe";
2385
2386    var beschr = txt(name) || "Karte";
2387    var nummer = ++gruppenZaehler;
2388
2389    var kopf = document.createElement("div");
2390    kopf.className = "bwk-gruppen-kopf";
2391
2392    var cb = document.createElement("input");
2393    cb.type = "checkbox";
2394    cb.id = "bwk-gr-" + nummer;
2395    cb.checked = !START_ALLE_AUS;
2396
2397    var lbl = document.createElement("label");
2398    lbl.htmlFor = cb.id;
2399    lbl.textContent = beschr;
2400
2401    var auf = document.createElement("button");
2402    auf.type = "button";
2403    auf.className = "bwk-auf";
2404    auf.title = "Auf- oder zuklappen";
2405    auf.setAttribute("aria-label", "Auf- oder zuklappen");
2406    auf.setAttribute("aria-expanded", "true");
2407    auf.innerHTML = pfeilSvg();
2408
2409    kopf.appendChild(cb);
2410    kopf.appendChild(lbl);
2411    kopf.appendChild(auf);
2412    box.appendChild(kopf);
2413
2414    var liste = document.createElement("div");
2415    liste.className = "bwk-gruppen-liste";
2416    liste.id = "bwk-liste-" + nummer;
2417    auf.setAttribute("aria-controls", liste.id);
2418    box.appendChild(liste);
2419
2420    (behaelter || menuInhalt).appendChild(box);
2421
2422    var gr = { box: box, liste: liste, cb: cb, auf: auf, ebenen: [] };
2423    alleGruppen.push(gr);
2424
2425    cb.addEventListener("change", function () {
2426      cb.indeterminate = false;
2427      gr.ebenen.forEach(function (e) {
2428        if (e._cb) e._cb.checked = cb.checked;
2429        schalte(e, cb.checked);
2430      });
2431      alleStand();
2432    });
2433
2434    auf.addEventListener("click", function () {
2435      gruppeKlappen(gr, !box.classList.contains("bwk-zugeklappt"));
2436    });
2437
2438    return gr;
2439  }
2440
2441  function gruppeStand(gr) {
2442    if (!gr || !gr.cb || !gr.ebenen.length) return;
2443    var an = 0;
2444    gr.ebenen.forEach(function (e) { if (e.aktiv) an++; });
2445    gr.cb.checked = an > 0;
2446    gr.cb.indeterminate = an > 0 && an < gr.ebenen.length;
2447  }
2448
2449  function gruppeEntfernen(gr) {
2450    if (!gr) return;
2451    gr.ebenen.slice().forEach(ebeneEntfernen);
2452    if (gr.box && gr.box.parentNode) gr.box.parentNode.removeChild(gr.box);
2453    var i = kulturGruppen.indexOf(gr);
2454    if (i > -1) kulturGruppen.splice(i, 1);
2455    var j = alleGruppen.indexOf(gr);
2456    if (j > -1) alleGruppen.splice(j, 1);
2457  }
2458
2459  // eine Ebene als Kästchen
2460  function menuZeile(e, gruppe) {
2461    var farbe = e.farbe || "#2f6b4f";
2462
2463    var zeile = document.createElement("label");
2464    zeile.className = "bwk-zeile " + (e.aktiv ? "bwk-an" : "bwk-aus");
2465
2466    var cb = document.createElement("input");
2467    cb.type = "checkbox";
2468    cb.className = "bwk-haken";
2469    cb.checked = !!e.aktiv;
2470
2471    var swatch = document.createElement("span");
2472    swatch.className = "bwk-swatch";
2473    swatch.innerHTML = swatchHtml(farbe, e.bild);
2474
2475    var name = document.createElement("span");
2476    name.className = "bwk-name";
2477    name.textContent = e.name;
2478
2479    var anzahl = document.createElement("span");
2480    anzahl.className = "bwk-anzahl";
2481    anzahl.textContent = e.punkte && e.punkte.length ? e.punkte.length : "";
2482
2483    zeile.appendChild(cb);
2484    zeile.appendChild(swatch);
2485    zeile.appendChild(name);
2486    zeile.appendChild(anzahl);
2487    gruppe.liste.appendChild(zeile);
2488    gruppe.ebenen.push(e);
2489
2490    e._zeile = zeile; e._cb = cb; e._anzahlFeld = anzahl;
2491    e._swatch = swatch; e._gruppe = gruppe;
2492
2493    // Original-Piktogramm auch im Filterpunkt nachreichen
2494    fernNachladen(e.bild, function () {
2495      if (e._swatch) e._swatch.innerHTML = swatchHtml(farbe, e.bild);
2496    });
2497
2498    cb.addEventListener("change", function () {
2499      schalte(e, cb.checked);
2500      gruppeStand(gruppe);
2501      alleStand();
2502    });
2503
2504    gruppeStand(gruppe);
2505    alleStand();
2506  }
2507
2508  function schalte(e, an) {
2509    e.aktiv = an;
2510    if (e._zeile) {
2511      e._zeile.classList.toggle("bwk-an", !!an);
2512      e._zeile.classList.toggle("bwk-aus", !an);
2513    }
2514    var layer = layerVon[e.id];
2515    if (layer) {
2516      if (an) layer.addTo(karte); else karte.removeLayer(layer);
2517    }
2518    gemeindeZaehlerAktualisieren();
2519    if (an && e.id === "va-kalender") zeigeTerminFilter();
2520  }
2521
2522  function ebeneEntfernen(e) {
2523    if (!e) return;
2524    if (layerVon[e.id]) { karte.removeLayer(layerVon[e.id]); delete layerVon[e.id]; }
2525    if (e._zeile && e._zeile.parentNode) e._zeile.parentNode.removeChild(e._zeile);
2526    if (e._gruppe) {
2527      var j = e._gruppe.ebenen.indexOf(e);
2528      if (j > -1) e._gruppe.ebenen.splice(j, 1);
2529    }
2530    var i = EBENEN.indexOf(e);
2531    if (i > -1) EBENEN.splice(i, 1);
2532    var k = kulturEbenen.indexOf(e);
2533    if (k > -1) kulturEbenen.splice(k, 1);
2534  }
2535
2536  /* ---------- Gemeinde-Filter ----------
2537     Eigener, flacher Chip-Filter über den Kategorien. Wirkt wie ein
2538     zusätzliches UND: ein Punkt braucht eine angehakte Kategorie
2539     UND eine angehakte Gemeinde, um zu erscheinen. Punkte ohne
2540     erkennbare Gemeinde werden nie versteckt. ---------- */
2541
2542  function baueGemeindeFilter(behaelter) {
2543    var box = document.createElement("div");
2544    box.className = "bwk-gemeinden";
2545
2546    var kopf = document.createElement("div");
2547    kopf.className = "bwk-kopfzeile";
2548
2549    var titel = document.createElement("p");
2550    titel.className = "bwk-ueberschrift";
2551    titel.textContent = "Gemeinden";
2552
2553    gemeindeAlleKnopf = document.createElement("button");
2554    gemeindeAlleKnopf.type = "button";
2555    gemeindeAlleKnopf.className = "bwk-alle";
2556    gemeindeAlleKnopf.textContent = "Alle abwählen";
2557    gemeindeAlleKnopf.addEventListener("click", gemeindeAlleSchalten);
2558
2559    kopf.appendChild(titel);
2560    kopf.appendChild(gemeindeAlleKnopf);
2561    box.appendChild(kopf);
2562
2563    var liste = document.createElement("div");
2564    liste.className = "bwk-gemeinde-liste";
2565    box.appendChild(liste);
2566
2567    GEMEINDE_ANZEIGE.forEach(function (name) {
2568      GEMEINDE_STAND[name] = true;
2569
2570      var chip = document.createElement("label");
2571      chip.className = "bwk-chip bwk-an";
2572
2573      var cb = document.createElement("input");
2574      cb.type = "checkbox";
2575      cb.className = "bwk-haken";
2576      cb.checked = true;
2577
2578      var beschriftung = document.createElement("span");
2579      beschriftung.textContent = name;
2580
2581      var anzahl = document.createElement("span");
2582      anzahl.className = "bwk-chip-anzahl";
2583
2584      chip.appendChild(cb);
2585      chip.appendChild(beschriftung);
2586      chip.appendChild(anzahl);
2587      liste.appendChild(chip);
2588
2589      GEMEINDE_ZEILEN[name] = { chip: chip, cb: cb, anzahlFeld: anzahl };
2590
2591      cb.addEventListener("change", function () {
2592        GEMEINDE_STAND[name] = cb.checked;
2593        chip.classList.toggle("bwk-an", cb.checked);
2594        chip.classList.toggle("bwk-aus", !cb.checked);
2595        gemeindeAlleStand();
2596        neuZeichnenAlle();
2597        gemeindeKartePassen();
2598      });
2599    });
2600
2601    behaelter.appendChild(box);
2602  }
2603
2604  function gemeindeAlleSchalten() {
2605    var an = GEMEINDE_ANZEIGE.some(function (g) { return GEMEINDE_STAND[g] !== false; });
2606    GEMEINDE_ANZEIGE.forEach(function (g) {
2607      GEMEINDE_STAND[g] = !an;
2608      var z = GEMEINDE_ZEILEN[g];
2609      if (!z) return;
2610      z.cb.checked = !an;
2611      z.chip.classList.toggle("bwk-an", !an);
2612      z.chip.classList.toggle("bwk-aus", an);
2613    });
2614    gemeindeAlleStand();
2615    neuZeichnenAlle();
2616    gemeindeKartePassen();
2617  }
2618
2619  function gemeindeAlleStand() {
2620    if (!gemeindeAlleKnopf) return;
2621    var an = GEMEINDE_ANZEIGE.some(function (g) { return GEMEINDE_STAND[g] !== false; });
2622    gemeindeAlleKnopf.textContent = an ? "Alle abwählen" : "Alle auswählen";
2623  }
2624
2625  // Zähler neben jeder Gemeinde: Summe über alle gerade aktiven
2626  // Ebenen (Kategorien), unabhängig vom Gemeinde-Filter selbst –
2627  // zeigt also "was gäbe es hier", nicht "was ist gerade sichtbar"
2628  function gemeindeZaehlerAktualisieren() {
2629    var summe = {};
2630    EBENEN.forEach(function (e) {
2631      if (!e.aktiv || !e._gemeindeAnzahl) return;
2632      Object.keys(e._gemeindeAnzahl).forEach(function (g) {
2633        summe[g] = (summe[g] || 0) + e._gemeindeAnzahl[g];
2634      });
2635    });
2636    GEMEINDE_ANZEIGE.forEach(function (g) {
2637      var z = GEMEINDE_ZEILEN[g];
2638      if (z && z.anzahlFeld) z.anzahlFeld.textContent = summe[g] || "";
2639    });
2640  }
2641
2642  // alle Ebenen mit dem aktuellen Gemeinde-Filter neu zeichnen
2643  // (nach einem Klick auf einen Gemeinde-Chip)
2644  function neuZeichnenAlle() {
2645    EBENEN.forEach(function (e) {
2646      if (e._roh) setzeGeojson(e, e._roh);
2647      else zeichneEbeneMarker(e);
2648    });
2649  }
2650
2651  /* ---------- Termin-Zeitraum-Dialog ----------
2652     Geht auf, sobald "Veranstaltungen" angehakt wird (siehe
2653     schalte()). "Alle Termine" an = kein Filter. Aus + Von/Bis
2654     gesetzt = nur Termine in diesem Zeitraum werden gezeichnet
2655     (siehe terminPasstInFilter(), verwendet in zeichneEbeneMarker()). ---------- */
2656
2657  var terminFilterElemente = null;
2658
2659  // "12.9.2026 19:00" -> 20260912 (Tag nur aus dem Anfang der
2660  // Zeichenkette, alles danach – Uhrzeit usw. – wird ignoriert)
2661  function terminDatumWert(datumStr) {
2662    var m = txt(datumStr).match(/^(\d{1,2})\.(\d{1,2})\.(\d{2,4})/);
2663    if (!m) return null;
2664    var tag = +m[1], monat = +m[2], jahr = +m[3];
2665    if (jahr < 100) jahr += 2000;
2666    return jahr * 10000 + monat * 100 + tag;
2667  }
2668  // "2026-09-12" (Wert eines <input type="date">) -> 20260912
2669  function eingabeDatumWert(s) {
2670    var t = txt(s).split("-");
2671    if (t.length !== 3) return null;
2672    return (+t[0]) * 10000 + (+t[1]) * 100 + (+t[2]);
2673  }
2674  function terminPasstInFilter(t) {
2675    if (TERMIN_FILTER.alle) return true;
2676    var w = terminDatumWert(t.datum);
2677    if (w === null) return true;   // kein erkennbares Datum: nicht herausfiltern
2678    var von = eingabeDatumWert(TERMIN_FILTER.von);
2679    var bis = eingabeDatumWert(TERMIN_FILTER.bis);
2680    if (von !== null && w < von) return false;
2681    if (bis !== null && w > bis) return false;
2682    return true;
2683  }
2684
2685  function baueTerminFilterDialog() {
2686    var hinter = document.createElement("div");
2687    hinter.id = "bwk-tf-hinter";
2688    hinter.hidden = true;
2689
2690    var box = document.createElement("div");
2691    box.className = "bwk-tf-box";
2692    box.setAttribute("role", "dialog");
2693    box.setAttribute("aria-modal", "true");
2694
2695    var schliessen = document.createElement("button");
2696    schliessen.type = "button";
2697    schliessen.className = "bwk-tf-schliessen";
2698    schliessen.title = "Schließen";
2699    schliessen.setAttribute("aria-label", "Schließen");
2700    schliessen.innerHTML = "&times;";
2701    schliessen.addEventListener("click", function () { hinter.hidden = true; });
2702
2703    var titel = document.createElement("p");
2704    titel.className = "bwk-tf-titel";
2705    titel.textContent = "Welcher Zeitraum?";
2706
2707    var zeile = document.createElement("div");
2708    zeile.className = "bwk-tf-zeile";
2709
2710    var vonLbl = document.createElement("label");
2711    vonLbl.appendChild(document.createTextNode("Von"));
2712    var von = document.createElement("input");
2713    von.type = "date";
2714    vonLbl.appendChild(von);
2715
2716    var bisLbl = document.createElement("label");
2717    bisLbl.appendChild(document.createTextNode("Bis"));
2718    var bis = document.createElement("input");
2719    bis.type = "date";
2720    bisLbl.appendChild(bis);
2721
2722    zeile.appendChild(vonLbl);
2723    zeile.appendChild(bisLbl);
2724
2725    var alleLbl = document.createElement("label");
2726    alleLbl.className = "bwk-tf-haken";
2727    var alle = document.createElement("input");
2728    alle.type = "checkbox";
2729    alle.checked = true;
2730    alleLbl.appendChild(alle);
2731    alleLbl.appendChild(document.createTextNode("Alle Termine anzeigen"));
2732
2733    var knoepfe = document.createElement("div");
2734    knoepfe.className = "bwk-tf-knoepfe";
2735    var anwenden = document.createElement("button");
2736    anwenden.type = "button";
2737    anwenden.className = "bwk-tf-anwenden";
2738    anwenden.textContent = "Filter anwenden";
2739    knoepfe.appendChild(anwenden);
2740
2741    box.appendChild(schliessen);
2742    box.appendChild(titel);
2743    box.appendChild(zeile);
2744    box.appendChild(alleLbl);
2745    box.appendChild(knoepfe);
2746    hinter.appendChild(box);
2747    // An #bwk-kartenbox hängen statt an document.body: im echten
2748    // Vollbildmodus rendert der Browser NUR den fullscreen-Container
2749    // und dessen Nachfahren – alles außerhalb (also auch document.body
2750    // direkt) bleibt unsichtbar, solange Vollbild aktiv ist.
2751    (kartenbox || document.body).appendChild(hinter);
2752
2753    // Die Felder bleiben immer bedienbar (ein "disabled"-Feld lässt
2754    // sich gar nicht erst anklicken – das war der eigentliche Fehler,
2755    // wegen dem der Filter "nie funktioniert" hat). Sobald ein Datum
2756    // gewählt wird, hakt "Alle Termine anzeigen" automatisch ab.
2757    von.addEventListener("change", function () { if (von.value || bis.value) alle.checked = false; });
2758    bis.addEventListener("change", function () { if (von.value || bis.value) alle.checked = false; });
2759    alle.addEventListener("change", function () {
2760      if (alle.checked) { von.value = ""; bis.value = ""; }
2761    });
2762
2763    anwenden.addEventListener("click", function () {
2764      TERMIN_FILTER.alle = alle.checked;
2765      TERMIN_FILTER.von = alle.checked ? "" : von.value;
2766      TERMIN_FILTER.bis = alle.checked ? "" : bis.value;
2767      hinter.hidden = true;
2768      var ziel = findeEbene("va-kalender");
2769      if (ziel) zeichneEbeneMarker(ziel);
2770    });
2771
2772    hinter.addEventListener("click", function (ev) {
2773      if (ev.target === hinter) hinter.hidden = true;
2774    });
2775    document.addEventListener("keydown", function (ev) {
2776      if (!hinter.hidden && (ev.key === "Escape" || ev.key === "Esc")) hinter.hidden = true;
2777    });
2778
2779    terminFilterElemente = { hinter: hinter, von: von, bis: bis, alle: alle };
2780  }
2781
2782  function zeigeTerminFilter() {
2783    if (!terminFilterElemente) return;
2784    var el = terminFilterElemente;
2785    el.von.value = TERMIN_FILTER.von || "";
2786    el.bis.value = TERMIN_FILTER.bis || "";
2787    el.alle.checked = TERMIN_FILTER.alle;
2788    el.hinter.hidden = false;
2789  }
2790
2791  /* =========================================================
2792     9) KULTUREBENEN (nur aus der Datei der Medienverwaltung)
2793     ========================================================= */
2794
2795  function neueKulturebene(name, farbe, bild, aktiv, daten, gruppe) {
2796    var e = { id: "kultur-" + EBENEN.length + "-" + Date.now() + "-" + Math.random().toString(36).slice(2, 
27966),
2797              name: name, farbe: farbe, bild: bild || null,
2798              aktiv: START_ALLE_AUS ? false : (aktiv !== false), punkte: [],
2799              _roh: daten || null };
2800    EBENEN.push(e);
2801    kulturEbenen.push(e);
2802    ebeneAufbauen(e);
2803    menuZeile(e, gruppe);
2804    if (daten) setzeGeojson(e, daten);
2805    return e;
2806  }
2807
2808  function kulturLeeren() {
2809    kulturGruppen.slice().forEach(gruppeEntfernen);
2810    kulturEbenen.slice().forEach(ebeneEntfernen);
2811    kulturGruppen = []; kulturEbenen = [];
2812    farbZaehler = 0;
2813    if (listeKultur) listeKultur.innerHTML = "";
2814    gemeindeZaehlerAktualisieren();
2815  }
2816
2817  function kulturAdresse() {
2818    var id = txt(KULTUR_FILEID);
2819    if (!id) return "";
2820    var adresse = KULTUR_URL_MUSTER.replace("{id}", encodeURIComponent(id));
2821    if (DATEI_FRISCH_LADEN) {
2822      adresse += (adresse.indexOf("?") === -1 ? "?" : "&") + "stand=" + Date.now();
2823    }
2824    return adresse;
2825  }
2826
2827  // Übersicht in der Konsole: welches Symbol und welche Farbe
2828  // bekommt welche Ebene?
2829  function ebenenBericht(daten) {
2830    if (!SYMBOL_BERICHT || !daten) return;
2831    var zeilen = [];
2832    var wurzel = daten.layers || (daten.type === "FeatureCollection" ? [daten] : []);
2833
2834    (function durch(liste, gruppe) {
2835      (liste || []).forEach(function (l, i) {
2836        if (!l) return;
2837        var name = nameAus(l, "Ebene " + (i + 1));
2838        var u = txt(opt(l, "iconUrl", ""));
2839        var farbe = farbeAus(l, "");
2840        if (l.features && l.features.length) {
2841          zeilen.push({
2842            Gruppe: gruppe || "–",
2843            Ebene: name,
2844            iconUrl: u || "(keine)",
2845            Symbol: (u ? symbolAusDatei(u) : "") || symbolAusText(name) || "punkt",
2846            Farbe: farbe || "(Vorgabe)",
2847            Symbolfarbe: farbe ? (istDunkelSymbol(farbe) ? "schwarz" : "weiß") : "weiß",
2848            Punkte: l.features.length
2849          });
2850        }
2851        if (l.layers) durch(l.layers, name);
2852      });
2853    })(wurzel, "");
2854
2855    if (!zeilen.length) {
2856      console.warn("[Karte] Keine Ebene mit Punkten in der Datei gefunden.");
2857      return;
2858    }
2859    console.info("[Karte] Symbole der Ebenen:");
2860    if (console.table) console.table(zeilen); else console.log(zeilen);
2861  }
2862
2863  function ladeKultur() {
2864    var adresse = kulturAdresse();
2865    if (!adresse) {
2866      console.info("[Karte] Keine KULTUR_FILEID gesetzt – es werden nur Veranstaltungen gezeigt.");
2867      return;
2868    }
2869
2870    fetch(adresse, { credentials: "same-origin", cache: "no-store" })
2871      .then(function (r) {
2872        if (!r.ok) throw new Error("HTTP " + r.status);
2873        return r.text();
2874      })
2875      .then(function (text) {
2876        try { return JSON.parse(text); }
2877        catch (e) { throw new Error("Datei ist kein gültiges JSON"); }
2878      })
2879      .then(function (daten) {
2880        if (daten && daten.uri) {
2881          try { UMAP_SERVER = new URL(daten.uri).origin.replace(/^http:/i, "https:"); }
2882          catch (e) { }
2883        }
2884        var anzahl = kulturVerarbeiten(daten);
2885        if (!anzahl) throw new Error("keine verwertbaren Ebenen in der Datei");
2886        console.info("[Karte] Kulturdatei geladen: " + anzahl + " Ebene(n), Symbolserver: " +
2887                     serverListe().join(", "));
2888        sicher("Ebenenbericht", function () { ebenenBericht(daten); });
2889      })
2890      .catch(function (fehler) {
2891        kulturLeeren();
2892        console.warn("[Karte] Kulturdatei (fileid " + KULTUR_FILEID + ") nicht verwendbar: " +
2893                     (fehler.message || fehler) + " – es werden nur Veranstaltungen gezeigt.");
2894      });
2895  }
2896
2897  // zerlegt einen uMap-Export in Gruppen und Ebenen; gibt die Anzahl der Ebenen zurück
2898  function kulturVerarbeiten(daten) {
2899    if (!daten) return 0;
2900
2901    if (daten.type === "FeatureCollection" && !daten.layers) {
2902      if (!daten.features || !daten.features.length) return 0;
2903      var titel = nameAus(daten, "Kulturkarte");
2904      var gr = neueGruppe("Kulturkarte", listeKultur);
2905      kulturGruppen.push(gr);
2906      neueKulturebene(titel, farbeAus(daten, naechsteFarbe()),
2907                      iconInfo(daten, null, titel), true, daten, gr);
2908      return 1;
2909    }
2910
2911    return ebenenListe(daten.layers, null, "");
2912  }
2913
2914  // Farbe einer Gruppe: eigene Farbe, sonst die erste Farbe
2915  // darin, sonst die nächste aus der Palette
2916  function gruppenFarbe(fc) {
2917    var eigen = farbeAus(fc, "");
2918    if (eigen) return eigen;
2919
2920    var gefunden = "";
2921    (function durch(liste) {
2922      (liste || []).forEach(function (l) {
2923        if (gefunden || !l) return;
2924        var c = farbeAus(l, "");
2925        if (c) { gefunden = c; return; }
2926        if (l.layers) durch(l.layers);
2927      });
2928    })(fc.layers);
2929
2930    return gefunden || naechsteFarbe();
2931  }
2932
2933  // Reihenfolge einer Gruppe/Ebene, wie in uMap selbst festgelegt
2934  // (Feld "rank", direkt neben "properties" – opt() findet es über
2935  // den letzten Rückgriff auf das Objekt selbst). Ohne "rank" ganz
2936  // ans Ende.
2937  function rangVon(o) {
2938    var r = opt(o, "rank", null);
2939    return (typeof r === "number") ? r : 999999;
2940  }
2941  function nachRang(liste) {
2942    try {
2943      return liste.slice().sort(function (a, b) { return rangVon(a) - rangVon(b); });
2944    } catch (fehler) {
2945      console.warn("[Karte] Sortierung nach Rang fehlgeschlagen, Reihenfolge aus der Datei wird verwendet:", fehler);
2946      return liste;
2947    }
2948  }
2949
2950  // arbeitet die (auch verschachtelten) uMap-Ebenen ab, in der
2951  // Reihenfolge, in der sie in uMap selbst angeordnet sind.
2952  // "farbe" ist die Farbe der übergeordneten Gruppe.
2953  function ebenenListe(liste, gruppe, farbe) {
2954    if (!liste || !liste.length) return 0;
2955    var anzahl = 0, ohneGruppe = gruppe;
2956    var sortiert = nachRang(liste);
2957
2958    sortiert.forEach(function (fc, i) {
2959      if (!fc) return;
2960      var name = nameAus(fc, "Ebene " + (i + 1));
2961      var istGruppe = !!(fc.layers && fc.layers.length) || opt(fc, "group", false) === true;
2962
2963      if (istGruppe) {
2964        var gfarbe = GRUPPENFARBE ? gruppenFarbe(fc) : "";
2965        var gr = neueGruppe(name, listeKultur);
2966        kulturGruppen.push(gr);
2967        var n = ebenenListe(fc.layers, gr, gfarbe);
2968
2969        if (fc.features && fc.features.length) {
2970          neueKulturebene(name, gfarbe || farbeAus(fc, naechsteFarbe()),
2971                          iconInfo(fc, null, name),
2972                          opt(fc, "displayOnLoad", true) !== false, fc, gr);
2973          n++;
2974        }
2975        if (!n) gruppeEntfernen(gr); else anzahl += n;
2976        return;
2977      }
2978
2979      if (!fc.features || !fc.features.length) return;   // leere Ebenen überspringen
2980
2981      if (!ohneGruppe) {
2982        ohneGruppe = neueGruppe("Karte", listeKultur);
2983        kulturGruppen.push(ohneGruppe);
2984      }
2985      // Ebenen einer Gruppe tragen normalerweise die Farbe der
2986      // Gruppe – außer eine Ebene hat selbst ausdrücklich eine
2987      // eigene Farbe gesetzt, die hat dann Vorrang.
2988      var eigeneFarbe = farbeAus(fc, "");
2989      var lfarbe = eigeneFarbe || (GRUPPENFARBE && farbe) || naechsteFarbe();
2990      neueKulturebene(name, lfarbe, iconInfo(fc, null, name),
2991                      opt(fc, "displayOnLoad", true) !== false, fc, ohneGruppe);
2992      anzahl++;
2993    });
2994
2995    return anzahl;
2996  }
2997
2998  // fasst doppelte Einträge zusammen (gleicher Name + gleiche Koordinaten)
2999  function entdoppeln(daten) {
3000    if (!daten || !daten.features || !daten.features.length) return daten;
3001    var gesehen = {}, raus = [];
3002
3003    daten.features.forEach(function (f) {
3004      if (!f) return;
3005      var p = f.properties || {}, g = f.geometry || {};
3006      var koord = JSON.stringify(g.coordinates === undefined ? "" : g.coordinates);
3007      var k = normalisiere(p.name || p.title || "") + "|" + (g.type || "") + "|" + koord;
3008
3009      if (gesehen[k]) {
3010        var alt = gesehen[k].properties || {};
3011        var neuText = p.description || p.beschreibung || "";
3012        var altText = alt.description || alt.beschreibung || "";
3013        if (neuText.length > altText.length) {
3014          gesehen[k].properties = gesehen[k].properties || {};
3015          gesehen[k].properties.description = neuText;
3016        }
3017        return;
3018      }
3019      gesehen[k] = f;
3020      raus.push(f);
3021    });
3022
3023    if (raus.length === daten.features.length) return daten;
3024    return { type: "FeatureCollection", features: raus };
3025  }
3026
3027   function istLinie(feature) {
3028    return !!(feature && feature.geometry && /LineString/.test(feature.geometry.type));
3029  }
3030
3031  // welcher der 24 Filter-Gemeinden gehört ein Punkt-Feature an?
3032  // Reihenfolge: 1) echte Gemeindegrenze anhand der Koordinate
3033  // (genau, sobald geladen), 2) Texterkennung in Adresse/Name als
3034  // Rückfallebene. Das Ergebnis wird am Feature zwischengespeichert,
3035  // aber erst NACHDEM die Grenzen einmal geladen sind – sonst würde
3036  // ein früher (per Text geratener) Treffer nie mehr aktualisiert.
3037  function gemeindeFuerFeature(feature) {
3038    if (GRENZEN_GELADEN && feature._bwkGemeinde !== undefined) return feature._bwkGemeinde;
3039
3040    var gem = "";
3041    var geom = feature.geometry;
3042    if (GRENZEN_GELADEN && geom && geom.type === "Point" && geom.coordinates) {
3043      gem = gemeindeAusKoordinaten(geom.coordinates[1], geom.coordinates[0]);
3044    }
3045    if (!gem) {
3046      var p = feature.properties || {};
3047      gem = gemeindeKanonisch(erkenneGemeinde(p.adresse || p.address || "",
3048                                               p.name || p.title || ""));
3049    }
3050    gem = gem || GEMEINDE_AUSSERHALB;   // nie leer: sonst wäre der Punkt "immer sichtbar"
3051    if (GRENZEN_GELADEN) feature._bwkGemeinde = gem;
3052    return gem;
3053  }
3054
3055  // welche der 24 Filter-Gemeinden berührt eine Linie (Route)?
3056  // Anders als bei einem Punkt kann das mehrere sein – eine Route
3057  // ist sichtbar, sobald IRGENDEINE ihrer Gemeinden angehakt ist.
3058  // Geprüft wird jeder Stützpunkt der Linie gegen die echten
3059  // Grenzen; solange die noch nicht geladen sind, greift ersatz-
3060  // weise die Texterkennung in Adresse/Name (liefert dann höchstens
3061  // eine Gemeinde). Wie bei Punkten wird das Ergebnis erst nach dem
3062  // Laden der Grenzen am Feature zwischengespeichert.
3063  function gemeindenFuerLinie(feature) {
3064    if (GRENZEN_GELADEN && feature._bwkGemeinden !== undefined) return feature._bwkGemeinden;
3065
3066    var geom = feature.geometry;
3067    var punkte = [];
3068    if (geom.type === "LineString") punkte = geom.coordinates;
3069    else if (geom.type === "MultiLineString") {
3070      geom.coordinates.forEach(function (teil) { punkte = punkte.concat(teil); });
3071    }
3072
3073    var namen = [];
3074    if (GRENZEN_GELADEN) {
3075      var treffer = {};
3076      punkte.forEach(function (p) {
3077        var g = gemeindeAusKoordinaten(p[1], p[0]);
3078        if (g) treffer[g] = true;
3079      });
3080      namen = Object.keys(treffer);
3081    }
3082    if (!namen.length) {
3083      var p = feature.properties || {};
3084      var text = gemeindeKanonisch(erkenneGemeinde(p.adresse || p.address || "",
3085                                                     p.name || p.title || ""));
3086      if (text) namen = [text];
3087    }
3088    if (!namen.length) namen = [GEMEINDE_AUSSERHALB];
3089
3090    if (GRENZEN_GELADEN) feature._bwkGemeinden = namen;
3091    return namen;
3092  }
3093
3094  function setzeGeojson(e, rohdaten) {
3095    var layer = layerVon[e.id];
3096    if (!layer) return 0;
3097    layer.clearLayers();
3098
3099    var daten = entdoppeln(rohdaten);
3100    var dauerhaft = opt(rohdaten, "showLabel", null) === true || BESCHRIFTUNG_IMMER;
3101    var anzahl = 0;
3102    var hilfen = [];
3103    var gemeindeAnzahl = {};
3104
3105    // bei GRUPPENFARBE zählt allein die Farbe der Ebene
3106    function punktFarbe(feature) {
3107      return GRUPPENFARBE ? e.farbe : farbeAus(feature, e.farbe);
3108    }
3109
3110    try {
3111      var geo = L.geoJSON(daten, {
3112        filter: function (feature) {
3113          if (!feature || !feature.geometry) return true;
3114          var typ = feature.geometry.type;
3115          if (typ === "Point") {
3116            var gem = gemeindeFuerFeature(feature);
3117            gemeindeAnzahl[gem] = (gemeindeAnzahl[gem] || 0) + 1;
3118            return gemeindeSichtbar(gem);
3119          }
3120          if (typ === "LineString" || typ === "MultiLineString") {
3121            return gemeindenFuerLinie(feature).some(gemeindeSichtbar);
3122          }
3123          return true;   // Flächen: derzeit nicht eingeschränkt
3124        },
3125        pointToLayer: function (feature, latlng) {
3126          var p = feature.properties || {};
3127          var name = p.name || p.title || "";
3128          return punktMarker(latlng, punktFarbe(feature),
3129                             iconInfo(feature, e.bild, name || e.name),
3130                             name, dauerhaft);
3131        },
3132        style: function (feature) {
3133          return {
3134            color: punktFarbe(feature),
3135            weight: LINIEN_BREITE,
3136            opacity: 1,
3137            lineCap: "round",
3138            lineJoin: "round",
3139            fillOpacity: .25
3140          };
3141        },
3142        onEachFeature: function (feature, objekt) {
3143          var p = feature.properties || {};
3144          var name = p.name || p.title || "";
3145          var beschreibungRoh = p.description || p.beschreibung || "";
3146          var inhalt = popupInhalt({
3147            name: name || e.name,
3148            adresse: p.adresse || p.address || "",
3149            info: beschreibungRoh
3150          }, punktFarbe(feature));
3151
3152          objekt.bindPopup(inhalt, popupOptionen());
3153
3154          // ----- Linien leichter treffen und beschriften -----
3155          if (istLinie(feature) && objekt.getLatLngs) {
3156            var hilfe = L.polyline(objekt.getLatLngs(), {
3157              color: punktFarbe(feature), opacity: 0, weight: KLICK_BREITE,
3158              lineCap: "round", lineJoin: "round", interactive: true
3159            });
3160            hilfe.bindPopup(inhalt, popupOptionen());
3161            if (txt(name)) {
3162              hilfe.bindTooltip(esc(txt(name)), {
3163                sticky: true, direction: "top", offset: [0, -8],
3164                opacity: 1, className: "bwk-linien-name"
3165              });
3166            }
3167            hilfe.on("mouseover", function () {
3168              try { objekt.setStyle({ weight: LINIEN_BREITE_HOVER }); } catch (er) { }
3169              if (objekt.bringToFront) objekt.bringToFront();
3170            });
3171            hilfe.on("mouseout", function () {
3172              try { objekt.setStyle({ weight: LINIEN_BREITE }); } catch (er) { }
3173            });
3174            hilfen.push(hilfe);
3175          }
3176
3177          anzahl++;
3178        }
3179      });
3180      layer.addLayer(geo);
3181      // die unsichtbaren Streifen zuletzt: sie liegen dann oben
3182      // und fangen den Klick zuverlässig ab
3183      hilfen.forEach(function (h) { layer.addLayer(h); });
3184    } catch (fehler) {
3185      console.warn("[Karte] Ebene \"" + e.name + "\" nicht zeichenbar:", fehler);
3186    }
3187    e._gemeindeAnzahl = gemeindeAnzahl;
3188    zaehlerSetzen(e, anzahl);
3189    gemeindeZaehlerAktualisieren();
3190    return anzahl;
3191  }
3192  
3193  /* =========================================================
3194     10) LISTENSEITE DER VERANSTALTUNGEN
3195     Die Seite zeigt Karten (.bemCard--list) statt einer Tabelle
3196     und blättert über ein Formular (Pager-Feld + Klick auf
3197     "javascript:void(0)"-Links), nicht über die Adresszeile.
3198     Der Code liest darum jedes Mal live nach:
3199       - welches Feld die Seitenzahl trägt (Feldname "pager-…"),
3200       - wohin das Formular schickt (form.action),
3201       - ob es eine nächste Seite gibt (letztes Element der
3202         Paginierung, Attribut "disabled").
3203     Nichts davon ist fest verdrahtet, damit spätere kleine
3204     Änderungen an der Liste (neue Feld-ID, anderer Wortlaut)
3205     die Karte nicht gleich wieder lahmlegen.
3206     ========================================================= */
3207
3208  // Formularfeld einer Karte anhand seiner sichtbaren Beschriftung
3209  // (".sr-only"-Text) auslesen, unabhängig von Klassennamen
3210  function feldWert(karte, label) {
3211    var lis = karte.querySelectorAll(".bemListContainer--contactList li.bemList__item");
3212    for (var i = 0; i < lis.length; i++) {
3213      var sr = lis[i].querySelector(".sr-only");
3214      if (!sr || txt(sr.textContent).toLowerCase() !== label.toLowerCase()) continue;
3215      var wert = lis[i].querySelector(".bemText__value");
3216      if (wert) return txt(wert.textContent);
3217      var link = lis[i].querySelector("a");
3218      if (link) return txt(link.textContent);
3219      return txt(lis[i].textContent).replace(txt(sr.textContent), "").trim();
3220    }
3221    return "";
3222  }
3223
3224  // Koordinaten, die direkt in der Karte stehen (Feld "Entfernung
3225  // (Luftlinie)" trägt data-lat/data-lon). 0/0 heißt: nicht gesetzt.
3226  function koordinatenAusKarte(karte) {
3227    var li = karte.querySelector(".bemDistanceCalculation[data-lat]");
3228    if (!li) return null;
3229    var lat = parseFloat(li.getAttribute("data-lat"));
3230    var lng = parseFloat(li.getAttribute("data-lon"));
3231    if (!lat || !lng) return null;
3232    if (!imBereich(lat, lng)) return null;
3233    return [lat, lng];
3234  }
3235
3236  function absoluteUrl(pfad) {
3237    if (!pfad) return "";
3238    try { return new URL(pfad, location.href).href; } catch (e) { return pfad; }
3239  }
3240
3241  // eine einzelne Veranstaltungskarte auslesen
3242  function leseKarte(karte) {
3243    var titelFeld = karte.querySelector(".bemHeaderContainer .bemHeader--h5");
3244    var titel = titelFeld ? txt(titelFeld.textContent) : "";
3245    if (!titel) return null;
3246
3247    var linkFeld = karte.querySelector(".bemButtonContainer a.bemLink-detail");
3248    var link = linkFeld ? absoluteUrl(linkFeld.getAttribute("href")) : "";
3249
3250    var datumFeld = karte.querySelector(".bemContainer--date");
3251    var datumMatch = datumFeld ? txt(datumFeld.textContent).match(/\d{1,2}\.\d{1,2}\.\d{2,4}/) : null;
3252    var datum = datumMatch ? datumMatch[0] : "";
3253
3254    var zeitFeld = karte.querySelector(".bemContainer--time");
3255    var zeit = zeitFeld ? txt(txt(zeitFeld.textContent).replace(/^Uhrzeit der Veranstaltung/i, "")) : "";
3256
3257    var quelleFeld = karte.querySelector(".card-footer .bemContainer--source");
3258    var ort = quelleFeld ? txt(txt(quelleFeld.textContent).replace(/^Datenquelle/i, "")) : "";
3259
3260    return {
3261      titel: titel,
3262      link: link,
3263      datum: datum,
3264      zeit: zeit,
3265      ort: ort,
3266      adresse: feldWert(karte, "Adresse"),
3267      standort: feldWert(karte, "Standort"),
3268      koordinaten: koordinatenAusKarte(karte)
3269    };
3270  }
3271
3272  function leseKarten(doc) {
3273    var raus = [];
3274    doc.querySelectorAll(".bemCard.bemCard--list").forEach(function (karte) {
3275      var eintrag = leseKarte(karte);
3276      if (eintrag) raus.push(eintrag);
3277    });
3278    return raus;
3279  }
3280
3281  // das Formular finden, das die Seitenzahl trägt – über das
3282  // Pager-Feld selbst, nicht über eine feste Formular-ID
3283  function pagerFormular(doc) {
3284    var pagerFeld = doc.querySelector('input[id^="pager-"]');
3285    return pagerFeld ? pagerFeld.closest("form") : null;
3286  }
3287
3288  // Wert der "nächste Seite"-Schaltfläche (letztes Element der
3289  // Paginierung); null, wenn sie ausgegraut/nicht vorhanden ist
3290  function naechsteSeite(doc) {
3291    var elemente = doc.querySelectorAll(".pagination .page-item");
3292    if (!elemente.length) return null;
3293    var letztes = elemente[elemente.length - 1];
3294    if (letztes.classList.contains("disabled")) return null;
3295    var a = letztes.querySelector("a[data-filterValue]");
3296    return a ? a.getAttribute("data-filterValue") : null;
3297  }
3298
3299  function ladeVeranstaltungsSeite(url, formularDaten) {
3300    var optionen = { credentials: "same-origin" };
3301    if (formularDaten != null) {
3302      optionen.method = "POST";
3303      optionen.headers = { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8" };
3304      optionen.body = formularDaten;
3305    }
3306    return fetch(url, optionen)
3307      .then(function (r) { return r.text(); })
3308      .then(function (html) { return new DOMParser().parseFromString(html, "text/html"); });
3309  }
3310
3311  // lädt Seite 1 und blättert dann über das Formular weiter, bis
3312  // die Paginierung keine nächste Seite mehr anbietet
3313  function ladeAlleSeiten() {
3314    return ladeVeranstaltungsSeite(VA_URL, null).then(function (doc0) {
3315      var alle = leseKarten(doc0);
3316      var form = pagerFormular(doc0);
3317      if (!form) return alle;
3318
3319      var aktionUrl = absoluteUrl(form.getAttribute("action"));
3320      var pagerFeld = form.querySelector('input[id^="pager-"]');
3321      var pagerName = pagerFeld ? pagerFeld.getAttribute("name") : "";
3322
3323      function weiter(wert, uebrig) {
3324        if (wert == null || !pagerName || uebrig <= 0) return Promise.resolve();
3325        var daten = new FormData(form);
3326        daten.set(pagerName, wert);
3327        return ladeVeranstaltungsSeite(aktionUrl, new URLSearchParams(daten).toString())
3328          .then(function (docN) {
3329            var neue = leseKarten(docN);
3330            if (!neue.length) return;
3331            alle = alle.concat(neue);
3332            return weiter(naechsteSeite(docN), uebrig - 1);
3333          });
3334      }
3335
3336      return weiter(naechsteSeite(doc0), VA_MAX_SEITEN).then(function () { return alle; });
3337    }).catch(function (e) {
3338      console.warn("[Karte] Veranstaltungsliste konnte nicht geladen werden:", e);
3339      return [];
3340    });
3341  }
3342
3343  /* =========================================================
3344     11) ORTE BESTIMMEN
3345     Viele Karten liefern die Koordinate schon direkt mit
3346     (koordinatenAusKarte). Fehlt sie, wird wie bisher zuerst
3347     die interne Detailseite (Lageplan-Link), danach eine
3348     Adresssuche über Nominatim versucht.
3349     ========================================================= */
3350
3351  function istIntern(url) { return url && url.indexOf(location.origin) === 0; }
3352
3353  function holeDoc(url) {
3354    return fetch(url, { credentials: "same-origin" })
3355      .then(function (r) { return r.text(); })
3356      .then(function (html) { return new DOMParser().parseFromString(html, "text/html"); });
3357  }
3358
3359  function ausVerzeichnis(schluessel) {
3360    if (schluessel.indexOf("ort:") !== 0) return null;
3361    var k = schluessel.slice(4);
3362    return ORTE[k] || ORTE[k.split("@")[0]] || null;
3363  }
3364
3365  function leseAdresse(doc, ortsname) {
3366    var roh = "";
3367    var karteLink = Array.prototype.find.call(doc.querySelectorAll("a"), function (a) {
3368      return txt(a.textContent).toLowerCase() === "zur karte";
3369    });
3370    if (karteLink && karteLink.parentElement) {
3371      roh = txt(karteLink.parentElement.textContent).replace(/\|?\s*zur\s*Karte\s*$/i, "");
3372    }
3373    if (!roh) {
3374      var m = txt(doc.body.textContent)
3375        .match(/([A-Za-zÄÖÜäöüß.\-/ ]{2,40}\s\d+[a-zA-Z]?,\s*\d{4}\s+[A-Za-zÄÖÜäöüß.\- ]{2,40})/);
3376      if (m) roh = txt(m[1]);
3377    }
3378    if (ortsname && roh.toLowerCase().indexOf(ortsname.toLowerCase()) === 0) {
3379      roh = txt(roh.slice(ortsname.length));
3380    }
3381    return roh.replace(/^[,|\s]+/, "");
3382  }
3383
3384  function koordinatenAusLageplan(doc) {
3385    var link = doc.querySelector('a[href*="digitalmaps.aspx"]');
3386    if (!link) return Promise.resolve(null);
3387    return fetch(link.href, { credentials: "same-origin" })
3388      .then(function (r) { return r.text(); })
3389      .then(function (html) {
3390        var m = html.match(/(4[5-9]\.\d{4,})\D{1,25}?(\d{1,2}\.\d{4,})/);
3391        if (!m) return null;
3392        var lat = parseFloat(m[1]), lng = parseFloat(m[2]);
3393        return imBereich(lat, lng) ? [lat, lng] : null;
3394      })
3395      .catch(function () { return null; });
3396  }
3397
3398  function koordinatenAusAdresse(begriff) {
3399    if (!begriff) return Promise.resolve(null);
3400    var url = "https://nominatim.openstreetmap.org/search?format=json&addressdetails=1&limit=1" +
3401              "&countrycodes=at,de&q=" + encodeURIComponent(begriff);
3402    return fetch(url, { headers: { "Accept": "application/json" } })
3403      .then(function (r) { return r.json(); })
3404      .then(function (j) {
3405        if (!j || !j.length) return null;
3406        var t = j[0];
3407        var lat = parseFloat(t.lat), lng = parseFloat(t.lon);
3408        if (!imBereich(lat, lng)) return null;
3409        if (NUR_GENAUE_ORTE) {
3410          var grob = (t.class === "place" || t.class === "boundary") &&
3411                     !(t.address && t.address.house_number);
3412          if (grob) return null;
3413        }
3414        return [lat, lng];
3415      })
3416      .catch(function () { return null; });
3417  }
3418
3419  function ausDetailseite(g) {
3420    if (!g.detailLink) return Promise.resolve(false);
3421    return holeDoc(g.detailLink).then(function (doc) {
3422      if (!g.adresse) g.adresse = leseAdresse(doc, g.viaLink ? "" : g.name);
3423      if (g.adresse && !g.gemeinde) g.gemeinde = erkenneGemeinde(g.adresse);
3424      return koordinatenAusLageplan(doc);
3425    }).then(function (koord) {
3426      if (!koord) return false;
3427      g.ort = { name: g.name, adresse: g.adresse || "",
3428                lat: +koord[0].toFixed(6), lng: +koord[1].toFixed(6) };
3429      return true;
3430    }).catch(function () { return false; });
3431  }
3432
3433  function ausAdresssuche(g) {
3434    var begriffe = [];
3435    if (g.adresse) begriffe.push(g.adresse + ", Österreich");
3436    if (g.name) begriffe.push(g.name + (g.gemeinde ? ", " + g.gemeinde : ", Bregenzerwald") + ", Vorarlberg");
3437    if (!begriffe.length) return Promise.resolve(false);
3438
3439    function versuch(i) {
3440      if (i >= begriffe.length) return Promise.resolve(false);
3441      return schlafe(PAUSE_ADRESSSUCHE)
3442        .then(function () { return koordinatenAusAdresse(begriffe[i]); })
3443        .then(function (koord) {
3444          if (!koord) return versuch(i + 1);
3445          g.ort = { name: g.name, adresse: g.adresse || "",
3446                    lat: +koord[0].toFixed(6), lng: +koord[1].toFixed(6) };
3447          return true;
3448        });
3449    }
3450    return versuch(0);
3451  }
3452
3453  /* =========================================================
3454     12) ABLAUF DER VERANSTALTUNGEN
3455     Jede Karte ist bereits ein einzelner Termin (eigenes Datum,
3456     eigene Uhrzeit). Termine am selben Ort werden hier zu einem
3457     Kartenpunkt mit mehreren Terminen zusammengefasst.
3458     ========================================================= */
3459
3460  function starteTermine() {
3461    var ziel = findeEbene("va-kalender");
3462    if (!ziel) return;
3463
3464    var gespeichert = speicherLesen(CACHE_TERMINE);
3465    var frisch = gespeichert && gespeichert.zeit &&
3466                 (Date.now() - gespeichert.zeit) < CACHE_STUNDEN * 3600000;
3467
3468    if (gespeichert && gespeichert.punkte && gespeichert.punkte.length) {
3469      setzePunkte(ziel, gespeichert.punkte);
3470      if (frisch) return;
3471      var gleich = function () { aktualisiere(ziel); };
3472      if (window.requestIdleCallback) requestIdleCallback(gleich, { timeout: 4000 });
3473      else setTimeout(gleich, 1000);
3474    } else {
3475      aktualisiere(ziel);
3476    }
3477  }
3478
3479  // eindeutiger Schlüssel für den physischen Ort eines Termins:
3480  // Standort/Adresse (+ Gemeinde), sonst als letzter Rückgriff
3481  // die Gemeinde allein
3482  function veranstaltungsSchluessel(e) {
3483    var basis = e.standort || e.adresse || e.ort || e.titel;
3484    var gem = e.ort || erkenneGemeinde(e.adresse, e.standort, e.titel);
3485    return "ort:" + normalisiere(basis) + (gem ? "@" + normalisiere(gem) : "");
3486  }
3487
3488  // eine der 24 Filter-Gemeinden für einen Veranstaltungseintrag:
3489  // zuerst die "Datenquelle" der Karte (exakt und zuverlässig),
3490  // dann die echte Gemeindegrenze anhand der Koordinate (falls schon
3491  // geladen und die Karte eine Koordinate mitliefert), zuletzt wie
3492  // gehabt über Adresse/Standort/Titel geraten
3493  function gemeindeFuerEintrag(e) {
3494    var exakt = gemeindeVonName(e.ort);
3495    if (exakt) return exakt;
3496    if (GRENZEN_GELADEN && e.koordinaten) {
3497      var perKoordinate = gemeindeAusKoordinaten(e.koordinaten[0], e.koordinaten[1]);
3498      if (perKoordinate) return perKoordinate;
3499    }
3500    var perText = gemeindeKanonisch(erkenneGemeinde(e.adresse, e.standort, e.titel, e.ort));
3501    return perText || GEMEINDE_AUSSERHALB;   // nie leer: sonst "immer sichtbar"
3502  }
3503
3504  function aktualisiere(ziel) {
3505    var ortsCache = speicherLesen(CACHE_ORTE) || {};
3506
3507    ladeAlleSeiten().then(function (eintraege) {
3508      var gruppen = {}, reihenfolge = [];
3509
3510      eintraege.forEach(function (e) {
3511        var k = veranstaltungsSchluessel(e);
3512        if (!gruppen[k]) {
3513          gruppen[k] = {
3514            name: e.standort || e.ort || e.titel,
3515            viaLink: !e.standort,
3516            gemeinde: gemeindeFuerEintrag(e),
3517            detailLink: istIntern(e.link) ? e.link : "",
3518            adresse: e.adresse || "", ort: null, termine: []
3519          };
3520          reihenfolge.push(k);
3521        }
3522        var g = gruppen[k];
3523        if (!g.detailLink && istIntern(e.link)) g.detailLink = e.link;
3524        if (!g.adresse && e.adresse) g.adresse = e.adresse;
3525        if (!g.gemeinde) g.gemeinde = gemeindeFuerEintrag(e);
3526        if (!g.ort && e.koordinaten) {
3527          g.ort = { name: g.name, adresse: g.adresse || "",
3528                    lat: e.koordinaten[0], lng: e.koordinaten[1] };
3529        }
3530        var terminDatum = e.datum + (e.zeit ? " " + e.zeit : "");
3531        var schon = g.termine.some(function (t) { return t.titel === e.titel && t.datum === terminDatum; });
3532        if (!schon) g.termine.push({ titel: e.titel, datum: terminDatum, link: e.link });
3533      });
3534
3535      var offeneDetail = [], jetzt = Date.now();
3536      reihenfolge.forEach(function (k) {
3537        var g = gruppen[k];
3538        if (g.ort) return;   // Koordinate stand schon in der Liste
3539        var fest = ausVerzeichnis(k);
3540        if (fest) { g.ort = fest; return; }
3541        var bekannt = ortsCache[k];
3542        if (bekannt && typeof bekannt.lat === "number" &&
3543            (jetzt - bekannt.zeit) < ORT_TAGE * 86400000) { g.ort = bekannt; return; }
3544        if (bekannt && typeof bekannt.lat !== "number" &&
3545            (jetzt - bekannt.zeit) < FEHLVERSUCH_TAGE * 86400000) { return; }
3546        offeneDetail.push(k);
3547      });
3548
3549      zeichne(ziel, reihenfolge, gruppen);
3550
3551      return gruppenweise(offeneDetail, DETAIL_PARALLEL, function (k) {
3552        return ausDetailseite(gruppen[k]).then(function (ok) {
3553          if (ok) merke(ortsCache, k, gruppen[k]);
3554        });
3555      }).then(function () {
3556        zeichne(ziel, reihenfolge, gruppen);
3557        speicherSchreiben(CACHE_ORTE, ortsCache);
3558
3559        var rest = offeneDetail.filter(function (k) { return !gruppen[k].ort; })
3560                               .slice(0, NEUE_ORTE_PRO_MAL);
3561        return naechster(rest);
3562
3563        function naechster(liste) {
3564          if (!liste.length) return Promise.resolve();
3565          var k = liste.shift();
3566          return ausAdresssuche(gruppen[k]).then(function (ok) {
3567            merke(ortsCache, k, gruppen[k]);
3568            if (ok) zeichne(ziel, reihenfolge, gruppen);
3569            speicherSchreiben(CACHE_ORTE, ortsCache);
3570            return naechster(liste);
3571          }).catch(function () { return naechster(liste); });
3572        }
3573      }).then(function () {
3574        zeichne(ziel, reihenfolge, gruppen);
3575        speicherSchreiben(CACHE_ORTE, ortsCache);
3576        letzteOffene = reihenfolge.filter(function (k) { return !gruppen[k].ort; })
3577          .map(function (k) {
3578            return { name: gruppen[k].name, gemeinde: gruppen[k].gemeinde || "?",
3579                     termine: gruppen[k].termine.length, schluessel: k };
3580          });
3581        if (letzteOffene.length) {
3582          console.info("[Karte] " + letzteOffene.length +
3583            " Veranstaltungsorte ohne Koordinaten – Liste über bwkOffeneOrte()");
3584        }
3585      });
3586    }).catch(function (e) {
3587      console.warn("[Karte] Termine konnten nicht geladen werden:", e);
3588    });
3589  }
3590
3591  function gruppenweise(liste, breite, arbeit) {
3592    var rest = liste.slice();
3593    function block() {
3594      if (!rest.length) return Promise.resolve();
3595      var teil = rest.splice(0, breite);
3596      return Promise.all(teil.map(function (x) {
3597        return arbeit(x).catch(function () { });
3598      })).then(block);
3599    }
3600    return block();
3601  }
3602
3603  function merke(cache, k, g) {
3604    cache[k] = g.ort
3605      ? { name: g.ort.name, adresse: g.ort.adresse, lat: g.ort.lat, lng: g.ort.lng,
3606          gemeinde: g.gemeinde || "", zeit: Date.now() }
3607      : { name: g.name, gemeinde: g.gemeinde || "", zeit: Date.now() };
3608  }
3609
3610  function zeichne(ziel, reihenfolge, gruppen) {
3611    var nachPunkt = {}, punkte = [];
3612
3613    reihenfolge.forEach(function (k) {
3614      var g = gruppen[k];
3615      if (!g.ort) return;
3616      var pk = g.ort.lat + "|" + g.ort.lng;
3617      if (!nachPunkt[pk]) {
3618        nachPunkt[pk] = { name: g.ort.name || g.name, adresse: g.ort.adresse || "",
3619                          lat: g.ort.lat, lng: g.ort.lng, gemeinde: g.gemeinde || "",
3620                          termine: [] };
3621        punkte.push(nachPunkt[pk]);
3622      }
3623      g.termine.forEach(function (t) {
3624        var schon = nachPunkt[pk].termine.some(function (x) {
3625          return x.titel === t.titel && x.datum === t.datum;
3626        });
3627        if (!schon) nachPunkt[pk].termine.push(t);
3628      });
3629    });
3630
3631    setzePunkte(ziel, punkte);
3632    speicherSchreiben(CACHE_TERMINE, { zeit: Date.now(), punkte: punkte });
3633  }
3634
3635  /* ---------- Karte zur gewählten Gemeinde bewegen ----------
3636     Läuft bei jeder Änderung im Gemeinde-Filter. Nutzt die schon
3637     geladenen echten Gemeindegrenzen (GEMEINDE_GRENZEN), um die
3638     Karte auf alle gerade angehakten Gemeinden gemeinsam
3639     einzupassen. Ist noch keine Gemeinde angehakt oder liegen die
3640     Grenzen noch nicht vor, bleibt die Karte einfach, wo sie ist. ---------- */
3641
3642  function grenzeAlsPunkte(geo) {
3643    if (!geo) return null;
3644    var punkte = [];
3645    function ausRing(ring) { ring.forEach(function (p) { punkte.push([p[1], p[0]]); }); }
3646    function ausPolygon(poly) { poly.forEach(ausRing); }
3647    if (geo.type === "Polygon") ausPolygon(geo.coordinates);
3648    else if (geo.type === "MultiPolygon") geo.coordinates.forEach(ausPolygon);
3649    return punkte.length ? punkte : null;
3650  }
3651
3652  // "Außerhalb vom Bregenzerwald" hat keine eigene Grenze – dafür
3653  // grob die Ausdehnung von Vorarlberg, damit die Karte dort
3654  // wenigstens sinnvoll hinauszoomt statt gar nichts zu tun
3655  var VORARLBERG_ECKEN = [[46.83, 9.47], [47.62, 10.30]];
3656
3657  function gemeindeKartePassen() {
3658    if (!karte) return;
3659    var aktive = GEMEINDE_ANZEIGE.filter(function (g) { return GEMEINDE_STAND[g] !== false; });
3660    if (!aktive.length) return;
3661
3662    var bounds = null;
3663    aktive.forEach(function (g) {
3664      var punkte = (g === GEMEINDE_AUSSERHALB) ? VORARLBERG_ECKEN : grenzeAlsPunkte(GEMEINDE_GRENZEN[g]);
3665      if (!punkte) return;
3666      if (!bounds) bounds = L.latLngBounds(punkte);
3667      else bounds.extend(punkte);
3668    });
3669    if (!bounds || !bounds.isValid()) return;
3670    karte.flyToBounds(bounds, { padding: [30, 30], maxZoom: 15, duration: .6 });
3671  }
3672
3673  /* =========================================================
3674     13) HILFEN FÜR DIE REDAKTION (Konsole)
3675     ========================================================= */
3676
3677  window.bwkVollbild = function (an) {
3678    if (an === false) vollbildAus();
3679    else if (an === true) vollbildEin();
3680    else vollbildSchalten();
3681    return vollbildAn ? "Vollbild an" : "Vollbild aus";
3682  };
3683
3684  // zeigt, was in den Markern tatsächlich steckt
3685  window.bwkMarkerPruefen = function () {
3686    var pins = document.querySelectorAll(".bwk-pin");
3687    if (!pins.length) return "Keine Marker im Dokument gefunden.";
3688    var mit = 0, ohne = 0;
3689    Array.prototype.forEach.call(pins, function (p) {
3690      if (p.querySelector("g, image")) mit++; else ohne++;
3691    });
3692    var erste = pins[0];
3693    var svg = erste.querySelector("svg");
3694    var masse = svg ? svg.getBoundingClientRect() : null;
3695    console.log("Marker gesamt: " + pins.length + ", mit Symbol: " + mit + ", ohne: " + ohne);
3696    if (masse) console.log("Größe des ersten Markers: " +
3697      Math.round(masse.width) + " x " + Math.round(masse.height) + " px");
3698    console.log(erste.innerHTML.slice(0, 500));
3699    return mit + " von " + pins.length + " Markern tragen ein Symbol";
3700  };
3701
3702  window.bwkOrteExportieren = function () {
3703    var cache = speicherLesen(CACHE_ORTE) || {}, gefunden = {}, ohne = [];
3704    Object.keys(cache).forEach(function (k) {
3705      var s = cache[k];
3706      if (!s || typeof s.lat !== "number") { ohne.push(s && s.name ? s.name : k); return; }
3707      if (k.indexOf("ort:") !== 0) return;
3708      gefunden[k.slice(4)] = '{ name: "' + String(s.name || "").replace(/"/g, "'") +
3709        '", adresse: "' + String(s.adresse || "").replace(/"/g, "'") +
3710        '", lat: ' + s.lat + ", lng: " + s.lng + " }";
3711    });
3712    var zeilen = Object.keys(gefunden).sort().map(function (k) {
3713      return '    "' + k + '": ' + gefunden[k];
3714    }).join(",\n");
3715    var ausgabe = "  var ORTE = {\n" + zeilen + "\n  };";
3716    if (ohne.length) ausgabe += "\n\n  /* ohne Koordinaten:\n     " + ohne.join("\n     ") + "\n  */";
3717    console.log(ausgabe);
3718    try { copy(ausgabe); } catch (e) { }
3719    return Object.keys(gefunden).length + " Orte, " + ohne.length + " offen";
3720  };
3721
3722  window.bwkOffeneOrte = function () {
3723    if (!letzteOffene.length) return "Alles verortet (oder noch am Laden).";
3724    console.table(letzteOffene);
3725    return letzteOffene.length + " Bezeichnungen ohne Koordinaten";
3726  };
3727
3728  window.bwkSymbolePruefen = function () {
3729    var adresse = kulturAdresse();
3730    if (!adresse) return "Keine KULTUR_FILEID gesetzt.";
3731    return fetch(adresse, { credentials: "same-origin", cache: "no-store" })
3732      .then(function (r) { return r.json(); })
3733      .then(function (d) {
3734        if (d && d.uri) {
3735          try { UMAP_SERVER = new URL(d.uri).origin.replace(/^http:/i, "https:"); } catch (e) { }
3736        }
3737        ebenenBericht(d);
3738        var gefunden = [];
3739        (function durch(liste) {
3740          (liste || []).forEach(function (l) {
3741            var u = txt(opt(l, "iconUrl", ""));
3742            if (u && gefunden.indexOf(u) === -1) gefunden.push(u);
3743            if (l.layers) durch(l.layers);
3744          });
3745        })(d.layers);
3746        if (!gefunden.length) { console.log("Keine iconUrl in der Datei."); return; }
3747        gefunden.forEach(function (u) {
3748          bildAdressen(u).forEach(function (adr) {
3749            if (/^data:/i.test(adr)) return;
3750            var bild = new Image();
3751            bild.onload  = function () { console.log("OK      " + adr); };
3752            bild.onerror = function () { console.warn("FEHLT   " + adr); };
3753            bild.src = adr;
3754          });
3755        });
3756      });
3757  };
3758
3759  window.bwkKulturPruefen = function () {
3760    var adresse = kulturAdresse();
3761    if (!adresse) return "Keine KULTUR_FILEID gesetzt.";
3762    return fetch(adresse, { credentials: "same-origin", cache: "no-store" })
3763      .then(function (r) { return r.text().then(function (t) { return { status: r.status, text: t }; }); })
3764      .then(function (a) {
3765        console.log("HTTP " + a.status + ", " + a.text.length + " Zeichen");
3766        try { ebenenBericht(JSON.parse(a.text)); }
3767        catch (e) { console.warn("Kein gültiges JSON:", e.message); }
3768      });
3769  };
3770
3771  window.bwkGrenzenPruefen = function () {
3772    var zeilen = GEMEINDE_FILTER.map(function (g) {
3773      var geo = GEMEINDE_GRENZEN[g];
3774      var ringe = 0;
3775      if (geo && geo.type === "Polygon") ringe = geo.coordinates.length;
3776      if (geo && geo.type === "MultiPolygon") ringe = geo.coordinates.reduce(function (s, p) { return s + p.length; }, 0);
3777      return { Gemeinde: g, Grenze: geo ? geo.type : "(fehlt)", Ringe: ringe || "" };
3778    });
3779    if (console.table) console.table(zeilen); else console.log(zeilen);
3780    return (GRENZEN_GELADEN ? "geladen: " : "lädt noch … ") +
3781      Object.keys(GEMEINDE_GRENZEN).length + " von " + GEMEINDE_FILTER.length;
3782  };
3783
3784  window.bwkGemeindenPruefen = function () {
3785    var zeilen = GEMEINDE_ANZEIGE.map(function (g) {
3786      return { Gemeinde: g, aktiv: GEMEINDE_STAND[g] !== false,
3787               Anzahl: (GEMEINDE_ZEILEN[g] && GEMEINDE_ZEILEN[g].anzahlFeld.textContent) || 0 };
3788    });
3789    if (console.table) console.table(zeilen); else console.log(zeilen);
3790    return zeilen.length + " Gemeinden im Filter";
3791  };
3792
3793  window.bwkVeranstaltungenPruefen = function () {
3794    return ladeAlleSeiten().then(function (eintraege) {
3795      var mitKoordinate = eintraege.filter(function (e) { return e.koordinaten; }).length;
3796      console.info("[Karte] " + eintraege.length + " Veranstaltungseinträge gelesen, " +
3797        mitKoordinate + " davon mit Koordinate direkt aus der Liste.");
3798      if (console.table) console.table(eintraege.slice(0, 30));
3799      return eintraege.length + " Einträge (siehe Konsole)";
3800    });
3801  };
3802
3803  window.bwkZuruecksetzen = function () {
3804    try {
3805      window.localStorage.removeItem(CACHE_ORTE);
3806      window.localStorage.removeItem(CACHE_TERMINE);
3807    } catch (e) { }
3808    return "Speicher geleert – Seite neu laden.";
3809  };
3810
3811  if (document.readyState === "complete" || document.readyState === "interactive") start();
3812  else document.addEventListener("DOMContentLoaded", start);
3813})();
3814</script>
3814</div>
3815<style>
3816.karte-button {
3817  display: inline-flex !important;
3818  align-items: center !important;
3819  gap: .6rem !important;
3820  padding: .8rem 1.1rem !important;
3821  background: #fff !important;
3822  border: 1px solid rgba(38,48,39,.12) !important;
3823  border-radius: 8px !important;
3824  color: #536B45 !important;
3825  font-size: .9rem !important;
3826  font-weight: 600 !important;
3827  text-decoration: none !important;
3828  transition: all .25s ease !important;
3829}
3830
3831.karte-button:hover {
3832  background: #2a7c30 !important;
3833  border-color: #4D882a !important;
3834  color: #fff !important;
3835  transform: translateY(-3px) !important;
3836  box-shadow: 0 6px 14px rgba(38,48,39,.15) !important;
3837}
3838
3839.karte-button span {
3840  font-size: 1.1rem !important;
3841  line-height: 1 !important;
3842}
3843</style>
3844
3845<p style="position:relative;clear:both;margin:0 0 2rem 0!important;text-align:center!important;">
3846  <a href="https://www.regiobregenzerwald.at/Karte" class="karte-button extlink">
3847    &nbsp;&nbsp;&nbsp;Gesamte Karte&nbsp;&nbsp;&nbsp;
3848    <span>&rsaquo;</span>
3849    &nbsp;&nbsp;&nbsp;
3850  </a>
3851</p></div></div><div class="box2042 section section__event"><div class="box2042 wrapper"><div class="titel"><h2>
3852																																																											Veranstaltungen | Termine
3853																																																										</h2><span class="titel_seperator"></span></div><div class="event"><div class="boxVeranstaltungsvorschau">
3854  <ul>
3855    <li>
3856      <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet">
3857        <span class="boxVeranstaltungsvorschauDatum">
3858          <span class="boxVeranstaltungsvorschauDatumTag">02</span>
3859          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
3860            <abbr title="Oktober">Okt</abbr>
3861          </span>
3862        </span>
3863      </a>
3864      <span class="boxVeranstaltungsvorschauTextBlock">
3865        <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet">
3866          <span class="boxVeranstaltungsvorschauText">
3867            <span class="boxVeranstaltungsvorschauTitel">
3868              <span class="boxVeranstaltungsvorschauTag">Heute</span>
3869              <h2>Dorfbücherei hat geöffnet</h2>
3870            </span>
3871          </span>
3872        </a>
3873        <span class="boxVeranstaltungsvorschauOrtBlock">
3874          <a class="extlink" href="http://riefensberg.bvoe.at" title="Dorfbücherei hat geöffnet">
3875            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
3876              <span class="boxVeranstaltungsvorschauTime">08:30 - 10:30 Uhr</span>
3877              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
3878            </span>
3879          </a>
3880        </span>
3881      </span>
3882      <div class="clear">
3883      </div>
3884    </li>
3885    <li>
3886      <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige">
3887        <span class="boxVeranstaltungsvorschauDatum">
3888          <span class="boxVeranstaltungsvorschauDatumTag">02</span>
3889          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
3890            <abbr title="Oktober">Okt</abbr>
3891          </span>
3892        </span>
3893      </a>
3894      <span class="boxVeranstaltungsvorschauTextBlock">
3895        <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige">
3896          <span class="boxVeranstaltungsvorschauText">
3897            <span class="boxVeranstaltungsvorschauTitel">
3898              <span class="boxVeranstaltungsvorschauTag">Heute</span>
3899              <h2>AusZeit für mich - für pflegende Angehörige</h2>
3900            </span>
3901          </span>
3902        </a>
3903        <span class="boxVeranstaltungsvorschauOrtBlock">
3904          <a class="extlink" href="/AusZeit_fuer_mich_-_fuer_pflegende_Angehoerige" title="AusZeit für mich - für pflegende Angehörige">
3905            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
3906              <span class="boxVeranstaltungsvorschauTime">09:30 - 16:30 Uhr</span>
3907              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
3908            </span>
3909          </a>
3910        </span>
3911      </span>
3912      <div class="clear">
3913      </div>
3914    </li>
3915    <li>
3916      <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3917        <span class="boxVeranstaltungsvorschauDatum">
3918          <span class="boxVeranstaltungsvorschauDatumTag">02</span>
3919          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
3920            <abbr title="Oktober">Okt</abbr>
3921          </span>
3922        </span>
3923      </a>
3924      <span class="boxVeranstaltungsvorschauTextBlock">
3925        <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3926          <span class="boxVeranstaltungsvorschauText">
3927            <span class="boxVeranstaltungsvorschauTitel">
3928              <span class="boxVeranstaltungsvorschauTag">Heute</span>
3929              <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2>
3930            </span>
3931          </span>
3932        </a>
3933        <span class="boxVeranstaltungsvorschauOrtBlock">
3934          <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3935            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
3936              <span class="boxVeranstaltungsvorschauTime">17:00 - 20:00 Uhr</span>
3937              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
3938            </span>
3939          </a>
3940        </span>
3941      </span>
3942      <div class="clear">
3943      </div>
3944    </li>
3945    <li>
3946      <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3947        <span class="boxVeranstaltungsvorschauDatum">
3948          <span class="boxVeranstaltungsvorschauDatumTag">03</span>
3949          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
3950            <abbr title="Oktober">Okt</abbr>
3951          </span>
3952        </span>
3953      </a>
3954      <span class="boxVeranstaltungsvorschauTextBlock">
3955        <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3956          <span class="boxVeranstaltungsvorschauText">
3957            <span class="boxVeranstaltungsvorschauTitel">
3958              <span class="boxVeranstaltungsvorschauTag">Morgen</span>
3959              <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2>
3960            </span>
3961          </span>
3962        </a>
3963        <span class="boxVeranstaltungsvorschauOrtBlock">
3964          <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
3965            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
3966              <span class="boxVeranstaltungsvorschauTime">10:00 - 16:00 Uhr</span>
3967              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
3968            </span>
3969          </a>
3970        </span>
3971      </span>
3972      <div class="clear">
3973      </div>
3974    </li>
3975    <li>
3976      <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
3977        <span class="boxVeranstaltungsvorschauDatum">
3978          <span class="boxVeranstaltungsvorschauDatumTag">03</span>
3979          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
3980            <abbr title="Oktober">Okt</abbr>
3981          </span>
3982        </span>
3983      </a>
3984      <span class="boxVeranstaltungsvorschauTextBlock">
3985        <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
3986          <span class="boxVeranstaltungsvorschauText">
3987            <span class="boxVeranstaltungsvorschauTitel">
3988              <span class="boxVeranstaltungsvorschauTag">Morgen</span>
3989              <h2>Öffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!"</h2>
3990            </span>
3991          </span>
3992        </a>
3993        <span class="boxVeranstaltungsvorschauOrtBlock">
3994          <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
3995            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
3996              <span class="boxVeranstaltungsvorschauTime">10:00 Uhr</span>
3997              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
3998            </span>
3999          </a>
4000        </span>
4001      </span>
4002      <div class="clear">
4003      </div>
4004    </li>
4005    <li>
4006      <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen">
4007        <span class="boxVeranstaltungsvorschauDatum">
4008          <span class="boxVeranstaltungsvorschauDatumTag">03</span>
4009          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
4010            <abbr title="Oktober">Okt</abbr>
4011          </span>
4012        </span>
4013      </a>
4014      <span class="boxVeranstaltungsvorschauTextBlock">
4015        <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen">
4016          <span class="boxVeranstaltungsvorschauText">
4017            <span class="boxVeranstaltungsvorschauTitel">
4018              <span class="boxVeranstaltungsvorschauTag">Morgen</span>
4019              <h2>ORF Lange Nacht der Museen</h2>
4020            </span>
4021          </span>
4022        </a>
4023        <span class="boxVeranstaltungsvorschauOrtBlock">
4024          <a class="extlink" href="/ORF_Lange_Nacht_der_Museen_1" title="ORF Lange Nacht der Museen">
4025            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
4026              <span class="boxVeranstaltungsvorschauTime">18:00 Uhr</span>
4027              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
4028            </span>
4029          </a>
4030        </span>
4031      </span>
4032      <div class="clear">
4033      </div>
4034    </li>
4035    <li>
4036      <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
4037        <span class="boxVeranstaltungsvorschauDatum">
4038          <span class="boxVeranstaltungsvorschauDatumTag">04</span>
4039          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
4040            <abbr title="Oktober">Okt</abbr>
4041          </span>
4042        </span>
4043      </a>
4044      <span class="boxVeranstaltungsvorschauTextBlock">
4045        <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
4046          <span class="boxVeranstaltungsvorschauText">
4047            <span class="boxVeranstaltungsvorschauTitel">
4048              <h2>Kunstbräu - Bregenzerwälder Kunstaustellung</h2>
4049            </span>
4050          </span>
4051        </a>
4052        <span class="boxVeranstaltungsvorschauOrtBlock">
4053          <a class="extlink" href="/Kunstbraeu_-_Bregenzerwaelder_Kunstaustellung_1" title="Kunstbräu - Bregenzerwälder Kunstaustellung">
4054            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
4055              <span class="boxVeranstaltungsvorschauTime">10:00 - 16:00 Uhr</span>
4056              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
4057            </span>
4058          </a>
4059        </span>
4060      </span>
4061      <div class="clear">
4062      </div>
4063    </li>
4064    <li>
4065      <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
4066        <span class="boxVeranstaltungsvorschauDatum">
4067          <span class="boxVeranstaltungsvorschauDatumTag">04</span>
4068          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
4069            <abbr title="Oktober">Okt</abbr>
4070          </span>
4071        </span>
4072      </a>
4073      <span class="boxVeranstaltungsvorschauTextBlock">
4074        <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
4075          <span class="boxVeranstaltungsvorschauText">
4076            <span class="boxVeranstaltungsvorschauTitel">
4077              <h2>Öffentliche Führung durch die Werkstätten und die Ausstellungen "Ich geh´ sticken!"</h2>
4078            </span>
4079          </span>
4080        </a>
4081        <span class="boxVeranstaltungsvorschauOrtBlock">
4082          <a class="extlink" href="/Oeffentliche_Fuehrung_durch_die_Werkstaetten_und_die_Ausstellungen_Ich_geh_sticken_" title="Öffentliche Führung durch die Werkstätten und die Ausstellungen &quot;Ich geh´ sticken!&quot;">
4083            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
4084              <span class="boxVeranstaltungsvorschauTime">10:00 Uhr</span>
4085              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
4086            </span>
4087          </a>
4088        </span>
4089      </span>
4090      <div class="clear">
4091      </div>
4092    </li>
4093    <li>
4094      <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz">
4095        <span class="boxVeranstaltungsvorschauDatum">
4096          <span class="boxVeranstaltungsvorschauDatumTag">04</span>
4097          <span class="boxVeranstaltungsvorschauvorschauDatumMonat">
4098            <abbr title="Oktober">Okt</abbr>
4099          </span>
4100        </span>
4101      </a>
4102      <span class="boxVeranstaltungsvorschauTextBlock">
4103        <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz">
4104          <span class="boxVeranstaltungsvorschauText">
4105            <span class="boxVeranstaltungsvorschauTitel">
4106              <h2>Wäldertanz</h2>
4107            </span>
4108          </span>
4109        </a>
4110        <span class="boxVeranstaltungsvorschauOrtBlock">
4111          <a class="extlink" href="/Waeldertanz_5" title="Wäldertanz">
4112            <span class="boxVeranstaltungsvorschauText boxVeranstaltungsvorschauTimeBlock">
4113              <span class="boxVeranstaltungsvorschauTime">14:00 - 17:00 Uhr</span>
4114              <span class="boxVeranstaltungsvorschauOrt">Bregenzerwald</span>
4115            </span>
4116          </a>
4117        </span>
4118      </span>
4119      <div class="clear">
4120      </div>
4121    </li>
4122  </ul>
4123</div>
4124<p class="boxVeranstaltungsvorschauWeitereTermine">
4125  <a class="extlink" href="/Aktuelles/Veranstaltungen">Alle Termine</a>
4126</p>
4127<div class="clear">
4128</div></div></div></div><div class="box2042 section section__partner"><div class="box2042 wrapper"><div class="titel"><h2>
4129																																																											Förderprojekte
4130																																																										</h2></div><div class="foerderprojekte"><p>In Zusammenarbeit mit <a class="extlink" href="https://www.bmluk.gv.at/themen/regionen-raumentwicklung/eu-regionalfoerderungen.html" target="_blank" rel="noopener noreferrer">Bund</a>, <a class="extlink" href="https://vorarlberg.at/-/abteilung-landwirtschaft-und-laendlicher-raum" target="_blank" rel="noopener noreferrer">Land</a> , <a class="extlink" href="https://ec.europa.eu/agriculture/rural-development-2014-2020_de" target="_blank" rel="noopener noreferrer">EU</a> und <a class="extlink" href="https://www.regio-v.at/" target="_blank" rel="noopener noreferrer">Regio V</a> wird der Öffentliche Nahverkehr zwischen dem Allgäu, Bregenzerwald, Lindau und dem Leiblachtal ausgebaut. Im Bregenzerwald stehen zudem die Förderung von Kultur, Vielfalt, Wissen und Austausch im Mittelpunkt.</p>
4131<div class="foerderblock">
4132
4133	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>Interegg</strong></a></p>
4134
4135	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>&Ouml;PNV grenzenlos unterwegs (ABH013)</strong></a></p>
4136
4137	<p>Grenzüberschreitender ÖPNV zwischen dem Allgäu, Bregenzerwald, Lindau und Leiblachtal.</p>
4138</div>
4139<div class="foerderblock">
4140
4141	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>Vernetzung /Mobilit&auml;t</strong></a></p>
4142
4143	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Europaeische_Projekte"><strong>BA0300391</strong></a></p>
4144
4145	<p>Gemeinsames ÖPNV-Angebot zwischen dem Bregenzerwald und dem Westallgäu stärken.</p>
4146</div>
4147<div class="foerderblock">
4148
4149	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p>
4150
4151	<p><a class="extlink" href="https://www.regio-v.at/projekte/bregenzerwald-in-vielfalt/" target="_blank" rel="noopener noreferrer"><strong>Bregenzerwald in Vielfalt</strong></a></p>
4152
4153	<p>Die Ausstellung zeigt die Zukunftsvision Bregenzerwald 2030 und lädt zur Auseinandersetzung mit Kultur, Zusammenleben und aktuellen Themen ein.</p>
4154</div>
4155<div class="foerderblock">
4156
4157	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p>
4158
4159	<p><a class="extlink" href="https://www.regio-v.at/projekte/bbm-wissenstransfer/" target="_blank" rel="noopener noreferrer"><strong>BBM Wissenstransfer</strong></a></p>
4160
4161	<p>Das Projekt beschäftigt sich mit der Geschichte der Bregenzerwälder Barockbaumeister und ihrer wissenschaftlichen Aufarbeitung.</p>
4162</div>
4163<div class="foerderblock">
4164
4165	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p>
4166
4167	<p><a class="extlink" href="https://www.regio-v.at/projekte/lebendige-geschichte-n/" target="_blank" rel="noopener noreferrer"><strong>Lebendige Geschichte(n)</strong></a></p>
4168
4169	<p>Bregenzerwälder Museen stärken ihre Zusammenarbeit, um Kultur einheitlich zu vermitteln.</p>
4170</div>
4171<div class="foerderblock">
4172
4173	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p>
4174
4175	<p><a class="extlink" href="https://www.regio-v.at/projekte/nahversorgung-leben/" target="_blank" rel="noopener noreferrer"><strong>Nahversorgung leben</strong></a></p>
4176
4177	<p>Das Projekt verbindet Jugend, Politik und Betriebe, um das Bewusstsein für regionale Angebote zu stärken.</p>
4178</div>
4179<div class="foerderblock">
4180
4181	<p><a class="extlink" href="https://www.regiobregenzerwald.at/Regio_V"><strong>Leader-Projekt</strong></a></p>
4182
4183	<p><a class="extlink" href="https://www.regio-v.at/projekte/oepnv-bw-optimiert/" target="_blank" rel="noopener noreferrer"><strong>&Ouml;PNV BW optimiert</strong></a></p>
4184
4185	<p>Das Projekt zielt darauf ab, Arbeitswege auszuarbeiten und zukunftsgerecht zu gestalten. </p>
4186</div></div><p><br></p><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/Partner_1"><img src="/system/web/getImage.ashx?fileid=1280141&amp;mode=T&amp;width=640&amp;height=131&amp;cts=1786092397" class="fr-dib width62" alt="Förderung von Land, Bund und Europäische Union"></a></p><p><br></p><p style="position:relative;clear:both;margin:0 0 2rem 0!important;text-align:center!important;"><a href="https://www.regiobregenzerwald.at/Partner_1" class="karte-button extlink">Zu den Projekten &nbsp; &nbsp;&rsaquo;</a></p></div></div><div class="box2042 section section__theme"><div class="box2042 wrapper"><div class="titel"><h2>
4187																																																											Regionale Aufgaben
4188																																																										</h2><span class="titel_seperator"></span></div><div class="box2042 flexbox flexbox__theme"><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Gemeinden/Gemeinden"><strong>Gemeinden</strong></a></h2><p>Die Regio Bregenzerwald stärkt die Zusammenarbeit der 24 Gemeinden des Bregenzerwaldes und entwickelt gemeinsam zukunftsorientierte Lösungen für die Region.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Baurechtsverwaltung"><strong>
4188Baurechtsverwaltung</strong></a></h2><p>Durch die Baurechtsverwaltung werden die Bauverfahren der Mitgliedsgemeinden einheitlich und kompetent durchgeführt.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/bregenzerwaldarchiv"><strong>Bregenzerwald Archiv</strong></a></h2><p>Das Bregenzerwald Archiv ist das Verwaltungsarchiv von 24 Gemeinden der Region Bregenzerwald. Der Zugang zu den Archivalien ist in der Archivordnung geregelt.</p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Informationen"><strong>Visionen</strong></a></h2><p>Gemeinsame Zukunftsvisionen und Leitsätze der Regio Bregenzerwald haben zum Ziel, das Miteinander in der Region nachhaltig, gesund und bewusst zu stärken.</p></div><div class="titel"><h2>
4189																																																											Themengebiete
4190																																																										</h2></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Leben">Leben</a></h2><p>Versorgung und Lebensqualität erhalten.</p></div><div class="https://www.regiobregenzerwald.at/Leben_1"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Bewegen">Bewegen</a></h2><p>Mobilität und Freiheit fördern.</p><p><br></p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Arbeiten">Arbeiten</a></h2><p>Innovation und Qualität garantieren.</p><p><br></p></div><div class="icon flexbox__item"><h2><a class="extlink" href="https://www.regiobregenzerwald.at/Bewahren">Bewahren</a></h2><p>Traditionen und Schützenswertes bewahren.</p></div></div></div></div><div class="box2042 section section__info"><div class="box2042 wrapper"><div class="box2042 flexbox flexbox__info"><div class="box2042 finder flexbox__item"><div class="h2"><h2>
4191																																																											Regionale Initiativen
4192																																																										</h2><span class="titel_seperator"></span></div><div class="gutschein"><p><a class="extlink" href="https://www.regiobregenzerwald.at/Bregenzerwald_Gutschein"><strong>Bregenzerwald Gutschein</strong></a></p><p>Schenken Sie regionale Verbundenheit und stärken Sie mit Ihrem Geschenk die heimische Wirtschaft.</p><p><br></p><p><a class="extlink" href="https://www.regiobregenzerwald.at/ich_kauf_im_Wald"><strong>Ich kauf im Wald</strong></a></p><p>Das Bewusstsein für nachhaltige und regionale Produkte stärken.</p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/fahrradbus-2026" target="_blank" rel="noopener noreferrer"><strong>Fahrradbus</strong></a></p><p>Mit den Fahrrad-Bus-Linien 8R1 & 8R2 lässt sich das eigene Fahrrad oder E-Bike auf den Anhänger der Linienbusse aufladen und unkompliziert mitnehmen. </p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/wanderbuslinie-497-bequem-ab-damuels-unterwegs" target="_blank" rel="noopener noreferrer"><strong>Wanderbus</strong></a></p><p>Die Wanderbuslinie verbindet Damüls über das Furkajoch mit Innerlaterns und erschließt damit das beliebte Wandergebiet mit dem öffentlichen Verkehr.</p><p><br></p><p><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald/nachtbuslinien-8n1-und-8n2" target="_blank" rel="noopener noreferrer"><strong>Nachtbus</strong></a></p><p>Die Nachtbusse 8N1 und 8N2 fahren in der Nacht von Samstag auf Sonntag, außer an Feiertagen. </p></div></div><div class="box2042 apps flexbox__item"><div class="h2"><h2>
4193																																																											Empfohlene APPs
4194																																																										</h2><span class="titel_seperator"></span></div><div class="app"><div class="app-container"><a href="/gem2go" target="newwnd" title="Mobile APP Gem2Go"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983798&amp;mode=o&amp;cts=1580896475" class="fr-fic fr-dii"></div><div class="app-text"><strong>Österreichs einzige mobile Bürgerservice App</strong><br>Gem2Go vereint alle Gemeinden in Österreich in einer App. Informationen zu Gemeinden und Regionen sind so schnell, bequem und mit einem Fingerzeig jederzeit abrufbar.</div></a></div></div><div class="app"><div class="app-container"><a href="/waelderdoc" target="newwnd" title="Anwendung Wälderdoc"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983801&amp;mode=o&amp;cts=1580896469"/></div><div class="app-text"><strong>Nichts geht &uuml;ber unsere Gesundheit<br></strong>Die W&auml;lderDoc-App bietet den Menschen in der Region und auch jenen, die im medizinischen Bereich t&auml;tig sind, eine einmalige Plattform. Kompakt, &uuml;bersichtlich, informativ.</div></a></div>
4195</div><div class="app"><div class="app-container"><a href="/fairtiq" target="newwnd" title="Fairtiq"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983799&amp;mode=o&amp;cts=1580896457" /></div><div class="app-text"><strong>Die einfachste Fahrkarte &Ouml;sterreichs<br></strong>Ein Wisch am Smartphone vor dem Einsteigen und nach dem Aussteigen reicht und Sie erhalten eine g&uuml;ltige Fahrkarte f&uuml;r die zur&uuml;ckgelegte Strecke &ndash; zum besten verf&uuml;gbaren Preis.</div></a></div>
4196</div><div class="app"><div class="app-container"><a href="/vmobil" target="newwnd" title="Clever V Mobil"><div class="app-image"><img alt="" src="/system/web/GetImage.ashx?fileid=983800&amp;mode=o&amp;cts=1580896462" /></div><div class="app-text"><strong>Die Mobilit&auml;tsplattform f&uuml;r Vorarlberg<br></strong>Bus, Bahn, Fahrrad, Carsharing, Schiff und zu Fu&szlig; &ndash; mit VMOBIL haben Sie alle Mobilit&auml;tsangebote Vorarlbergs auf einen Blick.</div></a></div>
4197</div></div></div></div></div>
4198        
4199        
4200    
4201<script type="text/javascript">
4202//<![CDATA[
4203var ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray =  new Array('', '', '', '/system/WebResource.axd?d=Cwluxy80IT5OIlqhOMCzhxuwwtValsTsqO5DhdxS1vYWcftWceEb3uVWV0UXEIUjAjpOe-7g1ckDb8RLYyD-LZEbt-2xZcYU__u05ThJzVuStu0W0&t=639245057389592256', '/system/WebResource.axd?d=0olVLoWJ9sR5mmBD1M-qWhn4ciKUWauv7smZaFZbosTf-YRtkJ8RLKSNZfezje3wFZwSvCZh9pAWf8ERb-qTU1bjQd6npVIWz96Li8x179pWdl780&t=639245057389592256', '/system/WebResource.axd?d=i-UhIwZ8h3_WXs3cYAF-UHZSQdDOHrsAnOJ0LyrM2_yQGYEje8m7Mokgy6QWESCR1LTvxaMB_Uwz3B_kbVLn_8w6beW0G3Sjg696qHUv5syR-zOp0&t=639245057389592256');
4204																																																										//]]>
4205</script>
4205
4206
4207																																																										<div class="aspNetHidden">
4208
4209																																																											<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="F35DDA41" />
4210																																																										</div>
4211																																																										            
4212                            
4212<script type="text/javascript">
4213                                    var lbsettings = {"txtImage":"Bild","txtOf":"von","sprachid":"1","imgCopyright":"Copyright","imgAltText":"Alternativtext","imgQuelle":"Quelle","imgLongDesc":"Fotobeschreibung","bildInformation":"Bildinformation","btnCloseLabel":"Schließen","btnNextImage":"Nächstes Bild","btnPreviousImage":"Vorheriges Bild"};
4214                                      var bslboptions = {
4215	                                    keyboard: true,
4216	                                    size: 'xl',
4217                                        target: '[data-lbgroup]',
4218                                        type: 'image'
4219                                    };
4220
4221                                    if (typeof jQuery === "undefined") {
4222                                        document.querySelectorAll('[data-lbgroup]').forEach((el) => el.addEventListener('click', (e) => {
4223                                            e.preventDefault();
4224
4225                                            let sprache = 1;
4226                                            let fileid = el.href.match(/fileid=(\d+)/i)[1];
4227
4228                                            let url = `/system/web/services/files/filesinfo.asmx/GetFileInfo`;
4229                                            let data = { FileID : fileid, SprachId: sprache };
4230                                            fetch(url, {
4231                                                method: 'POST',
4232                                                headers: {
4233                                                    'Content-Type': 'application/json'
4234                                                },
4235                                                body: JSON.stringify(data)
4236                                            }).then(response => {
4237                                                response.json().then(data => {
4238                                                    if(data && data.d && data.d.Longdesc)
4239                                                        el.dataset.description = data.d.Longdesc;
4240
4241
4242                                                    const lightbox = new Lightbox(el, bslboptions);
4243                                                    lightbox.show();
4244                                                });
4245                                            });
4246
4247
4248
4249                                        }));
4250                                    }
4251                                    else {
4252                                        $(document).ready(function () {
4253                                            if (typeof Lightbox != "undefined") {
4254                                                document.querySelectorAll('[data-lbgroup]').forEach((el) => el.addEventListener('click', (e) => {
4255                                                    e.preventDefault();
4256
4257                                            let sprache = 1;
4258                                            let fileid = el.href.match(/fileid=(\d+)/i)[1];
4259
4260                                            let url = `/system/web/services/files/filesinfo.asmx/GetFileInfo`;
4261                                            let data = { FileID : fileid, SprachId: sprache };
4262                                            fetch(url, {
4263                                                method: 'POST',
4264                                                headers: {
4265                                                    'Content-Type': 'application/json'
4266                                                },
4267                                                body: JSON.stringify(data)
4268                                            }).then(response => {
4269                                                response.json().then(data => {
4270                                                    if(data && data.d && data.d.Longdesc)
4271                                                        el.dataset.description = data.d.Longdesc;
4272
4273                                                    const lightbox = new Lightbox(el, bslboptions);
4274                                                    lightbox.show();
4275                                                });
4276                                            });
4277
4278
4279
4280                                                }));
4281                                            }
4282                                            else {
4283
4284                                                let styleEl = document.createElement("link");
4285                                                styleEl.rel = "stylesheet";
4286                                                styleEl.type = "text/css";
4287                                                styleEl.href = "/system/web/lightboxJQuery/css/jquery.lightbox-0.5.css";
4288                                                document.head.appendChild(styleEl);
4289
4290                                                $(function () {
4291                                                    $('a[data-lbgroup]').lightBox(lbsettings);
4292                                                    $('a[id*="startup"]').click();
4293                                                });
4294
4295
4296                                                $(function () {
4297                                                    if (!jQuery.isFunction($('a[data-lbgroup]').lightBox)) {
4298                                                        loadlightbox();
4299                                                    }
4300                                                    $('a[rel*="lightbox"]').lightBox(lbsettings);
4301                                                });
4302                                            }
4303                                        });
4304                                    }
4305
4306                                    
4307                            </script>
vendor: 2 bytes, line 4307
4307
4308<script type="text/javascript">
4309//<![CDATA[
4310var ctl00_ctl00_ctl00_cph_header_ctl02_Data = new Object();
4311ctl00_ctl00_ctl00_cph_header_ctl02_Data.images = ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray;
4312ctl00_ctl00_ctl00_cph_header_ctl02_Data.collapseToolTip = "Collapse {0}";
4313ctl00_ctl00_ctl00_cph_header_ctl02_Data.expandToolTip = "Expand {0}";
4314ctl00_ctl00_ctl00_cph_header_ctl02_Data.expandState = theForm.elements['ctl00_ctl00_ctl00_cph_header_ctl02_ExpandState'];
4315ctl00_ctl00_ctl00_cph_header_ctl02_Data.selectedNodeID = theForm.elements['ctl00_ctl00_ctl00_cph_header_ctl02_SelectedNode'];
4316(function() {
4317  for (var i=0;i<6;i++) {
4318  var preLoad = new Image();
4319  if (ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray[i].length > 0)
4320    preLoad.src = ctl00_ctl00_ctl00_cph_header_ctl02_ImageArray[i];
4321  }
4322})();
4323//]]>
4324</script>
4324
4325</form>
4326
4327    
4328        <div class="clear"></div>
4329        
4330    <div id="main-content-footer"></div></div></div>
4331
4332                            </div>
4333                        
4334																																																									</div>
4335                        
4336                    
4337																																																								</div>
4338                    <div id="col-c" class="sidecol-c">
4339                        
4340    
4341
4342                    </div>
4343                    <div class="clear" id="em"></div>
4344                </div>
4345
4346            </div></div><div class="footer_wrapper" role="contentinfo"><div id="footer" class="clear">
4347                
4348    <div class="box2042 flexbox flexbox__footer"><div class="box2042 wrapper_gemeinden flexbox__item"><h2>
4349																																																									Gemeinden
4350																																																								</h2><p>
4351	<a class="extlink" href="https://www.regiobregenzerwald.at/Gemeinden/Gemeinden" rel="noopener noreferrer" title="Partnergemeinden"><img src="/system/web/getImage.ashx?fileid=1348880&amp;mode=T&amp;width=640&amp;height=480&amp;cts=1786975111" class="fr-fic fr-dii width80"></a></p>
4352
4353<p>
4354	<br>
4355</p></div><div class="box2042 wrapper_contact flexbox__item"><div class="contact flexbox__item"><h2>
4356																																																									Kontakt
4357																																																								</h2><p style="color: #000000;"><strong>Regio Bregenzerwald</strong><br>Loco 597 | 6863 Egg</p><p style="color: #000000;"><a href="tel:+43551226000">+43 5512 26000</a><br><a href="mailto:[email protected]">[email protected]</a></p><p style="color: #000000;"><a class="extlink" href="https://www.regiobregenzerwald.at/Kontakt">Kontaktadressen</a></p></div></div><div class="box2042 wrapper_openinghours openinghours flexbox__item"><h2>
4358																																																									Öffnungszeiten
4359																																																								</h2><p class='ris_oz_ga_header'>Öffnungszeiten</p><div class='ris_oz_ga_times'><ul class='ris_oz_list'><li class='ris_oz_listitem odd'><span class='ris_oz_days'><abbr title='Montag'>Mo</abbr>, <abbr title='Dienstag'>Di</abbr>, <abbr title='Mittwoch'>Mi</abbr>, <abbr title='Freitag'>Fr</abbr> </span><span class='ris_oz_times'>09:00  <span class="ris_oz_uhr">Uhr</span> - 12:30  <span class="ris_oz_uhr">Uhr</span></span></li><li class='ris_oz_listitem even'><span class='ris_oz_days'><abbr title='Donnerstag'>Do</abbr> </span><span class='ris_oz_times'>09:00  <span class="ris_oz_uhr">Uhr</span> - 16:00  <span class="ris_oz_uhr">Uhr</span></span></li></ul>
4360</div><p class='ris_oz_da_next ris_ga_oz_closed'>Das nächste Mal geöffnet:<br /><abbr title='Montag'>Mo</abbr>, 05.10.2026 ab 09:00  <span class="ris_oz_uhr">Uhr</span></p></div><div class="box2042 "><h2>
4361																																																									Quicklinks
4362																																																								</h2><p style="color: #000000;"><a class="extlink" href="https://www.vmobil.at/de/ueber-vmobil/wir-sind-vmobil-mobilitaetspartner/landbus-bregenzerwald" target="_blank" rel="noopener noreferrer">Landbus Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://waelderkinder.com/" target="_blank" rel="noopener noreferrer">Kein Kind zurücklassen</a></p><p style="color: #000000;"><a class="extlink" href="https://www.bregenzerwald.at/" target="_blank" rel="noopener noreferrer">Bregenzerwald Tourismus</a></p><p style="color: #000000;"><a class="extlink" href="https://www.werkraum.at/" target="_blank" rel="noopener noreferrer">Werkraum Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://www.kaesestrasse.at/" target="_blank" rel="noopener noreferrer">KäseStrasse Bregenzerwald</a></p><p style="color: #000000;"><a class="extlink" href="https://www.ojb.at/" target="_blank" rel="noopener noreferrer">Offene Jugendarbeit</a></p><p style="color: #000000;"><a class="extlink" href="https://www.regiobregenzerwald.at/Karte">Bregenzerwald Karte</a></p></div></div></div></div><div class="box2042 section section__tray mobility1 mobility2"><div class="box2042 wrapper"><div class="hmenu  tray mobility1 mobility2"><p class="TrayMenu"><a  href="/Web/Datenschutz" class="schwarz-empty">Datenschutz</a><a  href="/Web/Impressum" class="schwarz-empty">Impressum</a><a  href="/Web/Sitemap" class="schwarz-empty">Sitemap</a><a  href="/Web/Suche" class="schwarz-empty">Suche</a></p></div></div></div><div class="box2042 section section__map mobility1 mobility2"><div class="box2042 "></div></div><div class="box2042 section section__links mobility1 mobility2"></div></div><!-- CORE JS -->
4363<script src="/system/web/GetDocument.ashx?fileid=998466&amp;cts=1604476299" type="text/javascript"></script>
vendor: 2 bytes, line 4363
4363
4364<script src="/system/web/GetDocument.ashx?fileid=983666&amp;cts=1604476435" type="text/javascript"></script>
4364
4365
4366<!-- Matomo -->
4367<script type="text/javascript">
4368  var _paq = window._paq = window._paq || [];
4369_paq.push(['enableLinkTracking']);_paq.push(['trackPageView']);
4370  (function() {
4371    var u="https://statistics.gem2go.page/";
4372    if(!allowTracking) {
4373      _paq.push(['disableCookies']);
4374      _paq.push(['forgetCookieConsentGiven']);
4375    }
4376    _paq.push(['setTrackerUrl', u+'piwik.php']);
4377    _paq.push(['setSiteId', 2771]);
4378    var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
4379    g.type='text/javascript'; g.async=true; g.src=u+'js/'; s.parentNode.insertBefore(g,s);
4380  })();
4381try {
4382  document.addEventListener('DOMContentLoaded', function() {
4383    // Handle phone link clicks
4384    const phoneLinks = document.querySelectorAll('a[href^="tel:"]');
4385    for (const link of phoneLinks) {
4386      link.addEventListener('click', function() {
4387        _paq.push(['trackEvent','Linkklick', 'Telefonnummer anrufen (tel:)']);
4388      });
4389    }
4390
4391    // Handle download link clicks
4392    const downloadLinks = document.querySelectorAll('.piwik_download_tracker');
4393    for (const link of downloadLinks) {
4394      link.addEventListener('click', function() {
4395        const currentLoc = window.location.origin;
4396        const datatyp = link.dataset.trackingtyp;
4397        let bez = link.dataset.bez;
4398
4399        if (bez === undefined) {
4400          bez = link.title;
4401        }
4402
4403        if (bez === undefined) {
4404          bez = link.textContent;
4405        }
4406        _paq.push(['trackLink',currentLoc + '/' + datatyp + '/' + bez, 'download']);
4407      });
4408    }
4409  });
4410} catch (err) {}
4411</script>
4411
4412<!-- End Matomo Code -->
4413
4414<script type="text/javascript">
4415    window.piwikAsyncInit = function () {};
4416</script>
4416
4417    
4418
4419            </div></div>
4420    
4421
4422    
4423
4424    </div>
4425    
4426    
4426<script src="/cdnstatic/system/Javascriptz/ris/iFrameMessageAPI.js" type="text/javascript" async="async"></script>
4426
4427																																																								
4427<script src="/cdnstatic/system/Javascript/ris/trackNewspoolView.js?20210531T2006" type="text/javascript"></script>
4427
4428																																																								
4428<script src="/cdnstatic/meineseite/meineseite.js" type="text/javascript"></script>
4428
4429																																																								
4429<script src="/cdnstatic/muellinfoservice/muellinfoservice.js" type="text/javascript"></script>
4429
4430																																																								
4430<script src="/cdnstatic/gelbeseite/userinvite.js" type="text/javascript"></script>
4430
4431																																																								
4431<script src="/cdnstatic/nachrichtendienst/nachrichtendienst.js" type="text/javascript"></script>
4431
4432																																																								
4432<script src="/system/statV.1789655742/JavaScript/cookie.defer.js" type="text/javascript" defer="defer"></script>
4432
4433																																																								
4433<script src="/system/statV.1789655742/JavaScript/mobileAppdetector.defer.js" type="text/javascript" defer="defer"></script>
4433
4434																																																								
4434<script src="/cdnstatic/system/Javascript/flipbook/js/flipbook.init.defer.js" type="text/javascript" defer="defer"></script>
4434
4435																																																								
4436
4437</body>
4438</html>

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.