{"id":52854,"date":"2026-04-27T12:31:37","date_gmt":"2026-04-27T10:31:37","guid":{"rendered":"https:\/\/blickpunkt-lokalsport.de\/?page_id=52854"},"modified":"2026-06-10T18:47:30","modified_gmt":"2026-06-10T16:47:30","slug":"statistikbg","status":"publish","type":"page","link":"https:\/\/blickpunkt-lokalsport.de\/english\/statistikbg\/","title":{"rendered":"Statistikbg"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"52854\" class=\"elementor elementor-52854\" data-elementor-settings=\"{&quot;element_pack_global_tooltip_width&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;element_pack_global_tooltip_width_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;element_pack_global_tooltip_width_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;element_pack_global_tooltip_padding&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;element_pack_global_tooltip_padding_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;element_pack_global_tooltip_padding_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;element_pack_global_tooltip_border_radius&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;element_pack_global_tooltip_border_radius_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true},&quot;element_pack_global_tooltip_border_radius_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;top&quot;:&quot;&quot;,&quot;right&quot;:&quot;&quot;,&quot;bottom&quot;:&quot;&quot;,&quot;left&quot;:&quot;&quot;,&quot;isLinked&quot;:true}}\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-e6f55eb e-flex e-con-boxed e-con e-parent\" data-id=\"e6f55eb\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-139f8e5 elementor-widget elementor-widget-html\" data-id=\"139f8e5\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"fotostatistik-owl\">\r\n  <style>\r\n    #fotostatistik-owl {\r\n      --bg: #f6f4ef;\r\n      --bg-soft: #ffffff;\r\n      --card: #ffffff;\r\n      --line: #e6e2d8;\r\n      --line-soft: #f0ece2;\r\n      --text: #2a2a2a;\r\n      --text-soft: #5a5a5a;\r\n      --muted: #9a948a;\r\n      --accent: #2f7d4f;\r\n      --accent-soft: #d8eadd;\r\n      --accent-alt: #5a87bf;\r\n      --accent-alt-soft: #dde7f3;\r\n      --warn: #c97a2b;\r\n      --warn-soft: #f6e3cb;\r\n      --cold: #b85a1c;\r\n      --cold-soft: #fde4cb;\r\n      --shadow: 0 1px 2px rgba(0,0,0,.04), 0 4px 12px rgba(0,0,0,.04);\r\n      background: var(--bg);\r\n      color: var(--text);\r\n      font: 15px\/1.55 -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,sans-serif;\r\n      padding: 0;\r\n    }\r\n\r\n    #fotostatistik-owl * { box-sizing: border-box; }\r\n    #fotostatistik-owl .wrap { max-width: 1200px; margin: 0 auto; padding: 36px 22px 80px; }\r\n    #fotostatistik-owl h1 { font-size: 30px; margin: 0 0 6px; letter-spacing: -.02em; }\r\n    #fotostatistik-owl h2 {\r\n      font-size: 16px;\r\n      margin: 0 0 18px;\r\n      letter-spacing: .02em;\r\n      color: var(--text-soft);\r\n      text-transform: uppercase;\r\n      font-weight: 600;\r\n    }\r\n    #fotostatistik-owl .sub { color: var(--text-soft); margin-bottom: 16px; font-size: 14px; }\r\n\r\n    #fotostatistik-owl .status {\r\n      margin: 0 0 10px;\r\n      padding: 10px 12px;\r\n      border-radius: 10px;\r\n      background: var(--bg-soft);\r\n      border: 1px solid var(--line);\r\n      color: var(--text-soft);\r\n      font-size: 13px;\r\n    }\r\n    #fotostatistik-owl .status.error {\r\n      background: var(--warn-soft);\r\n      color: var(--warn);\r\n      border-color: #edcfaa;\r\n    }\r\n    #fotostatistik-owl .status.ok {\r\n      background: var(--accent-soft);\r\n      color: var(--accent);\r\n      border-color: #bdd8c5;\r\n    }\r\n\r\n    #fotostatistik-owl .kpi-grid {\r\n      display: grid;\r\n      grid-template-columns: repeat(4, 1fr);\r\n      gap: 14px;\r\n      margin-bottom: 36px;\r\n    }\r\n\r\n    #fotostatistik-owl .kpi {\r\n      background: var(--card);\r\n      border: 1px solid var(--line);\r\n      border-radius: 12px;\r\n      padding: 18px 20px;\r\n      box-shadow: var(--shadow);\r\n    }\r\n\r\n    #fotostatistik-owl .kpi .num {\r\n      font-size: 30px;\r\n      font-weight: 700;\r\n      color: var(--accent);\r\n      letter-spacing: -.02em;\r\n    }\r\n\r\n    #fotostatistik-owl .kpi .lbl {\r\n      color: var(--text-soft);\r\n      font-size: 13px;\r\n      margin-top: 4px;\r\n    }\r\n\r\n    #fotostatistik-owl .grid {\r\n      display: grid;\r\n      grid-template-columns: 1.5fr 1fr;\r\n      gap: 22px;\r\n      margin-bottom: 28px;\r\n    }\r\n\r\n    @media (max-width: 900px) {\r\n      #fotostatistik-owl .grid { grid-template-columns: 1fr; }\r\n      #fotostatistik-owl .kpi-grid { grid-template-columns: repeat(2, 1fr); }\r\n    }\r\n\r\n    @media (max-width: 560px) {\r\n      #fotostatistik-owl .kpi-grid { grid-template-columns: 1fr; }\r\n    }\r\n\r\n    #fotostatistik-owl .card {\r\n      background: var(--card);\r\n      border: 1px solid var(--line);\r\n      border-radius: 12px;\r\n      padding: 22px;\r\n      box-shadow: var(--shadow);\r\n    }\r\n\r\n    #fotostatistik-owl .club-card { padding: 14px 0; border-bottom: 1px solid var(--line-soft); }\r\n    #fotostatistik-owl .club-card:last-child { border-bottom: 0; }\r\n    #fotostatistik-owl .club-head { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; flex-wrap: wrap; }\r\n    #fotostatistik-owl .club-rank { font-size: 12px; color: var(--muted); font-weight: 600; min-width: 24px; }\r\n    #fotostatistik-owl .club-name { font-weight: 600; flex: 1; }\r\n    #fotostatistik-owl .club-count { font-size: 13px; color: var(--accent); font-weight: 600; }\r\n\r\n    #fotostatistik-owl .bar-track { height: 8px; background: var(--line-soft); border-radius: 4px; overflow: hidden; }\r\n    #fotostatistik-owl .bar-fill { height: 100%; background: var(--accent); border-radius: 4px; transition: width .4s ease; }\r\n    #fotostatistik-owl .bar-fill.alt { background: var(--accent-alt); }\r\n\r\n    #fotostatistik-owl .age-pills { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }\r\n    #fotostatistik-owl .age-pill {\r\n      display: inline-flex;\r\n      align-items: center;\r\n      gap: 6px;\r\n      padding: 3px 9px;\r\n      background: var(--accent-soft);\r\n      color: var(--accent);\r\n      border-radius: 14px;\r\n      font-size: 12px;\r\n      font-weight: 500;\r\n      cursor: help;\r\n    }\r\n\r\n    #fotostatistik-owl .age-pill b { font-weight: 600; }\r\n\r\n    #fotostatistik-owl .age-pill .pill-count {\r\n      background: rgba(255,255,255,.6);\r\n      padding: 0 6px;\r\n      border-radius: 10px;\r\n      font-size: 11px;\r\n      font-weight: 600;\r\n    }\r\n\r\n    #fotostatistik-owl .age-pill.cold {\r\n      background: var(--cold-soft);\r\n      color: var(--cold);\r\n      border: 1px dashed var(--cold);\r\n      padding: 2px 8px;\r\n    }\r\n\r\n    #fotostatistik-owl .age-pill.cold .pill-count { background: rgba(255,255,255,.7); }\r\n\r\n    #fotostatistik-owl .cold-badge {\r\n      display: inline-block;\r\n      padding: 2px 8px;\r\n      background: var(--cold-soft);\r\n      color: var(--cold);\r\n      border-radius: 10px;\r\n      font-size: 11px;\r\n      font-weight: 600;\r\n      margin-right: 4px;\r\n    }\r\n\r\n    #fotostatistik-owl .legend {\r\n      display: flex;\r\n      gap: 16px;\r\n      flex-wrap: wrap;\r\n      margin-bottom: 14px;\r\n      font-size: 12px;\r\n      color: var(--text-soft);\r\n      align-items: center;\r\n    }\r\n\r\n    #fotostatistik-owl .legend-item { display: inline-flex; align-items: center; gap: 6px; }\r\n    #fotostatistik-owl .legend-swatch { width: 14px; height: 14px; border-radius: 50%; display: inline-block; }\r\n    #fotostatistik-owl .legend-swatch.warm { background: var(--accent-soft); border: 1px solid var(--accent); }\r\n    #fotostatistik-owl .legend-swatch.cold { background: var(--cold-soft); border: 1px dashed var(--cold); }\r\n\r\n    #fotostatistik-owl .bar-row { margin-bottom: 14px; }\r\n    #fotostatistik-owl .bar-label {\r\n      font-size: 14px;\r\n      margin-bottom: 4px;\r\n      font-weight: 500;\r\n      display: flex;\r\n      justify-content: space-between;\r\n      align-items: baseline;\r\n      gap: 10px;\r\n    }\r\n\r\n    #fotostatistik-owl .age-num { font-size: 13px; color: var(--accent-alt); font-weight: 600; }\r\n\r\n    #fotostatistik-owl .month-row {\r\n      display: flex;\r\n      align-items: flex-end;\r\n      gap: 8px;\r\n      height: 180px;\r\n      padding: 8px 0;\r\n      overflow-x: auto;\r\n    }\r\n\r\n    #fotostatistik-owl .month-bar {\r\n      flex: 1;\r\n      min-width: 38px;\r\n      display: flex;\r\n      flex-direction: column;\r\n      align-items: center;\r\n      justify-content: flex-end;\r\n      height: 100%;\r\n    }\r\n\r\n    #fotostatistik-owl .month-fill {\r\n      width: 70%;\r\n      max-width: 32px;\r\n      background: linear-gradient(to top, var(--accent), #6cc28d);\r\n      border-radius: 4px 4px 0 0;\r\n      min-height: 4px;\r\n      transition: height .4s ease;\r\n    }\r\n\r\n    #fotostatistik-owl .month-count { font-size: 12px; color: var(--text); font-weight: 600; margin-bottom: 4px; }\r\n    #fotostatistik-owl .month-label { font-size: 11px; color: var(--muted); margin-top: 6px; }\r\n\r\n    #fotostatistik-owl .search-box { display: flex; gap: 10px; margin-bottom: 14px; flex-wrap: wrap; align-items: center; }\r\n    #fotostatistik-owl .search-box input {\r\n      flex: 1;\r\n      min-width: 220px;\r\n      background: #fff;\r\n      border: 1px solid var(--line);\r\n      color: var(--text);\r\n      padding: 10px 14px;\r\n      border-radius: 8px;\r\n      font: inherit;\r\n    }\r\n\r\n    #fotostatistik-owl .search-box input:focus {\r\n      outline: 2px solid var(--accent);\r\n      outline-offset: -1px;\r\n      border-color: transparent;\r\n    }\r\n\r\n    #fotostatistik-owl .search-box button {\r\n      background: var(--bg-soft);\r\n      border: 1px solid var(--line);\r\n      color: var(--text-soft);\r\n      padding: 9px 16px;\r\n      border-radius: 8px;\r\n      cursor: pointer;\r\n      font: inherit;\r\n    }\r\n\r\n    #fotostatistik-owl .search-box button:hover { background: var(--line-soft); }\r\n    #fotostatistik-owl .search-box .info { color: var(--muted); font-size: 13px; margin-left: auto; }\r\n\r\n    #fotostatistik-owl table { width: 100%; border-collapse: collapse; font-size: 13px; }\r\n    #fotostatistik-owl th, #fotostatistik-owl td {\r\n      padding: 10px 12px;\r\n      text-align: left;\r\n      border-bottom: 1px solid var(--line-soft);\r\n      vertical-align: top;\r\n    }\r\n\r\n    #fotostatistik-owl th {\r\n      position: sticky;\r\n      top: 0;\r\n      background: #faf8f3;\r\n      color: var(--text-soft);\r\n      font-size: 11px;\r\n      text-transform: uppercase;\r\n      letter-spacing: .05em;\r\n      font-weight: 600;\r\n    }\r\n\r\n    #fotostatistik-owl .date { white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--accent); width: 110px; font-weight: 600; }\r\n    #fotostatistik-owl .clubs { font-weight: 500; }\r\n    #fotostatistik-owl .age { width: 170px; }\r\n    #fotostatistik-owl .summary { color: var(--muted); font-size: 12px; }\r\n    #fotostatistik-owl .comp-pill {\r\n      display: inline-block;\r\n      padding: 2px 8px;\r\n      background: var(--warn-soft);\r\n      color: var(--warn);\r\n      border-radius: 12px;\r\n      font-size: 11px;\r\n      font-weight: 500;\r\n    }\r\n\r\n    #fotostatistik-owl .muted { color: var(--muted); }\r\n    #fotostatistik-owl .table-wrap {\r\n      max-height: 600px;\r\n      overflow: auto;\r\n      border: 1px solid var(--line);\r\n      border-radius: 10px;\r\n      background: #fff;\r\n    }\r\n\r\n    #fotostatistik-owl tr.hidden { display: none; }\r\n    #fotostatistik-owl tr:hover td { background: #faf8f3; }\r\n    #fotostatistik-owl .empty-note { color: var(--muted); font-size: 13px; }\r\n  <\/style>\r\n\r\n  <div class=\"wrap\">\r\n    <h1>Fotostatistik OWL<\/h1>\r\n    <div class=\"sub\" id=\"fs-subline\">Kalenderdaten werden geladen\u2026<\/div>\r\n    <div class=\"status\" id=\"fs-status\">Kalender wird \u00fcber WordPress geladen\u2026<\/div>\r\n\r\n    <div class=\"kpi-grid\" id=\"fs-kpis\">\r\n      <div class=\"kpi\"><div class=\"num\">\u2013<\/div><div class=\"lbl\">Foto-Termine gesamt<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">\u2013<\/div><div class=\"lbl\">Vereine fotografiert<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">\u2013<\/div><div class=\"lbl\">Altersklassen abgedeckt<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">\u2013<\/div><div class=\"lbl\">Top-Verein<\/div><\/div>\r\n    <\/div>\r\n\r\n    <div class=\"grid\">\r\n      <div class=\"card\">\r\n        <h2>Vereine \u2014 sortiert nach Anzahl Termine, mit Altersklassen<\/h2>\r\n        <div class=\"legend\">\r\n          <span class=\"legend-item\"><span class=\"legend-swatch warm\"><\/span> aktiv (letzter Termin innerhalb 8 Wochen)<\/span>\r\n          <span class=\"legend-item\"><span class=\"legend-swatch cold\"><\/span> l\u00e4nger her (letzter Termin l\u00e4nger als 8 Wochen her)<\/span>\r\n          <span class=\"legend-item\" style=\"margin-left:auto\"><b id=\"fs-coldTotal\">0<\/b>&nbsp;\u201el\u00e4nger her\u201c-Altersklassen insgesamt<\/span>\r\n        <\/div>\r\n        <div id=\"fs-clubsList\"><div class=\"empty-note\">Wird geladen\u2026<\/div><\/div>\r\n      <\/div>\r\n\r\n      <div class=\"card\">\r\n        <h2>Top Altersklassen<\/h2>\r\n        <div id=\"fs-agesList\"><div class=\"empty-note\">Wird geladen\u2026<\/div><\/div>\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <div class=\"card\" style=\"margin-bottom: 28px;\">\r\n      <h2>Termine pro Monat<\/h2>\r\n      <div class=\"month-row\" id=\"fs-monthsList\"><div class=\"empty-note\">Wird geladen\u2026<\/div><\/div>\r\n    <\/div>\r\n\r\n    <div class=\"card\">\r\n      <h2 id=\"fs-tableHeadline\">Alle Termine \u2014 neueste zuerst<\/h2>\r\n      <div class=\"search-box\">\r\n        <input id=\"fs-search\" type=\"text\" placeholder=\"Filtern: Verein, Altersklasse oder Datum (z.B. 2026-04, Theesen, U15)\u2026\">\r\n        <button id=\"fs-resetBtn\" type=\"button\">Reset<\/button>\r\n        <span class=\"info\" id=\"fs-info\">0 Termine<\/span>\r\n      <\/div>\r\n      <div class=\"table-wrap\">\r\n        <table>\r\n          <thead>\r\n            <tr><th>Datum<\/th><th>Verein(e)<\/th><th>Altersklasse<\/th><th>Originaltitel<\/th><\/tr>\r\n          <\/thead>\r\n          <tbody id=\"fs-tbody\"><\/tbody>\r\n        <\/table>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<script>\r\n(function() {\r\n  const root = document.getElementById('fotostatistik-owl');\r\n  if (!root || root.dataset.initialized === '1') return;\r\n  root.dataset.initialized = '1';\r\n\r\n  const WP_PROXY_URL = \"\/wp-json\/blickpunkt\/v1\/fotostatistik-ics\";\r\n  const COLD_WEEKS = 8;\r\n  const MONTHS_DE = [\"Jan\", \"Feb\", \"M\u00e4r\", \"Apr\", \"Mai\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Okt\", \"Nov\", \"Dez\"];\r\n\r\n  const CLUB_CANON = [\r\n    { canon: \"VfR Wellensiek\", aliases: [\"vfr wellensiek\", \"wellensiek\"] },\r\n    { canon: \"VfB Fichte Bielefeld\", aliases: [\"vfb fichte bielefeld\", \"vfb fichte\", \"fichte\"] },\r\n    { canon: \"SV Heepen\", aliases: [\"sv heepen\", \"spvg heepen\"] },\r\n    { canon: \"VfL Theesen\", aliases: [\"vfl theesen\"] },\r\n    { canon: \"TuS J\u00f6llenbeck\", aliases: [\"tus j\u00f6llenbeck\", \"jollenbeck\", \"j\u00f6llenbeck\"] },\r\n    { canon: \"TuS Quelle\", aliases: [\"tus quelle\", \"quelle\"] },\r\n    { canon: \"TuS Dornberg\", aliases: [\"tus dornberg\", \"dornberg\"] },\r\n    { canon: \"TuS Eintracht Bielefeld\", aliases: [\"tus eintracht bielefeld\", \"tus eintracht\"] },\r\n    { canon: \"SV Ubbedissen\", aliases: [\"sv ubbedissen 09\", \"sv ubbedissen\"] },\r\n    { canon: \"TuS Ost\", aliases: [\"tus ost\"] },\r\n    { canon: \"SC Halle\", aliases: [\"sc halle\"] },\r\n    { canon: \"VfL Schildesche\", aliases: [\"vfl schildesche\"] },\r\n    { canon: \"FC G\u00fctersloh\", aliases: [\"fc g\u00fctersloh\", \"fc guetersloh\", \"fc gutersloh\"] },\r\n    { canon: \"SC 04\/26 Bielefeld\", aliases: [\"sc bielefeld 04\/26\", \"sc 04\/26 bielefeld\", \"sc bielefeld\", \"scb\"] },\r\n    { canon: \"SC Peckeloh\", aliases: [\"sc peckeloh\", \"jsg peckeloh\"] },\r\n    { canon: \"Spvg. Steinhagen\", aliases: [\"spvg. steinhagen\", \"spvg steinhagen\", \"steinhagen\", \"turksportsteinhagen\", \"t\u00fcrksportsteinhagen\"] },\r\n    { canon: \"SC Verl\", aliases: [\"sc verl\"] },\r\n    { canon: \"TuS Hoberge-Uerentrup\", aliases: [\"tus hoberge-uerentrup\", \"hoberge uerentrup\"] },\r\n    { canon: \"TuS Einigkeit Hillegossen\", aliases: [\"tus hillegossen\", \"tus einigkeit hillegossen\", \"hillegossen\"] },\r\n    { canon: \"SV Spexard\", aliases: [\"sv spexard\"] },\r\n    { canon: \"VfL Oldentrup\", aliases: [\"vfl oldentrup\"] },\r\n    { canon: \"TV Friesen Milse\", aliases: [\"tv friesen milse\"] },\r\n    { canon: \"BV Werther\", aliases: [\"bv werther\", \"werther\"] },\r\n    { canon: \"TuS Langenheide\", aliases: [\"tus langenheide\"] },\r\n    { canon: \"SV Avenwedde\", aliases: [\"sv avenwedde\"] },\r\n    { canon: \"TG H\u00f6rste\", aliases: [\"tg h\u00f6rste\", \"tg hoerste\"] },\r\n    { canon: \"Arminia Bielefeld\", aliases: [\"arminia bielefeld\", \"traditionself arminia\", \"dsc arminia bielefeld\"] },\r\n    { canon: \"Borussia Dortmund\", aliases: [\"borussia dortmund\"] },\r\n    { canon: \"FC Schalke 04\", aliases: [\"fc schalke 04\"] },\r\n    { canon: \"SC Wiedenbr\u00fcck\", aliases: [\"sc wiedenbr\u00fcck\", \"sc wiedenbruck\"] },\r\n    { canon: \"TuS Senne\", aliases: [\"tus senne\", \"tus 08 senne i\", \"tus 08 senn i\"] },\r\n    { canon: \"SuK Canlar Bielefeld\", aliases: [\"suk canlar bielefeld\"] },\r\n    { canon: \"Brakel\", aliases: [\"brakel\"] },\r\n    { canon: \"Ummeln\", aliases: [\"ummeln\", \"vfl ummeln\"] },\r\n    { canon: \"H\u00f6velhofer SV\", aliases: [\"h\u00f6velhofer sv\", \"hoevelhofer sv\"] },\r\n    { canon: \"SV Heide Paderborn\", aliases: [\"sv heide paderborn\"] },\r\n    { canon: \"JSG FC L\u00fcbbecke \/ L\u00fcbbecker Land\", aliases: [\"jsg fc l\u00fcbbecke\", \"jsg fc luebbecke\", \"l\u00fcbbecker land\", \"lubbecker land\"] },\r\n    { canon: \"Nordkirchen\", aliases: [\"nordkirchen\"] },\r\n    { canon: \"Victoria Clarholz\", aliases: [\"victoria clarholz\"] },\r\n    { canon: \"Blau-Wei\u00df 98 G\u00fctersloh\", aliases: [\"blau wei\u00df 98 g\u00fctersloh\", \"blau weiss 98 g\u00fctersloh\", \"bw 98 g\u00fctersloh\", \"bw 98 gutersloh\"] },\r\n    { canon: \"B\u00fcnder SV\", aliases: [\"b\u00fcnder sv\", \"buender sv\"] },\r\n    { canon: \"SSV Bauer 07\/28\", aliases: [\"ssv bauer 07\/28\"] },\r\n    { canon: \"RW Kirchlengern\", aliases: [\"rw kirchlengern\"] },\r\n    { canon: \"Westfalia Soest\", aliases: [\"westfalia soest\"] },\r\n    { canon: \"JSG Quelle \/ Gadderbaum\", aliases: [\"jsg quelle \/ gadderbaum\", \"jsg quelle\"] },\r\n    { canon: \"VfL Sportfreunde Lotte\", aliases: [\"vfl sportfreunde lotte\"] },\r\n    { canon: \"Schlo\u00df Holte\", aliases: [\"schloss holte\", \"schlo\u00df holte\"] },\r\n    { canon: \"Lippstadt\", aliases: [\"lippstadt\"] },\r\n    { canon: \"SV Oelde\", aliases: [\"sv oelde\"] },\r\n    { canon: \"SG Wattenscheid 09\", aliases: [\"sg wattenscheid 09\"] }\r\n  ];\r\n\r\n  const IGNORE_SUMMARY_PATTERNS = [\r\n    \/^test\\b\/i,\r\n    \/\\btestverein\\b\/i,\r\n    \/\\btesthausen\\b\/i,\r\n    \/\\bjhv\\b\/i,\r\n    \/\\btagespraktika\\b\/i,\r\n    \/\\bvorstand\\b\/i,\r\n    \/^pokalfinale$\/i,\r\n    \/^kick for ref!?$\/i,\r\n    \/^auslosung\\b\/i\r\n  ];\r\n\r\n  const AGE_ORDER = {\r\n    \"U7\": 7, \"U8\": 8, \"U9\": 9, \"U10\": 10, \"U11\": 11, \"U12\": 12, \"U13\": 13, \"U14\": 14,\r\n    \"U15\": 15, \"U16\": 16, \"U17\": 17, \"U19\": 19,\r\n    \"Herren\": 100, \"Frauen\": 101, \"Turnier\": 110, \"U15 Frauen\": 111\r\n  };\r\n\r\n  const state = { rows: [], total: 0 };\r\n\r\n  function escapeHtml(v) {\r\n    return String(v ?? \"\")\r\n      .replace(\/&\/g, \"&amp;\")\r\n      .replace(\/<\/g, \"&lt;\")\r\n      .replace(\/>\/g, \"&gt;\")\r\n      .replace(\/\"\/g, \"&quot;\");\r\n  }\r\n\r\n  function normalizeText(v) {\r\n    return String(v || \"\")\r\n      .toLowerCase()\r\n      .normalize(\"NFD\").replace(\/[\\u0300-\\u036f]\/g, \"\")\r\n      .replace(\/\u00df\/g, \"ss\")\r\n      .replace(\/[()'\"]\/g, \" \")\r\n      .replace(\/[\u2013\u2014]\/g, \"-\")\r\n      .replace(\/\\s+\/g, \" \")\r\n      .trim();\r\n  }\r\n\r\n  function decodeICSValue(value) {\r\n    return String(value || \"\")\r\n      .replace(\/\\\\,\/g, \",\")\r\n      .replace(\/\\\\;\/g, \";\")\r\n      .replace(\/\\\\n\/gi, \"\\n\")\r\n      .replace(\/\\\\\\\\\/g, \"\\\\\");\r\n  }\r\n\r\n  async function fetchICSViaWordPress() {\r\n    const res = await fetch(WP_PROXY_URL, {\r\n      method: \"GET\",\r\n      cache: \"no-store\",\r\n      credentials: \"same-origin\"\r\n    });\r\n\r\n    if (!res.ok) throw new Error(`HTTP ${res.status}`);\r\n\r\n    const data = await res.json();\r\n\r\n    if (!data || !data.success || !data.ics) {\r\n      throw new Error(data?.message || \"Ung\u00fcltige Proxy-Antwort\");\r\n    }\r\n\r\n    return data.ics;\r\n  }\r\n\r\n  function parseICSText(icsText) {\r\n    const unfolded = String(icsText || \"\").replace(\/\\r\\n[ \\t]\/g, \"\").replace(\/\\n[ \\t]\/g, \"\");\r\n    const lines = unfolded.split(\/\\r?\\n\/);\r\n    const events = [];\r\n    let event = null;\r\n\r\n    for (const line of lines) {\r\n      if (line === \"BEGIN:VEVENT\") { event = {}; continue; }\r\n      if (line === \"END:VEVENT\") { if (event) events.push(event); event = null; continue; }\r\n      if (!event) continue;\r\n\r\n      const idx = line.indexOf(\":\");\r\n      if (idx === -1) continue;\r\n\r\n      const rawKey = line.slice(0, idx);\r\n      const key = rawKey.split(\";\")[0].toUpperCase();\r\n      const value = line.slice(idx + 1);\r\n\r\n      if (!event[key]) event[key] = value;\r\n    }\r\n\r\n    return events;\r\n  }\r\n\r\n  function parseICSDate(value) {\r\n    if (!value) return null;\r\n    const pure = value.replace(\/Z$\/, \"\");\r\n\r\n    if (\/^\\d{8}$\/.test(pure)) {\r\n      return new Date(+pure.slice(0,4), +pure.slice(4,6)-1, +pure.slice(6,8));\r\n    }\r\n\r\n    if (\/^\\d{8}T\\d{6}$\/.test(pure)) {\r\n      return new Date(\r\n        +pure.slice(0,4),\r\n        +pure.slice(4,6)-1,\r\n        +pure.slice(6,8),\r\n        +pure.slice(9,11),\r\n        +pure.slice(11,13),\r\n        +pure.slice(13,15)\r\n      );\r\n    }\r\n\r\n    return null;\r\n  }\r\n\r\n  function formatDateDE(d) {\r\n    return `${String(d.getDate()).padStart(2,\"0\")}.${String(d.getMonth()+1).padStart(2,\"0\")}.${d.getFullYear()}`;\r\n  }\r\n\r\n  function formatISODate(d) {\r\n    return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,\"0\")}-${String(d.getDate()).padStart(2,\"0\")}`;\r\n  }\r\n\r\n  function canonicalClubName(raw) {\r\n    const n = normalizeText(raw)\r\n      .replace(\/\\bii+\\b\/g, \"\")\r\n      .replace(\/\\biii+\\b\/g, \"\")\r\n      .replace(\/\\b1\\b\/g, \"\")\r\n      .replace(\/\\b2\\b\/g, \"\")\r\n      .replace(\/\\s+\/g, \" \")\r\n      .trim();\r\n\r\n    for (const entry of CLUB_CANON) {\r\n      if (entry.aliases.some(a => n === normalizeText(a) || n.includes(normalizeText(a)))) {\r\n        return entry.canon;\r\n      }\r\n    }\r\n\r\n    return raw.replace(\/\\s+\/g, \" \").trim();\r\n  }\r\n\r\n  function extractAge(summary, description = \"\") {\r\n    const text = `${summary} ${description}`;\r\n\r\n    if (\/\\bU15\\s*Frauen\\b\/i.test(text) || \/\\bU15w\\b\/i.test(text)) return \"U15 Frauen\";\r\n\r\n    const ageMatch = text.match(\/\\bU\\s?(\\d{1,2})\\b\/i);\r\n    if (ageMatch) return `U${ageMatch[1]}`;\r\n\r\n    if (\/\\bHerren\\b\/i.test(text) || \/\\bDamen\\b\/i.test(text)) return \/\\bDamen\\b\/i.test(text) ? \"Frauen\" : \"Herren\";\r\n    if (\/\\bFrauen\\b\/i.test(text)) return \"Frauen\";\r\n    if (\/\\bTurnier\\b\/i.test(text) || \/\\bHallenturnier\\b\/i.test(text)) return \"Turnier\";\r\n    return \"\";\r\n  }\r\n\r\n  function extractCompetition(summary, description = \"\") {\r\n    const text = `${summary} ${description}`;\r\n    if (\/\\bPokal\\b\/i.test(text) || \/\\bWestfalenpokal\\b\/i.test(text)) return \"Pokal\";\r\n    if (\/\\bTurnier\\b\/i.test(text) || \/\\bHallenturnier\\b\/i.test(text) || \/\\bCup\\b\/i.test(text)) return \"Turnier\";\r\n    return \"\";\r\n  }\r\n\r\n  function shouldIgnoreEvent(summary) {\r\n    return IGNORE_SUMMARY_PATTERNS.some(rx => rx.test(summary.trim()));\r\n  }\r\n\r\n  function cleanSummaryForClubParsing(summary) {\r\n    return summary\r\n      .replace(\/^Vorschlag:\\s*\/i, \"\")\r\n      .replace(\/^Vorschalg:\\s*\/i, \"\")\r\n      .replace(\/^Buchung\\s*\/i, \"\")\r\n      .replace(\/^Fototermin\\s*\/i, \"\")\r\n      .replace(\/^Pokal\\s+\/i, \"\")\r\n      .replace(\/^Flutlichtspiel\\s+\/i, \"\")\r\n      .replace(\/\\b(U15 Frauen|U\\d{1,2}|Herren|Frauen|Damen|Turnier|Hallenturnier)\\b\/gi, \"\")\r\n      .replace(\/\\((?:w)\\)\/gi, \"\")\r\n      .replace(\/\\s+\/g, \" \")\r\n      .trim();\r\n  }\r\n\r\n  function extractClubs(summary) {\r\n    const cleaned = cleanSummaryForClubParsing(summary);\r\n    const norm = normalizeText(cleaned);\r\n    const hits = [];\r\n\r\n    for (const entry of CLUB_CANON) {\r\n      for (const alias of entry.aliases) {\r\n        const a = normalizeText(alias);\r\n        if (norm.includes(a)) {\r\n          if (!hits.includes(entry.canon)) hits.push(entry.canon);\r\n          break;\r\n        }\r\n      }\r\n    }\r\n\r\n    if (hits.length >= 2) return hits.slice(0, 2);\r\n\r\n    const split = cleaned.split(\/\\s*-\\s*\/).map(v => v.trim()).filter(Boolean);\r\n    if (split.length >= 2) {\r\n      const clubs = split.slice(0, 2).map(canonicalClubName).filter(Boolean);\r\n      return [...new Set(clubs)].slice(0, 2);\r\n    }\r\n\r\n    if (hits.length === 1) return hits;\r\n    return [];\r\n  }\r\n\r\n  function weeksAgo(dateObj, reference = new Date()) {\r\n    const diffMs = reference.getTime() - dateObj.getTime();\r\n    return Math.floor(diffMs \/ (1000 * 60 * 60 * 24 * 7));\r\n  }\r\n\r\n  function ageSortValue(age) {\r\n    return AGE_ORDER[age] ?? 999;\r\n  }\r\n\r\n  function monthDiff(from, to) {\r\n    return (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth());\r\n  }\r\n\r\n  function buildMonthRange(dates) {\r\n    if (!dates.length) return [];\r\n    const sorted = [...dates].sort((a, b) => a - b);\r\n    const start = new Date(sorted[0].getFullYear(), sorted[0].getMonth(), 1);\r\n    const end = new Date(sorted[sorted.length - 1].getFullYear(), sorted[sorted.length - 1].getMonth(), 1);\r\n    const total = monthDiff(start, end);\r\n    const result = [];\r\n\r\n    for (let i = 0; i <= total; i++) {\r\n      const current = new Date(start.getFullYear(), start.getMonth() + i, 1);\r\n      result.push({\r\n        key: `${current.getFullYear()}-${String(current.getMonth()+1).padStart(2,\"0\")}`,\r\n        label: `${MONTHS_DE[current.getMonth()]} ${String(current.getFullYear()).slice(2)}`,\r\n        count: 0\r\n      });\r\n    }\r\n\r\n    return result;\r\n  }\r\n\r\n  function buildEvents(rawEvents) {\r\n    return rawEvents.map(item => {\r\n      const summary = decodeICSValue(item.SUMMARY || \"\").trim();\r\n      const description = decodeICSValue(item.DESCRIPTION || \"\").trim();\r\n      const dateObj = parseICSDate(item.DTSTART);\r\n\r\n      if (!summary || !dateObj) return null;\r\n      if (shouldIgnoreEvent(summary)) return null;\r\n\r\n      const age = extractAge(summary, description);\r\n      const competition = extractCompetition(summary, description);\r\n      const clubs = extractClubs(summary);\r\n\r\n      return {\r\n        summary,\r\n        description,\r\n        dateObj,\r\n        dateDe: formatDateDE(dateObj),\r\n        isoDate: formatISODate(dateObj),\r\n        age,\r\n        competition,\r\n        clubs,\r\n        clubsSearch: clubs.join(\" | \").toLowerCase()\r\n      };\r\n    })\r\n    .filter(Boolean)\r\n    .sort((a, b) => b.dateObj - a.dateObj);\r\n  }\r\n\r\n  function buildStats(events) {\r\n    const now = new Date();\r\n    const clubMap = new Map();\r\n    const ageMap = new Map();\r\n    const monthMap = new Map();\r\n\r\n    const months = buildMonthRange(events.map(e => e.dateObj));\r\n    months.forEach(m => monthMap.set(m.key, m));\r\n\r\n    for (const event of events) {\r\n      if (event.age) ageMap.set(event.age, (ageMap.get(event.age) || 0) + 1);\r\n\r\n      const monthKey = `${event.dateObj.getFullYear()}-${String(event.dateObj.getMonth()+1).padStart(2,\"0\")}`;\r\n      if (monthMap.has(monthKey)) monthMap.get(monthKey).count += 1;\r\n\r\n      for (const club of event.clubs) {\r\n        if (!clubMap.has(club)) clubMap.set(club, { count: 0, ages: new Map() });\r\n        const entry = clubMap.get(club);\r\n        entry.count += 1;\r\n\r\n        if (event.age) {\r\n          if (!entry.ages.has(event.age)) entry.ages.set(event.age, { count: 0, lastDate: null });\r\n          const ageEntry = entry.ages.get(event.age);\r\n          ageEntry.count += 1;\r\n          if (!ageEntry.lastDate || event.dateObj > ageEntry.lastDate) ageEntry.lastDate = event.dateObj;\r\n        }\r\n      }\r\n    }\r\n\r\n    let totalLongerHerAges = 0;\r\n\r\n    const clubRanking = [...clubMap.entries()].map(([name, data]) => {\r\n      const ages = [...data.ages.entries()]\r\n        .map(([age, meta]) => {\r\n          const diffWeeks = weeksAgo(meta.lastDate, now);\r\n          const isCold = diffWeeks > COLD_WEEKS;\r\n          if (isCold) totalLongerHerAges += 1;\r\n          return {\r\n            age,\r\n            count: meta.count,\r\n            lastDate: meta.lastDate,\r\n            lastDateDe: formatDateDE(meta.lastDate),\r\n            lastDiffText: diffWeeks < 5 ? `${diffWeeks} W.` : `${Math.floor(diffWeeks \/ 4)} Mon.`,\r\n            isCold\r\n          };\r\n        })\r\n        .sort((a, b) => b.count - a.count || ageSortValue(a.age) - ageSortValue(b.age));\r\n\r\n      return {\r\n        name,\r\n        count: data.count,\r\n        ages,\r\n        longerHerCount: ages.filter(a => a.isCold).length\r\n      };\r\n    }).sort((a, b) => b.count - a.count || a.name.localeCompare(b.name, \"de\"));\r\n\r\n    const ageRanking = [...ageMap.entries()]\r\n      .map(([age, count]) => ({ age, count }))\r\n      .sort((a, b) => b.count - a.count || ageSortValue(a.age) - ageSortValue(b.age));\r\n\r\n    const topClub = clubRanking[0] || null;\r\n\r\n    return {\r\n      totalAppointments: events.length,\r\n      totalClubs: clubRanking.length,\r\n      totalAges: ageRanking.length,\r\n      topClubName: topClub ? topClub.name : \"\u2013\",\r\n      topClubCount: topClub ? topClub.count : 0,\r\n      totalLongerHerAges,\r\n      clubRanking,\r\n      ageRanking,\r\n      months: [...monthMap.values()]\r\n    };\r\n  }\r\n\r\n  function renderKpis(stats) {\r\n    root.querySelector(\"#fs-kpis\").innerHTML = `\r\n      <div class=\"kpi\"><div class=\"num\">${stats.totalAppointments}<\/div><div class=\"lbl\">Foto-Termine gesamt<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">${stats.totalClubs}<\/div><div class=\"lbl\">Vereine fotografiert<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">${stats.totalAges}<\/div><div class=\"lbl\">Altersklassen abgedeckt<\/div><\/div>\r\n      <div class=\"kpi\"><div class=\"num\">${stats.topClubCount}<\/div><div class=\"lbl\">Top-Verein: ${escapeHtml(stats.topClubName)}<\/div><\/div>\r\n    `;\r\n  }\r\n\r\n  function renderClubs(stats) {\r\n    const list = root.querySelector(\"#fs-clubsList\");\r\n    root.querySelector(\"#fs-coldTotal\").textContent = stats.totalLongerHerAges;\r\n\r\n    if (!stats.clubRanking.length) {\r\n      list.innerHTML = `<div class=\"empty-note\">Keine Vereinsdaten gefunden.<\/div>`;\r\n      return;\r\n    }\r\n\r\n    const max = stats.clubRanking[0].count || 1;\r\n\r\n    list.innerHTML = stats.clubRanking.map((club, index) => {\r\n      const pills = club.ages.map(age => {\r\n        const cold = age.isCold ? \" cold\" : \"\";\r\n        const title = `Letzter Termin ${age.lastDateDe} \u00b7 vor ${age.lastDiffText}`;\r\n        return `<span class=\"age-pill${cold}\" title=\"${escapeHtml(title)}\"><b>${escapeHtml(age.age)}<\/b><span class=\"pill-count\">${age.count}<\/span><\/span>`;\r\n      }).join(\"\");\r\n\r\n      const longerHerBadge = club.longerHerCount > 0\r\n        ? `<span class=\"cold-badge\" title=\"Altersklassen, die seit \u00fcber 8 Wochen nicht fotografiert wurden\">${club.longerHerCount} l\u00e4nger her<\/span>`\r\n        : \"\";\r\n\r\n      return `\r\n        <div class=\"club-card\">\r\n          <div class=\"club-head\">\r\n            <span class=\"club-rank\">#${index + 1}<\/span>\r\n            <span class=\"club-name\">${escapeHtml(club.name)}<\/span>\r\n            ${longerHerBadge}\r\n            <span class=\"club-count\">${club.count} Termine<\/span>\r\n          <\/div>\r\n          <div class=\"bar-track\"><div class=\"bar-fill\" style=\"width:${Math.max(4, Math.round(club.count \/ max * 100))}%\"><\/div><\/div>\r\n          <div class=\"age-pills\">${pills}<\/div>\r\n        <\/div>\r\n      `;\r\n    }).join(\"\");\r\n  }\r\n\r\n  function renderAges(stats) {\r\n    const list = root.querySelector(\"#fs-agesList\");\r\n    if (!stats.ageRanking.length) {\r\n      list.innerHTML = `<div class=\"empty-note\">Keine Altersklassen erkannt.<\/div>`;\r\n      return;\r\n    }\r\n\r\n    const max = stats.ageRanking[0].count || 1;\r\n    list.innerHTML = stats.ageRanking.map(item => `\r\n      <div class=\"bar-row\">\r\n        <div class=\"bar-label\">${escapeHtml(item.age)} <span class=\"age-num\">${item.count}<\/span><\/div>\r\n        <div class=\"bar-track\"><div class=\"bar-fill alt\" style=\"width:${Math.max(2, Math.round(item.count \/ max * 100))}%\"><\/div><\/div>\r\n      <\/div>\r\n    `).join(\"\");\r\n  }\r\n\r\n  function renderMonths(stats) {\r\n    const list = root.querySelector(\"#fs-monthsList\");\r\n    if (!stats.months.length) {\r\n      list.innerHTML = `<div class=\"empty-note\">Keine Monatsdaten vorhanden.<\/div>`;\r\n      return;\r\n    }\r\n\r\n    const max = Math.max(...stats.months.map(m => m.count), 1);\r\n    list.innerHTML = stats.months.map(item => `\r\n      <div class=\"month-bar\">\r\n        <div class=\"month-count\">${item.count}<\/div>\r\n        <div class=\"month-fill\" style=\"height:${item.count ? Math.max(6, Math.round(item.count \/ max * 100)) : 4}%\"><\/div>\r\n        <div class=\"month-label\">${escapeHtml(item.label)}<\/div>\r\n      <\/div>\r\n    `).join(\"\");\r\n  }\r\n\r\n  function renderTable(events) {\r\n    const tbody = root.querySelector(\"#fs-tbody\");\r\n    root.querySelector(\"#fs-tableHeadline\").textContent = `Alle Termine (${events.length}) \u2014 neueste zuerst`;\r\n\r\n    tbody.innerHTML = events.map(event => {\r\n      const clubsText = event.clubs.length ? event.clubs.map(escapeHtml).join(\" \u00b7 \") : `<span class=\"muted\">\u2014<\/span>`;\r\n      const agePill = event.age ? `<span class=\"age-pill\">${escapeHtml(event.age)}<\/span>` : \"\";\r\n      const compPill = event.competition ? ` <span class=\"comp-pill\">${escapeHtml(event.competition)}<\/span>` : \"\";\r\n\r\n      return `\r\n        <tr data-date=\"${escapeHtml(event.isoDate)}\" data-clubs=\"${escapeHtml(event.clubsSearch)}\" data-age=\"${escapeHtml(event.age.toLowerCase())}\">\r\n          <td class=\"date\">${escapeHtml(event.dateDe)}<\/td>\r\n          <td class=\"clubs\">${clubsText}<\/td>\r\n          <td class=\"age\">${agePill}${compPill}<\/td>\r\n          <td class=\"summary\">${escapeHtml(event.summary)}<\/td>\r\n        <\/tr>\r\n      `;\r\n    }).join(\"\");\r\n\r\n    state.rows = Array.from(root.querySelectorAll(\"#fs-tbody tr\"));\r\n    state.total = state.rows.length;\r\n    filterRows();\r\n  }\r\n\r\n  function filterRows() {\r\n    const q = root.querySelector(\"#fs-search\").value.trim().toLowerCase();\r\n    let visible = 0;\r\n\r\n    state.rows.forEach(row => {\r\n      const haystack = (row.dataset.date + \" \" + row.dataset.clubs + \" \" + row.dataset.age + \" \" + row.textContent).toLowerCase();\r\n      const match = !q || haystack.includes(q);\r\n      row.classList.toggle(\"hidden\", !match);\r\n      if (match) visible++;\r\n    });\r\n\r\n    root.querySelector(\"#fs-info\").textContent = q ? `${visible} von ${state.total} Terminen` : `${state.total} Termine`;\r\n  }\r\n\r\n  async function loadCalendar() {\r\n    const status = root.querySelector(\"#fs-status\");\r\n    const subline = root.querySelector(\"#fs-subline\");\r\n\r\n    try {\r\n      status.textContent = \"Kalender wird \u00fcber WordPress geladen\u2026\";\r\n\r\n      const text = await fetchICSViaWordPress();\r\n      const rawEvents = parseICSText(text);\r\n      const events = buildEvents(rawEvents);\r\n      const stats = buildStats(events);\r\n\r\n      renderKpis(stats);\r\n      renderClubs(stats);\r\n      renderAges(stats);\r\n      renderMonths(stats);\r\n      renderTable(events);\r\n\r\n      const oldest = events.length ? events[events.length - 1].dateDe : \"\u2013\";\r\n      const newest = events.length ? events[0].dateDe : \"\u2013\";\r\n      subline.textContent = `Best\u00e4tigte Foto-Termine seit ${oldest} \u00b7 Stand ${newest} \u00b7 Blickpunkt Lokalsport`;\r\n      status.textContent = `Kalender erfolgreich \u00fcber WordPress geladen \u00b7 ${events.length} Termine verarbeitet`;\r\n      status.classList.remove(\"error\");\r\n      status.classList.add(\"ok\");\r\n    } catch (err) {\r\n      console.error(err);\r\n      status.textContent = \"Kalender konnte nicht \u00fcber den WordPress-Proxy geladen werden.\";\r\n      status.classList.remove(\"ok\");\r\n      status.classList.add(\"error\");\r\n      root.querySelector(\"#fs-clubsList\").innerHTML = `<div class=\"empty-note\">Keine Daten geladen.<\/div>`;\r\n      root.querySelector(\"#fs-agesList\").innerHTML = `<div class=\"empty-note\">Keine Daten geladen.<\/div>`;\r\n      root.querySelector(\"#fs-monthsList\").innerHTML = `<div class=\"empty-note\">Keine Daten geladen.<\/div>`;\r\n      root.querySelector(\"#fs-tbody\").innerHTML = \"\";\r\n      root.querySelector(\"#fs-info\").textContent = \"0 Termine\";\r\n    }\r\n  }\r\n\r\n  root.querySelector(\"#fs-search\").addEventListener(\"input\", filterRows);\r\n  root.querySelector(\"#fs-resetBtn\").addEventListener(\"click\", () => {\r\n    root.querySelector(\"#fs-search\").value = \"\";\r\n    filterRows();\r\n  });\r\n\r\n  loadCalendar();\r\n})();\r\n<\/script>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Fotostatistik OWL Kalenderdaten werden geladen\u2026 Kalender wird \u00fcber WordPress geladen\u2026 \u2013Foto-Termine gesamt \u2013Vereine fotografiert \u2013Altersklassen abgedeckt \u2013Top-Verein Vereine \u2014 sortiert nach Anzahl Termine, mit Altersklassen aktiv (letzter Termin innerhalb 8 Wochen) l\u00e4nger her (letzter Termin l\u00e4nger als 8 Wochen her) 0&nbsp;\u201el\u00e4nger her\u201c-Altersklassen insgesamt Wird geladen\u2026 Top Altersklassen Wird geladen\u2026 Termine pro Monat Wird geladen\u2026 Alle &#8230; <a title=\"Statistikbg\" class=\"read-more\" href=\"https:\/\/blickpunkt-lokalsport.de\/english\/statistikbg\/\" aria-label=\"Read more about Statistikbg\">Read more<\/a><\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-52854","page","type-page","status-publish"],"acf":[],"_links":{"self":[{"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/pages\/52854","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/comments?post=52854"}],"version-history":[{"count":10,"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/pages\/52854\/revisions"}],"predecessor-version":[{"id":53677,"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/pages\/52854\/revisions\/53677"}],"wp:attachment":[{"href":"https:\/\/blickpunkt-lokalsport.de\/english\/wp-json\/wp\/v2\/media?parent=52854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}