{"id":512,"date":"2026-05-07T12:07:40","date_gmt":"2026-05-07T10:07:40","guid":{"rendered":"https:\/\/flyaerolloydvirtual.com\/?page_id=512"},"modified":"2026-05-07T12:07:40","modified_gmt":"2026-05-07T10:07:40","slug":"live-map","status":"publish","type":"page","link":"https:\/\/flyaerolloydvirtual.com\/de\/live-map\/","title":{"rendered":"Live Map"},"content":{"rendered":"\n<div id=\"aeroLiveWrap\" style=\"font-family:'Segoe UI',Arial,sans-serif;max-width:1600px;margin:0 auto;padding:0 24px;\">\n\n<style>\n\/* \u2500\u2500 Stabile Scrollleiste \u2500\u2500 Live-Updates (FIDS\/Positionen) aendern die\n   Inhaltshoehe minimal; ohne feste Scrollleiste erscheint\/verschwindet sie\n   und die ganze Seite springt seitlich um deren Breite (\"wackeln\").\n   Eine immer reservierte Scrollleiste verhindert das komplett. *\/\nhtml { overflow-y: scroll !important; scrollbar-gutter: stable; }\n\n\/* \u2500\u2500 Header z-index fix \u2014 Leaflet panes use z-index up to 1000; ensure\n   the site header and its dropdowns always render above the map \u2500\u2500 *\/\n.site-header, #masthead { position: relative; z-index: 9999 !important; }\n\n\/* \u2500\u2500 MAP \u2500\u2500 *\/\n#aeroMapWrap{position:relative;border-radius:10px;overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,.4);margin-bottom:24px;}\n#aeroMapBar{background:linear-gradient(135deg,#2D297A,#1a1836);padding:11px 20px;display:flex;justify-content:space-between;align-items:center;}\n#aeroMapBar .bar-l{display:flex;align-items:center;gap:14px;}\n#aeroMapBar .bar-title{color:#fff;font-size:15px;font-weight:700;letter-spacing:.5px;}\n#aeroMapBar .bar-sub{color:#8A90C0;font-size:11px;margin-top:2px;}\n#aeroMapInfoBox{background:rgba(0,0,0,.65);border-radius:7px;padding:9px 16px;text-align:right;min-width:240px;backdrop-filter:blur(6px);border:1px solid rgba(255,255,255,.07);}\n#mapFlight{color:#F2A900;font-size:17px;font-weight:700;font-family:'Courier New',monospace;}\n#mapRoute{color:#aac4ff;font-size:12px;margin:3px 0;}\n#mapDetail{color:#666;font-size:11px;}\n#aeroMap{height:620px;width:100%;}\n#aeroMapFooter{display:none;}\n\/* Neue Flip-Tafel [aero_fids] unter der Karte exakt so breit wie die Karte\n   (hebt alle Breiten-\/Rand-Begrenzungen der Wrapper NUR hier auf \u2014 Crew Center\n   bleibt unber\u00fchrt). So deckt sich die Tafel 1:1 mit #aeroMapWrap dar\u00fcber. *\/\n.aero-live-board,\n.aero-live-board .aero-ui,\n.aero-live-board .aui-sec{max-width:none !important;width:100% !important;margin:0 !important;padding:0 !important;}\n.aero-live-board{margin-top:20px !important;}\n.aero-live-board #aeroSolari{width:100%;margin:0;}\n\/* Aero-Lloyd-Branding der DAY\/NIGHT-Basiskarte: cleane Light-Gray-Karte in\n   warmes Elfenbein\/Gold get\u00f6nt. Wirkt nur auf diesen einen Kachel-Layer,\n   nicht auf Flieger, Routen, Aurora oder die Terminator-Linie. *\/\n.aol-brandmap{filter:sepia(.35) saturate(.55) hue-rotate(-8deg) brightness(1.05) contrast(.96);}\n#mapStatusDot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#444;margin-right:7px;vertical-align:middle;}\n#mapStatusDot.active{background:#4ade80;box-shadow:0 0 6px #4ade80;animation:pulse 2s infinite;}\n@keyframes pulse{0%,100%{opacity:1;}50%{opacity:.4;}}\n#mapStatusTxt{color:#888;font-size:11px;font-family:'Courier New',monospace;}\n#mapUpdated{color:#555;font-size:10px;font-family:'Courier New',monospace;}\n\n\/* \u2500\u2500 FIDS WRAPPER \u2500\u2500 *\/\n#aeroFIDSWrap{display:grid;grid-template-columns:1fr;gap:20px;}\n\n\/* \u2500\u2500 FIDS BOARD \u2500\u2500 *\/\n.fids{background:#0d0d14;border-radius:10px;overflow:hidden;box-shadow:0 4px 24px rgba(0,0,0,.5);border:1px solid #1a1a2e;}\n.fids-hd{background:#111120;padding:0;border-bottom:3px solid #1a1a2e;}\n.fids-hd-top{display:flex;justify-content:space-between;align-items:center;padding:13px 20px 10px;}\n.fids-hd-label{color:#F2A900;font-size:13px;font-weight:700;letter-spacing:3px;font-family:'Courier New',monospace;}\n.fids-hd-airport{color:#fff;font-size:17px;font-weight:700;font-family:'Courier New',monospace;}\n.fids-hd-time{color:#555;font-size:13px;font-family:'Courier New',monospace;text-align:right;}\n.fids-hd-time span{display:block;color:#888;font-size:11px;}\n.fids-cols-bar{background:#090910;display:grid;padding:6px 20px;font-size:9px;font-weight:700;letter-spacing:.12em;color:#444;font-family:'Courier New',monospace;text-transform:uppercase;}\n.fids-cols-dep{grid-template-columns:90px 1fr 70px 70px 60px 130px;}\n.fids-cols-arr{grid-template-columns:90px 1fr 70px 70px 70px 130px;}\n.fids-rows{max-height:460px;overflow-y:auto;}\n.fids-row{display:grid;padding:11px 20px;border-bottom:1px solid #111;align-items:center;transition:background .15s;}\n.fids-row:hover{background:#0f0f1e;}\n.fids-row-dep{grid-template-columns:90px 1fr 70px 70px 60px 130px;}\n.fids-row-arr{grid-template-columns:90px 1fr 70px 70px 70px 130px;}\n.fids-fn{color:#F2A900;font-weight:700;font-size:13px;font-family:'Courier New',monospace;}\n.fids-cs{color:#3a3a5c;font-size:10px;font-family:'Courier New',monospace;display:block;margin-top:1px;}\n.fids-airport{color:#e0e0ff;font-size:12px;font-family:'Courier New',monospace;font-weight:600;}\n.fids-time{color:#8888aa;font-size:13px;font-family:'Courier New',monospace;}\n.fids-time.actual{color:#fff;}\n.fids-gate{color:#5566aa;font-size:13px;font-family:'Courier New',monospace;font-weight:600;}\n.fids-empty{color:#2a2a3a;text-align:center;padding:30px;font-family:'Courier New',monospace;font-size:12px;letter-spacing:.1em;}\n\n\n@media(max-width:900px){\n    #aeroFIDSWrap{grid-template-columns:1fr;}\n    #aeroMap{height:340px;}\n    .sf-cols,.sf-row{grid-template-columns:16px 80px 55px 100px 45px 1fr 55px 45px 90px;}\n}\n<\/style>\n\n<!-- \u2550\u2550 MAP \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div id=\"aeroMapWrap\">\n    <div id=\"aeroMapBar\">\n        <div class=\"bar-l\">\n            <div>\n                <div class=\"bar-title\">AERO LLOYD VIRTUAL &nbsp;\u00b7&nbsp; LIVE OPERATIONS<\/div>\n                <div class=\"bar-sub\">Real-time Flight Tracking &nbsp;\u00b7&nbsp; 19 Oct 2026<\/div>\n            <\/div>\n        <\/div>\n        <div style=\"display:flex;align-items:center;gap:10px;\">\n            <!-- Map mode toggle -->\n            <div style=\"display:flex;gap:4px;\">\n                <button id=\"btnNight\"\n                    style=\"background:#2D297A;color:#fff;border:none;border-radius:4px;\n                           padding:4px 10px;font-size:10px;font-weight:700;cursor:pointer;\n                           font-family:'Segoe UI',sans-serif;letter-spacing:.05em;\">\n                    NIGHT\n                <\/button>\n                <button id=\"btnTerrain\"\n                    style=\"background:#333;color:#aaa;border:none;border-radius:4px;\n                           padding:4px 10px;font-size:10px;font-weight:700;cursor:pointer;\n                           font-family:'Segoe UI',sans-serif;letter-spacing:.05em;\">\n                    TERRAIN\n                <\/button>\n                <button id=\"btnDayNight\"\n                    style=\"background:#333;color:#aaa;border:none;border-radius:4px;\n                           padding:4px 10px;font-size:10px;font-weight:700;cursor:pointer;\n                           font-family:'Segoe UI',sans-serif;letter-spacing:.05em;\">\n                    DAY\/NIGHT\n                <\/button>\n                <button id=\"btnAurora\"\n                    title=\"Live-Nordlicht-Zonen (NOAA)\"\n                    style=\"background:#333;color:#aaa;border:none;border-radius:4px;\n                           padding:4px 10px;font-size:10px;font-weight:700;cursor:pointer;\n                           font-family:'Segoe UI',sans-serif;letter-spacing:.05em;margin-left:6px;\">\n                    \u2726 AURORA\n                <\/button>\n            <\/div>\n            <div id=\"aeroMapInfoBox\">\n                <div id=\"mapFlight\">\u2014\u2014<\/div>\n                <div id=\"mapRoute\" style=\"color:#8A90C0;\">Awaiting next departure<\/div>\n                <div id=\"mapDetail\">\u2014\u2014<\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n    <div id=\"aeroMap\"><\/div>\n    <div id=\"aeroMapFooter\">\n        <div>\n            <span id=\"mapStatusDot\"><\/span>\n            <span id=\"mapStatusTxt\">No active flight<\/span>\n        <\/div>\n        <div id=\"mapUpdated\">\u2014<\/div>\n    <\/div>\n<\/div>\n\n<!-- \u2550\u2550 NEUE FLIP-TAFEL \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n<div class=\"aero-live-board\" style=\"margin-top:20px;\">    <div class=\"aero-ui\">\n    <section class=\"aui-sec\">\n\n      <div id=\"aeroFidsStandalone\" style=\"font-family:'Segoe UI',Arial,sans-serif;\">\n\n      <style>\n      \/* \u2500\u2500 SOLARI SPLIT-FLAP FLIP BOARD \u2500\u2500 *\/\n      \/* Klassische Palette: Schwarz, Elfenbein (#e9e4d8), gedaempftes Gold (#b89a5e).\n         Farbe nur dort, wo sie etwas bedeutet (Diverted = gedaempftes Rot). *\/\n      #aeroSolari{--sf-font:\"Bahnschrift SemiCondensed\",\"Bahnschrift\",\"DIN Condensed\",\"DIN Alternate\",\"Roboto Condensed\",\"Arial Narrow\",\"DejaVu Sans Condensed\",sans-serif;--sf-white:#f4f4f1;font-family:var(--sf-font);background:#111317;border-radius:6px;overflow:hidden;box-shadow:0 6px 24px rgba(0,0,0,.45);border:1px solid #23262c;border-top:1px solid #3a352a;}\n      #aeroSolariHd{background:#111317;padding:20px 24px 16px;display:flex;justify-content:space-between;align-items:flex-start;gap:16px;border-bottom:1px solid #23262c;}\n      #aeroSolariHd .sf-title{color:#b89a5e;font-size:11px;font-weight:700;letter-spacing:.35em;font-family:var(--sf-font);}\n      #aeroSolariHd .sf-mode{color:#f3f0e8;font-family:var(--sf-font);font-size:22px;font-weight:700;letter-spacing:.18em;margin-top:10px;}\n      #aeroSolariHd .sf-sub{color:#8a867c;font-family:var(--sf-font);font-size:12px;letter-spacing:.03em;margin-top:8px;}\n      #aeroSolariHd .sf-clock{color:#9a968c;font-size:12px;font-weight:700;font-family:var(--sf-font);letter-spacing:.2em;}\n      .sf-ctl{display:flex;gap:10px;justify-content:flex-end;align-items:center;margin-top:12px;}\n      .sf-seg{display:inline-flex;border:1px solid #4a4840;border-radius:4px;overflow:hidden;}\n      .sf-seg button{background:transparent;border:0;font-family:var(--sf-font);font-size:11px;font-weight:700;letter-spacing:.08em;padding:6px 12px;color:#9a968c;cursor:pointer;}\n      .sf-seg button:hover{color:#e9e4d8;}\n      .sf-seg button[aria-pressed=\"true\"]{background:#e9e4d8;color:#15161a;}\n      .sf-snd{background:transparent;border:1px solid #4a4840;border-radius:4px;color:#c9c4b8;padding:4px 8px;cursor:pointer;display:inline-flex;align-items:center;}\n      .sf-snd:hover{color:#f3f0e8;border-color:#7a766c;}\n      .sf-snd svg{width:16px;height:16px;display:block;}\n      \/* Theme-Knopfstile (blauer Hintergrund, Schatten) auf der Tafel neutralisieren *\/\n      #aeroSolari .sf-snd,#aeroSolari .sf-snd:focus,#aeroSolari .sf-snd:active{background:transparent !important;background-image:none !important;box-shadow:none !important;color:#c9c4b8 !important;border:1px solid #4a4840 !important;text-shadow:none !important;}\n      #aeroSolari .sf-snd:hover{color:#f3f0e8 !important;border-color:#7a766c !important;}\n      #aeroSolari .sf-seg button{background-image:none !important;box-shadow:none !important;text-shadow:none !important;border-radius:0 !important;}\n      #aeroSolari .sf-seg button:not([aria-pressed=\"true\"]){background:transparent !important;color:#9a968c !important;}\n      #aeroSolari .sf-seg button[aria-pressed=\"true\"]{background:#e9e4d8 !important;color:#15161a !important;}\n      .sf-tag{font-size:10px;letter-spacing:.12em;margin-right:10px;border:1px solid #4a4840;border-radius:3px;padding:1px 5px;color:#b5b0a4;vertical-align:1px;font-weight:700;}\n      .sf-vat{margin-left:12px;font-size:9px;letter-spacing:.14em;color:#9a968c;border:1px solid #4a4840;border-radius:3px;padding:1px 5px;font-weight:700;vertical-align:2px;}\n      .sf-div{margin-left:14px;color:#d0655e;}\n      .sf-legend{display:flex;flex-wrap:wrap;gap:8px 22px;padding:11px 24px 13px;border-top:1px solid #1d2026;font-family:var(--sf-font);font-size:11px;color:#7d7a72;align-items:center;}\n      .sf-gold{display:inline-block;width:7px;height:7px;border-radius:50%;background:#38c95a;box-shadow:0 0 5px rgba(56,201,90,.75);}   \/* gruene Status-LED wie auf der FRA-Tafel *\/\n      \/* Beschilderung unter der Tafel (wie das blaue FRA-Schild), in Aero-Lloyd-Violett *\/\n      .sf-sign{display:flex;align-items:center;gap:14px;padding:12px 22px;background:linear-gradient(180deg,#34308a 0%,#2D297A 55%,#26226a 100%);border-top:1px solid #4a46a0;}\n      .sf-sign-ico{width:34px;height:34px;border-radius:3px;background:#fff;display:flex;align-items:center;justify-content:center;flex:0 0 auto;}\n      .sf-sign-ico svg{display:block;}\n      .sf-sign-txt{line-height:1.15;color:#fff;font-family:var(--sf-font);}\n      .sf-sign-txt b{display:block;font-size:17px;font-weight:700;letter-spacing:.01em;}\n      .sf-sign-txt i{display:block;font-size:14px;font-style:italic;font-weight:400;opacity:.92;}\n      .sf-cols,.sf-row{display:grid;grid-template-columns:24px 80px 108px 104px 1fr 150px 62px;column-gap:18px;align-items:center;}\n      .sf-cols{align-items:start;}\n      .sf-cols{padding:9px 24px 7px;font-size:9px;font-weight:700;letter-spacing:.15em;color:#7d7a72;font-family:var(--sf-font);border-bottom:1px solid #262c33;text-transform:uppercase;}\n      .sf-cols .c-r{text-align:right;}\n      .sf-rows{min-height:40px;}\n      .sf-row{padding:6px 24px;border-bottom:1px solid #1a1c20;}\n      .sf-row:last-child{border-bottom:none;}\n      .sf-led{width:7px;height:7px;border-radius:50%;display:inline-block;background:#1a1a1a;}\n      .sf-led.green{background:#4ade80;box-shadow:0 0 6px #4ade80;}\n      .sf-led.grey{background:#2a2a2a;}\n      .sf-led.led-a{animation:sfBlinkA 1.2s infinite;}\n      .sf-led.led-b{animation:sfBlinkB 1.2s infinite;}\n      @keyframes sfBlinkA{0%,45%{opacity:1;box-shadow:0 0 6px currentColor;}50%,95%{opacity:.1;box-shadow:none;}100%{opacity:1;}}\n      @keyframes sfBlinkB{0%,45%{opacity:.1;box-shadow:none;}50%,95%{opacity:1;box-shadow:0 0 6px currentColor;}100%{opacity:.1;}}\n      .sf-cell{display:inline-flex;gap:1px;}\n      .sf-cell.gate-cell{justify-content:flex-end;width:100%;}\n      .sf-char{display:inline-block;width:13px;height:22px;background:#0b0c0e;border:1px solid #1e1e1e;border-radius:2px;position:relative;overflow:hidden;font-family:var(--sf-font);font-size:16px;font-weight:600;color:var(--sf-white);text-align:center;letter-spacing:0;line-height:22px;box-shadow:inset 0 1px 0 rgba(255,255,255,.03),0 2px 4px rgba(0,0,0,.5);}\n      .sf-char::after{content:'';position:absolute;top:50%;left:0;right:0;height:1px;background:rgba(0,0,0,.6);pointer-events:none;z-index:5;}\n      \/* \u2500\u2500 Echtes 3D-Split-Flap \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n         Waehrend des Wechsels besteht ein Feld aus 4 Lagen:\n           hinten oben  = NEUES Zeichen (obere Haelfte, wird freigelegt)\n           hinten unten = ALTES Zeichen (untere Haelfte, wird verdeckt)\n           Blatt 1      = ALTES Zeichen oben -> klappt um die Mittelachse nach vorn-unten weg\n           Blatt 2      = NEUES Zeichen unten -> faellt von vorn herunter auf die untere Haelfte *\/\n      .sf-char.sf-anim{overflow:visible;perspective:70px;}\n      .sf-h{position:absolute;left:0;top:0;width:100%;height:100%;background:#0b0c0e;border-radius:2px;color:inherit;text-align:center;line-height:22px;backface-visibility:hidden;-webkit-backface-visibility:hidden;}\n      .sf-h.sf-top{clip-path:inset(0 0 50% 0);}\n      .sf-h.sf-bot{clip-path:inset(50% 0 0 0);}\n      .sf-h.sf-f1{z-index:3;transform-origin:50% 50%;animation:sfFlap1 var(--sf-half,.3s) ease-in forwards;}\n      .sf-h.sf-f2{z-index:4;transform-origin:50% 50%;transform:rotateX(90deg);animation:sfFlap2 var(--sf-half,.3s) ease-out var(--sf-half,.3s) forwards;}\n      @keyframes sfFlap1{from{transform:rotateX(0deg);filter:brightness(1);}to{transform:rotateX(-90deg);filter:brightness(.45);}}\n      @keyframes sfFlap2{from{transform:rotateX(90deg);filter:brightness(.45);}to{transform:rotateX(0deg);filter:brightness(1);}}\n      .sf-char.gate-j{color:var(--sf-white);}  \/* Non-Schengen: J\/V-Gate erkennt man am Buchstaben *\/\n      \/* (alte Ganzzeichen-Animation durch echtes Split-Flap ersetzt, siehe .sf-h) *\/\n      .sf-city{font-family:var(--sf-font);font-size:15px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--sf-white);padding-left:10px;overflow:hidden;white-space:nowrap;display:flex;align-items:center;min-width:0;}\n      \/* Strecke als Fallblatt-Kacheln (etwas schmaler als die uebrigen Felder) *\/\n      .sf-cell.route-cell{flex:0 0 auto;}\n      \/* JEDER Bereich als Kacheln (wie die FRA-Tafel): Status, DEP\/ARR, \"via\"-Zeile *\/\n      .sf-rtwrap{display:flex;flex-direction:column;align-items:flex-start;gap:3px;min-width:0;}\n      .sf-cell.st-cell{justify-content:flex-end;width:100%;}\n      .sf-cell.st-cell .sf-char{width:11px;font-size:13px;}   \/* gleiche Groesse wie die Strecke *\/\n      .sf-cell.tag-cell{margin-right:10px;flex:0 0 auto;}\n      .sf-cell.tag-cell .sf-char{width:11px;font-size:13px;color:#b5b0a4;}\n      .sf-cell.via-cell .sf-char{width:9px;height:15px;line-height:15px;font-size:10px;}\n      .sf-cell.via-cell .sf-h{line-height:15px;}\n      .sf-char.red{color:#d0655e;}\n      .sf-cell.route-cell .sf-char{width:11px;font-size:13px;}   \/* 13px: M und W passen in die Kachel *\/\n      .sf-cols .sf-via{display:block;font-size:8px;font-style:italic;font-weight:400;letter-spacing:.08em;text-transform:none;color:#6f6c64;margin-top:1px;}\n      .sf-cols .sf-to{display:inline-block;vertical-align:top;}\n      .sf-statuslabel{font-family:var(--sf-font);font-size:14px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;display:flex;align-items:center;gap:7px;transition:opacity .28s ease;overflow:hidden;white-space:nowrap;}\n      .sf-statuslabel.fade{opacity:0;}\n      .sf-cx{font-family:var(--sf-font);font-size:12px;color:#9fb6dd;}\n      .sf-sound{margin-left:14px;vertical-align:middle;background:transparent;border:1px solid #333;border-radius:3px;color:#777;font-family:var(--sf-font);font-size:9px;font-weight:700;letter-spacing:.14em;padding:3px 8px;cursor:pointer;display:inline-flex;align-items:center;gap:5px;transition:color .15s,border-color .15s;}\n      .sf-sound:hover{color:#F2A900;border-color:#F2A900;}\n      .sf-sound[aria-pressed=\"true\"]{color:#F2A900;border-color:#4a3c14;}\n      .sf-empty{color:#8a867c;text-align:center;padding:20px;font-family:var(--sf-font);font-size:11px;font-weight:700;letter-spacing:.2em;}\n      @media(max-width:900px){.sf-cols,.sf-row{grid-template-columns:16px 60px 82px 78px 1fr 104px 46px;column-gap:9px;}.sf-city{font-size:11px;}.sf-statuslabel{font-size:10.5px;}}\n      \/* \u2500\u2500 Handy (<= 640 px): jede Flugzeile als kleiner Block \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n           Zeile 1: LED \u00b7 Zeit \u00b7 Flug \u00b7 Gate\n           Zeile 2: Strecke (+ via)        Zeile 3: Status\n         Codeshare und Spaltenkopf entfallen; Kopfbereich untereinander. *\/\n      @media(max-width:640px){\n        #aeroSolariHd{flex-direction:column;align-items:stretch;padding:16px 14px 12px;gap:10px;}\n        #aeroSolariHd > div:last-child{text-align:left !important;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;}\n        #aeroSolariHd .sf-title{letter-spacing:.22em;}\n        #aeroSolariHd .sf-mode{font-size:18px;letter-spacing:.12em;margin-top:6px;}\n        #aeroSolariHd .sf-sub{font-size:11px;}\n        .sf-ctl{justify-content:flex-start;width:100%;margin-top:6px;}\n        .sf-seg button{font-size:10px;padding:6px 9px;}\n        .sf-cols{display:none;}\n        .sf-row{grid-template-columns:12px auto auto 1fr;grid-template-areas:\"led tm fn gt\" \". rt rt rt\" \". st st tg\";column-gap:8px;row-gap:6px;padding:10px 14px;}\n        .sf-row > :nth-child(1){grid-area:led;}\n        .sf-row > :nth-child(2){grid-area:tm;}\n        .sf-row > :nth-child(3){grid-area:fn;}\n        .sf-row > :nth-child(4){display:none;}                \/* Codeshare *\/\n        .sf-row > .sf-city{display:contents;}                 \/* Kennung und Strecke werden eigene Rasterzellen *\/\n        .sf-row .sf-rtwrap{grid-area:rt;}\n        .sf-row .tag-cell{grid-area:tg;margin-right:0;align-self:center;justify-self:end;}\n        .sf-row > .st-cell{grid-area:st;justify-content:flex-start;width:auto;}\n        .sf-row > .gate-cell{grid-area:gt;justify-self:end;}\n        .sf-cell.route-cell .sf-char{width:8px;font-size:10px;}\n        .sf-cell.via-cell .sf-char{width:8px;font-size:9px;}\n        .sf-cell.tag-cell .sf-char{width:9px;font-size:11px;}\n        .sf-cell.st-cell .sf-char{width:10px;font-size:11px;}\n        .sf-legend{padding:10px 14px 12px;}\n        .sf-sign{padding:10px 14px;}\n      }\n      <\/style>\n\n      <div id=\"aeroSolari\" translate=\"no\" class=\"notranslate\">\n          <div id=\"aeroSolariHd\">\n              <div>\n                <div class=\"sf-title\">&#9992; &nbsp; AERO LLOYD VIRTUAL<\/div>\n                <div class=\"sf-mode\" id=\"sfModeDe\">LIVE AERIS FLIGHTS<\/div>\n                <div class=\"sf-sub\" id=\"sfModeEn\">Aero Lloyd crews in the air and landed today<\/div>\n              <\/div>\n              <div style=\"text-align:right;\">\n                  <div class=\"sf-clock\" id=\"sfClock\">--:-- FRA LOCAL<\/div>\n                  <div style=\"font-family:var(--sf-font);color:#f3f0e8;margin-top:4px;letter-spacing:.12em;\">\n                      <span id=\"sfUTC\" style=\"font-size:22px;font-weight:700;\">--:--<\/span>\n                  <\/div>\n                  <div style=\"font-family:var(--sf-font);font-size:9px;color:#5f5c55;margin-top:2px;letter-spacing:2px;\">\n                      <span id=\"sfDate\">-<\/span>\n                  <\/div>\n                  <div class=\"sf-ctl\">\n                      <span class=\"sf-seg\" role=\"group\" aria-label=\"Board view\">\n                          <button type=\"button\" id=\"sfTabLive\" aria-pressed=\"true\" title=\"Aero Lloyd flights tracked by AERIS today\">LIVE AERIS FLIGHTS<\/button>\n                          <button type=\"button\" id=\"sfTabFull\" aria-pressed=\"false\" title=\"Today's published timetable\">TIMETABLE<\/button>\n                      <\/span>\n                      <button type=\"button\" id=\"sfSound\" class=\"sf-snd\" aria-pressed=\"true\" title=\"Board sound\">\n                          <span id=\"sfSoundIcon\"><\/span><span id=\"sfSoundTxt\" style=\"display:none;\"><\/span>\n                      <\/button>\n                  <\/div>\n              <\/div>\n          <\/div>\n          <div class=\"sf-cols\">\n              <span><\/span>\n              <span id=\"sfColTime\">TIME<\/span>\n              <span id=\"sfColFlight\">FLIGHT<\/span>\n              <span id=\"sfColCx\">CODESHARE<\/span>\n              <span id=\"sfColPlace\">ROUTE<\/span>\n              <span class=\"c-r\" id=\"sfColStatus\">STATUS<\/span>\n              <span class=\"c-r\" id=\"sfColGate\">GATE<\/span>\n          <\/div>\n          <div class=\"sf-rows\" id=\"sfBoard\">\n              <div class=\"sf-empty\">LOADING ...<\/div>\n          <\/div>\n          <div class=\"sf-legend\">\n              <span><span class=\"sf-gold\"><\/span>&nbsp; flown by an Aero Lloyd crew<\/span>\n              <span>VATSIM <span style=\"opacity:.75;\">(via line)<\/span> &nbsp;flight online on the VATSIM network<\/span>\n              <span>DIV <span style=\"opacity:.75;\">(via line)<\/span> &nbsp;diverted to<\/span>\n          <\/div>\n          <div class=\"sf-sign\">\n              <span class=\"sf-sign-ico\" title=\"Aero Lloyd Virtual\">\n                  <!-- Aero-Lloyd-Signet -->\n                  <svg width=\"28\" height=\"21\" viewBox=\"0 0 1190 896\" aria-hidden=\"true\">\n                      <rect x=\"13\" y=\"13\" width=\"1164\" height=\"870\" fill=\"none\" stroke=\"#2D297A\" stroke-width=\"26\"\/>\n                      <polygon points=\"77,814 768,82 1113,82 431,814\" fill=\"#2D297A\"\/>\n                      <polygon points=\"775,474 1116,106 1116,814 775,814\" fill=\"#2D297A\"\/>\n                  <\/svg>\n              <\/span>\n              <span class=\"sf-sign-ico\" id=\"sfSignPlane\"><\/span>\n              <span class=\"sf-sign-txt\"><b id=\"sfSignDe\">Live-Fl\u00fcge<\/b><i id=\"sfSignEn\">Live AERIS flights<\/i><\/span>\n          <\/div>\n      <\/div>\n\n      <\/div>\n\n      <script>\n      (function(){\n\n      \/\/ \u2500\u2500 SPLIT-FLAP ENGINE (unveraendert) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      var sfState = {};\n      function escHtml(c){ if(c==='<')return '&lt;'; if(c==='>')return '&gt;'; if(c==='&')return '&amp;'; return c; }\n      function sfMakeCell(id, width, cls){\n          var html = '<span class=\"sf-cell'+(cls?' '+cls:'')+'\" id=\"sfc-'+id+'\">';\n          for (var i=0;i<width;i++) html += '<span class=\"sf-char\" id=\"sfc-'+id+'-'+i+'\"> <\/span>';\n          return html + '<\/span>';\n      }\n\n      var _sfAudioCtx = null;\n      function sfGetAudioCtx(){ if(!_sfAudioCtx){ try{_sfAudioCtx=new (window.AudioContext||window.webkitAudioContext)();}catch(e){} } return _sfAudioCtx; }\n      \/\/ Langsamerer, ruhigerer Takt: mehr Abstand zwischen den Zeichen und Klacks.\n      \/\/ Welle von OBEN nach UNTEN: jede Zeile startet SF_ROW_STAGGER ms nach der\n      \/\/ darueber; innerhalb einer Zeile klappen die Zeichen fast gleichzeitig.\n      \/\/ Zeilen beginnen von oben nach unten; jedes Feld hat eigenen Zufallsstart,\n      \/\/ eigene Klappgeschwindigkeit und blaettert 0-2 Zwischenzeichen durch (wie\n      \/\/ eine echte Solari-Tafel) \u2014 dadurch laeuft nichts synchron.\n      var SF_ROW_STAGGER=170, SF_START_JITTER=320, SF_FLIP_HALF=200, SF_CLACK_GAP=0.10, _sfNextClack=0;\n      \/\/ Ein Feld klappt um: oberes Blatt faellt nach vorn-unten (SF_FLIP_HALF ms),\n      \/\/ dann legt sich das neue untere Blatt herunter (nochmal SF_FLIP_HALF ms).\n      function sfFlap(el, from, to, half){\n          half = half || SF_FLIP_HALF;\n          var e=function(c){ return c===' ' ? '&nbsp;' : escHtml(c); };\n          el.style.setProperty('--sf-half', Math.round(half)+'ms');\n          el.classList.add('sf-anim');\n          el.innerHTML = '<span class=\"sf-h sf-top\">'+e(to)+'<\/span>'\n                       + '<span class=\"sf-h sf-bot\">'+e(from)+'<\/span>'\n                       + '<span class=\"sf-h sf-top sf-f1\">'+e(from)+'<\/span>'\n                       + '<span class=\"sf-h sf-bot sf-f2\">'+e(to)+'<\/span>';\n          clearTimeout(el._sfT);\n          el._sfT = setTimeout(function(){ el.classList.remove('sf-anim'); el.textContent=to; }, 2*half+30);\n      }\n      \/\/ Ein Feld blaettert ueber 0-2 zufaellige Zwischenzeichen zum Ziel.\n      var SF_POOL_D='0123456789', SF_POOL_A='ABCDEFGHIJKLMNOPRSTUVWXYZ';\n      function sfFlapSeq(el, from, to){\n          var pool = \/[0-9]\/.test(to) ? SF_POOL_D : SF_POOL_A, seq=[], n=Math.floor(Math.random()*3);\n          for(var k=0;k<n;k++){ seq.push(pool.charAt(Math.floor(Math.random()*pool.length))); }\n          seq.push(to);\n          var tok = (el._sfTok = (el._sfTok||0) + 1);       \/\/ neuere Folge gewinnt\n          (function step(i, cur){\n              if(i>=seq.length || el._sfTok!==tok) return;\n              var half = 140 + Math.random()*90;           \/\/ jedes Blatt etwas anders schnell\n              sfFlap(el, cur, seq[i], half);\n              sfPlayClack(half);                            \/\/ Klack beim Aufschlagen\n              setTimeout(function(){ step(i+1, seq[i]); }, 2*half + 15);\n          })(0, from);\n      }\n      var sfSoundOn=true; try{ sfSoundOn = localStorage.getItem('aeroSolariSound')!=='0'; }catch(e){}\n\n      function sfPlayClack(delayMs){\n          if(!sfSoundOn||document.hidden) return;\n          var ctx=sfGetAudioCtx(); if(!ctx) return;\n          if(ctx.state!=='running'){ try{ ctx.resume(); }catch(e){} return; }\n          if(_sfNextClack > ctx.currentTime + 5) _sfNextClack = 0;   \/\/ veralteten Zeitstempel verwerfen\n          var when=ctx.currentTime+delayMs\/1000;\n          if(when<_sfNextClack) return; _sfNextClack=when+SF_CLACK_GAP;\n          \/\/ Weiche PLASTIK-Blaettchen (wie die Fallblatt-Tafel in FRA): heller, kurzer\n          \/\/ Ton mit sanftem Anschlag; dazu ein zweites, leiseres \"Nachklappern\", weil\n          \/\/ das Blatt kurz nachfedert.\n          var sr=ctx.sampleRate;\n          var tick=function(at, vol, freq, len){\n              var n=Math.floor(sr*len), buf=ctx.createBuffer(1,n,sr), d=buf.getChannelData(0);\n              for(var i=0;i<n;i++){ var t=i\/n; d[i]=(Math.random()*2-1)*Math.min(1,i\/(sr*0.014))*Math.pow(1-t,2.6); }\n              var src=ctx.createBufferSource(); src.buffer=buf;\n              var bpf=ctx.createBiquadFilter(); bpf.type='bandpass'; bpf.frequency.value=freq; bpf.Q.value=0.55;\n              var lpf=ctx.createBiquadFilter(); lpf.type='lowpass';  lpf.frequency.value=2100; lpf.Q.value=0.4;\n              var g=ctx.createGain(); g.gain.value=vol;\n              src.connect(bpf); bpf.connect(lpf); lpf.connect(g); g.connect(ctx.destination); src.start(at);\n          };\n          var f=1600+Math.random()*450;\n          tick(when,                         0.12+Math.random()*0.02, f,       0.042);   \/\/ Aufschlag\n          tick(when+0.014+Math.random()*0.01, 0.022,                  f*1.08,  0.024);   \/\/ Nachfedern\n      }\n\n      function sfUpdate(id, newText, width, charCls, row){\n          var padded=(''+newText).toUpperCase().padEnd(width,' ').substring(0,width);\n          var prev=sfState[id]||''.padEnd(width,' ');\n          sfState[id]=padded;\n          for(var i=0;i<width;i++){\n              (function(idx){\n                  var el=document.getElementById('sfc-'+id+'-'+idx); if(!el) return;\n                  if(charCls!==undefined){ el.className='sf-char'+(charCls?' '+charCls:''); }\n                  if(prev[idx]===padded[idx]) return;\n                  var target=padded[idx], from=prev[idx];\n                  \/\/ Zeilen von oben nach unten; innerhalb der Zeile minimaler Zufallsversatz\n                  \/\/ (wie echte Mechanik), keine Links-nach-rechts-Welle.\n                  var delay=(row||0)*SF_ROW_STAGGER + Math.floor(Math.random()*SF_START_JITTER);\n                  setTimeout(function(){ sfFlapSeq(el, from, target); }, delay);\n              })(i);\n          }\n      }\n\n      function sfGate(v){\n          var s=(''+(v==null?'':v)).trim().toUpperCase();\n          if(s===''||s==='-'||s==='TBA') return 'TBA';\n          if(s.indexOf('ASSIGNED')===0||s.indexOf('ON ARRIVAL')>-1) return 'TBA';\n          if(s==='N\/A'||s==='NA'||s==='TBD') return 'TBA';\n          return s;\n      }\n\n      function sfLed(kind){\n          if(kind==='g') return '<span class=\"sf-led green led-a\" style=\"margin-right:3px;\"><\/span><span class=\"sf-led green led-b\"><\/span>';\n          if(kind==='r') return '<span class=\"sf-led\" style=\"background:#c9605a;display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:3px;\"><\/span><span class=\"sf-led\" style=\"background:#c9605a;display:inline-block;width:6px;height:6px;border-radius:50%;\"><\/span>';\n          return '<span class=\"sf-led grey\" style=\"margin-right:3px;opacity:0;\"><\/span><span class=\"sf-led grey\" style=\"opacity:0;\"><\/span>';\n      }\n\n      \/\/ \u2500\u2500 Status-Codes \u2192 DE\/EN + Farbe + LED \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      \/\/ Klassisch: echte Betriebsstatus in Elfenbein, Abgeschlossenes\/Geplantes grau,\n      \/\/ nur \"Diverted\" farbig (gedaempftes Rot). Keine blinkenden gruenen LEDs.\n      var W='#f4f4f1';   \/\/ Fallblatt-Weiss: alle Status weiss wie auf der FRA-Tafel,\n                         \/\/ nur \"Diverted\" (echte Abweichung) gedaempft rot.\n      var ST = {\n          SCHEDULED : {de:'Planm\u00e4\u00dfig',    en:'Scheduled',     c:W, led:'e'},\n          CHECKIN   : {de:'Check-in',     en:'Check-in',      c:W, led:'e'},\n          GATE_OPEN : {de:'Gate offen',   en:'Gate open',     c:W, led:'e'},\n          BOARDING  : {de:'Einstieg',     en:'Boarding',      c:W, led:'e'},\n          FINAL_CALL: {de:'Letzter Aufruf',en:'Final call',   c:W, led:'e'},\n          DEPARTING : {de:'Startet',      en:'Departing',     c:W, led:'e'},\n          DEPARTED  : {de:'Abgeflogen',   en:'Departed',      c:W, led:'e'},\n          INFLIGHT  : {de:'Im Flug',      en:'In flight',     c:W, led:'e'},\n          APPROACH  : {de:'Im Anflug',    en:'Approaching',   c:W, led:'e'},\n          LANDING   : {de:'Landung',      en:'Landing',       c:W, led:'e'},\n          TAXIIN    : {de:'Rollt',        en:'Taxi in',       c:W, led:'e'},\n          EXPECTED  : {de:'Erwartet',     en:'Expected',      c:W, led:'e'},\n          LANDED    : {de:'Gelandet',     en:'Landed',        c:W, led:'e'},\n          ARRIVED   : {de:'Gelandet',     en:'Landed',        c:W, led:'e'},\n          DIVERTED  : {de:'Umgeleitet',   en:'Diverted',      c:'#d0655e', led:'r'}\n      };\n\n      \/\/ \u2500\u2500 Zustand \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      var BOARD = {departures:[], arrivals:[]};\n      var mode = 'dep';          \/\/ 'dep' | 'arr'\n      var view = 'auto';         \/\/ 'auto' = Live | 'full' = kompletter Flugplan\n      var langIdx = 1;           \/\/ feste Sprache Englisch (keine Rotation mehr)\n      var cxIdx = 0;\n      var renderedCount = -1;\n      var loaded = false;\n      var userPicked = false;    \/\/ true, sobald der Besucher selbst einen Tab w\u00e4hlt\n      var didAutoView = false;   \/\/ Smart-Default nur einmal anwenden\n\n      \/\/ LIVE = nur ECHTE Fl\u00fcge (Live-Position aktiv oder heutiger PIREP), beide\n      \/\/ Richtungen gemischt und nach Zeit sortiert. FULL = der geplante Fahrplan,\n      \/\/ flippt Abflug\/Ankunft. (Rein geplante Fl\u00fcge sind NICHT \"live\".)\n      function liveList(){\n          var out=[];\n          (BOARD.departures||[]).forEach(function(f){ if(f.live) out.push(Object.assign({dir:'dep'}, f)); });\n          (BOARD.arrivals||[]).forEach(function(f){ if(f.live) out.push(Object.assign({dir:'arr'}, f)); });\n          out.sort(function(a,b){ return (''+a.time).localeCompare(''+b.time); });\n          return out;\n      }\n      function data(){\n          if (view==='auto') return liveList();                            \/\/ LIVE: echte Fl\u00fcge\n          return (mode==='dep' ? BOARD.departures : BOARD.arrivals) || [];  \/\/ FULL: Fahrplan\n      }\n\n      \/\/ Spaltenkopf-Beschriftungen DE\/EN\n      var COLHEAD = {\n          time  : {de:'ZEIT',  en:'TIME'},\n          flight: {de:'FLUG',  en:'FLIGHT'},\n          cx    : {de:'CODESHARE', en:'CODESHARE'},\n          status: {de:'STATUS',en:'STATUS'},\n          gate  : {de:'GATE',  en:'GATE'}\n      };\n      function placeHead(){\n          return 'ROUTE';   \/\/ volle Strecke \"Start -> Ziel\" mit ausgeschriebenen Namen\n      }\n      function paintColHeaders(){\n          var set=function(id,txt){ var el=document.getElementById(id); if(el) el.textContent=txt; };\n          set('sfColTime',   COLHEAD.time[langIdx?'en':'de']);\n          set('sfColFlight', COLHEAD.flight[langIdx?'en':'de']);\n          set('sfColCx',     COLHEAD.cx[langIdx?'en':'de']);\n          set('sfColStatus', COLHEAD.status[langIdx?'en':'de']);\n          set('sfColGate',   COLHEAD.gate[langIdx?'en':'de']);\n          var pl=document.getElementById('sfColPlace');\n          if(pl) pl.innerHTML='FROM - <span class=\"sf-to\">TO<span class=\"sf-via\">via<\/span><\/span>';\n      }\n\n      var RW=20, renderedRW=-1, renderedView='';   \/\/ Kachelbreite der Strecke (an laengste Strecke angepasst)\n      var SW=9;                                       \/\/ Status-Kacheln (\"SCHEDULED\", \"IN FLIGHT\", ...)\n      function ensureRows(n){\n          if(renderedCount===n && renderedRW===RW && renderedView===view) return;\n          var board=document.getElementById('sfBoard'); if(!board) return;\n          var html='';\n          for(var i=0;i<n;i++){\n              html += '<div class=\"sf-row\" id=\"sfrow-'+i+'\">'\n                  + '<div id=\"sfled-'+i+'\">'+sfLed('e')+'<\/div>'\n                  + sfMakeCell('tm'+i,5)\n                  + sfMakeCell('fn'+i,7)\n                  + sfMakeCell('cx'+i,7)\n                  + '<span class=\"sf-city\" id=\"sfcity-'+i+'\">'\n                  +   (view==='auto' ? sfMakeCell('tg'+i, 3, 'tag-cell') : '')\n                  +   '<span class=\"sf-rtwrap\">' + sfMakeCell('rt'+i, RW, 'route-cell')\n                  +   sfMakeCell('vi'+i, RW, 'via-cell') + '<\/span><\/span>'\n                  + sfMakeCell('st'+i, SW, 'st-cell')\n                  + sfMakeCell('gt'+i,4,'gate-cell')\n                  + '<\/div>';\n          }\n          board.innerHTML = html || '<div class=\"sf-empty\">NO FLIGHTS<\/div>';\n          \/\/ sfState fuer neu aufgebaute Zellen zuruecksetzen\n          for(var k in sfState){ if(sfState.hasOwnProperty(k)) delete sfState[k]; }\n          renderedCount = n; renderedRW = RW; renderedView = view;\n      }\n\n      function paintStatus(i, code){\n          var st = ST[code] || ST.SCHEDULED;\n          var txt = (langIdx? st.en : st.de).toUpperCase();\n          if(txt.length < SW) txt = new Array(SW - txt.length + 1).join(' ') + txt;   \/\/ rechtsbuendig\n          sfUpdate('st'+i, txt, SW, code==='DIVERTED' ? 'red' : '', i);\n      }\n\n      function paintRows(){\n          var d = data();\n          if(!d.length){\n              var b=document.getElementById('sfBoard');\n              if(b) b.innerHTML='<div class=\"sf-empty\">'+(view==='auto'?'NO AERO LLOYD VIRTUAL FLIGHTS IN THE AIR RIGHT NOW':'NO FURTHER FLIGHTS TODAY')+'<\/div>';\n              renderedCount=-1;\n              return;\n          }\n          \/\/ Einheitliche Kachelbreite fuer alle Zeilen: laengste Strecke (16..28 Zeichen)\n          var mx=16; d.forEach(function(f){ mx=Math.max(mx, routeStr(f).length); });\n          RW=Math.min(28, mx);\n          ensureRows(d.length);\n          for(var i=0;i<d.length;i++){\n              var f=d[i];\n              sfUpdate('tm'+i, f.time||'', 5, undefined, i);\n              sfUpdate('fn'+i, f.flight||'', 7, undefined, i);\n              var cx=f.connex||[]; sfUpdate('cx'+i, cx.length?cx[cxIdx%cx.length]:'', 7, undefined, i);\n              if(view==='auto') sfUpdate('tg'+i, f.dir==='dep'?'DEP':'ARR', 3, undefined, i);\n              sfUpdate('rt'+i, routeStr(f), RW, undefined, i);          \/\/ Strecke als Kacheln\n              sfUpdate('vi'+i, viaStr(f), RW, f.div ? 'red' : '', i);    \/\/ \"via\": Ausweichflughafen \/ VATSIM\n              paintStatus(i, f.status);\n              var ledEl=document.getElementById('sfled-'+i);\n              if(ledEl){\n                  ledEl.innerHTML = f.live\n                      ? '<span class=\"sf-gold\" title=\"Flown by an Aero Lloyd crew today\"><\/span>'\n                      : sfLed('e');\n              }\n              var g=sfGate(f.gate), gc=(g.charAt(0)==='J'||g.charAt(0)==='V')?'gate-j':'';\n              sfUpdate('gt'+i, g, 4, gc, i);\n          }\n      }\n      function escCity(s){ return (''+s).replace(\/&\/g,'&amp;').replace(\/<\/g,'&lt;').replace(\/>\/g,'&gt;'); }\n      \/\/ Volle Strecke \"Startstadt -> Zielstadt\" mit ausgeschriebenen Namen.\n      \/\/ Fallback auf die alte Einzelstadt, falls from\/to (noch) fehlen (gecachte Daten).\n      \/\/ Strecke fuer die Kacheln: \"FRANKFURT-HERAKLION\"\n      function routeStr(f){\n          var from=f.from||'', to=f.to||'';\n          return ((from && to) ? from+'-'+to : (f.city||'')).toUpperCase();\n      }\n      \/\/ \"via\"-Zeile unter der Strecke: Ausweichflughafen und\/oder VATSIM\n      function viaStr(f){\n          var p=[]; if(f.div) p.push('DIV '+f.div); if(f.vatsim) p.push('VATSIM');\n          return p.join(' \/ ').toUpperCase();\n      }\n      function routeExtras(f){\n          var div = f.div ? '<span class=\"sf-div\" title=\"Diverted to\">&#8627; '+escCity(f.div)+'<\/span>' : '';\n          var vat = f.vatsim ? '<span class=\"sf-vat\" title=\"Online on the VATSIM network\">VATSIM<\/span>' : '';\n          return div+vat;\n      }\n      function routeText(f){\n          var from=f.from||'', to=f.to||'';\n          var div = f.div ? '<span class=\"sf-div\">'+escCity(f.div)+'<\/span>' : '';\n          var vat = f.vatsim ? '<span class=\"sf-vat\" title=\"Online on the VATSIM network\">VATSIM<\/span>' : '';\n          if(from && to) return escCity(from)\n              +'<span style=\"margin:0 2px;\">-<\/span>'\n              +escCity(to)+div+vat;\n          return escCity(f.city||'')+div+vat;\n      }\n\n      function paintHeader(){\n          var de=document.getElementById('sfModeDe'), en=document.getElementById('sfModeEn');\n          var sd=document.getElementById('sfSignDe'), se=document.getElementById('sfSignEn'), sp=document.getElementById('sfSignPlane');\n          var plane=function(rot){ return '<svg width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" aria-hidden=\"true\" style=\"transform:rotate('+rot+'deg)\"><path fill=\"#2D297A\" d=\"M21 16v-2l-8-5V3.5a1.5 1.5 0 0 0-3 0V9l-8 5v2l8-2.5V19l-2 1.5V22l3.5-1 3.5 1v-1.5L13 19v-5.5z\"\/><\/svg>'; };\n          if(view==='auto'){\n              if(sd) sd.textContent='Live-Fl\u00fcge'; if(se) se.textContent='Live AERIS flights'; if(sp) sp.innerHTML=plane(90);\n          } else if(mode==='dep'){\n              if(sd) sd.textContent='Abflug'; if(se) se.textContent='Departures'; if(sp) sp.innerHTML=plane(45);\n          } else {\n              if(sd) sd.textContent='Ankunft'; if(se) se.textContent='Arrivals'; if(sp) sp.innerHTML=plane(135);\n          }\n          if(view==='auto'){\n              if(de) de.textContent='LIVE AERIS FLIGHTS';\n              if(en) en.textContent='Aero Lloyd crews in the air and landed today';\n          } else {\n              if(de) de.textContent = mode==='dep'?'DEPARTURES':'ARRIVALS';\n              if(en) en.textContent = \"Today's timetable \u00b7 departures and arrivals\";\n          }\n          paintColHeaders();\n      }\n\n      \/\/ \u2500\u2500 Dynamik \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      \/\/ Nur der Fahrplan (FULL) flippt Abflug\/Ankunft. LIVE bleibt die gemischte Liste.\n      function flipView(){\n          if(!loaded || view!=='full') return;\n          mode = (mode==='dep'?'arr':'dep');\n          paintHeader();\n          paintRows();\n      }\n      function applyTabs(){\n          var l=document.getElementById('sfTabLive'), f=document.getElementById('sfTabFull');\n          if(l) l.setAttribute('aria-pressed', view==='auto'?'true':'false');\n          if(f) f.setAttribute('aria-pressed', view==='full'?'true':'false');\n      }\n      function setView(v){\n          if(view===v) return;\n          view = v; userPicked = true;   \/\/ ab jetzt Nutzerwahl respektieren\n          applyTabs();\n          paintHeader();\n          paintRows();\n      }\n      function rotateConnex(){\n          if(!loaded) return;\n          cxIdx++;\n          var d=data();\n          for(var i=0;i<d.length;i++){\n              var cx=d[i].connex||[];\n              if(cx.length<2) continue;\n              sfUpdate('cx'+i, cx[cxIdx%cx.length], 7, undefined, i);\n          }\n      }\n\n      function fetchBoard(){\n          fetch('https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/nexus\/v1\/board', {credentials:'same-origin'})\n              .then(function(r){ return r.json(); })\n              .then(function(d){\n                  BOARD.departures = d.departures||[];\n                  BOARD.arrivals   = d.arrivals||[];\n                  loaded = true;\n                  \/\/ Smart-Default beim ersten Laden: Live-Verkehr -> LIVE, sonst\n                  \/\/ FULL SCHEDULE (damit die Tafel nie leer wirkt). Ab einer\n                  \/\/ eigenen Tab-Wahl (userPicked) wird das nicht mehr \u00fcberschrieben.\n                  if(!userPicked && !didAutoView){\n                      view = liveList().length ? 'auto' : 'full';\n                      applyTabs();\n                      didAutoView = true;\n                  }\n                  paintHeader();\n                  paintRows();\n              })\n              .catch(function(){});\n      }\n\n      \/\/ \u2500\u2500 Uhr \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      \/\/ Uhr nur bei tatsaechlicher Aenderung schreiben (Minutenraster). Ein\n      \/\/ textContent-Write pro Sekunde erzwingt sonst ein Reflow und laesst die\n      \/\/ laufenden CSS-Animationen (LED-Blink etc.) sichtbar \"zucken\".\n      var _clk={};\n      setInterval(function(){\n          var now=new Date();\n          var fra=now.toLocaleTimeString('en-GB',{timeZone:'Europe\/Berlin',hour:'2-digit',minute:'2-digit'})+' FRA LOCAL';\n          var utc=now.toLocaleTimeString('en-GB',{timeZone:'UTC',hour:'2-digit',minute:'2-digit'})+'Z';\n          var dat=now.toLocaleDateString('en-GB',{timeZone:'UTC',day:'2-digit',month:'short',year:'numeric'}).toUpperCase();\n          var el=document.getElementById('sfClock'), eu=document.getElementById('sfUTC'), ed=document.getElementById('sfDate');\n          if(el && _clk.fra!==fra){ el.textContent=fra; _clk.fra=fra; }\n          if(eu && _clk.utc!==utc){ eu.textContent=utc; _clk.utc=utc; }\n          if(ed && _clk.dat!==dat){ ed.textContent=dat; _clk.dat=dat; }\n      },1000);\n\n      \/\/ \u2500\u2500 Ton-Schalter \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      function sfApplySound(){\n          var btn=document.getElementById('sfSound'); if(!btn) return;\n          btn.setAttribute('aria-pressed', sfSoundOn?'true':'false');\n          var ic=document.getElementById('sfSoundIcon'), tx=document.getElementById('sfSoundTxt');\n          var spk='<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M4 9h4l5-4v14l-5-4H4z\"\/>';\n          if(ic) ic.innerHTML = spk + (sfSoundOn\n              ? '<path d=\"M16.5 8.5a5 5 0 0 1 0 7\"\/><path d=\"M19 6a8.5 8.5 0 0 1 0 12\"\/><\/svg>'\n              : '<path d=\"M17 9.5l5 5M22 9.5l-5 5\"\/><\/svg>');\n          if(tx) tx.textContent=sfSoundOn?'SOUND ON':'SOUND OFF';\n          btn.title=sfSoundOn?'Mute board sound':'Unmute board sound';\n      }\n      (function(){\n          var btn=document.getElementById('sfSound'); if(!btn) return;\n          sfApplySound();\n          btn.addEventListener('click', function(){\n              sfSoundOn=!sfSoundOn;\n              try{ localStorage.setItem('aeroSolariSound', sfSoundOn?'1':'0'); }catch(e){}\n              if(sfSoundOn){ var ctx=sfGetAudioCtx(); if(ctx&&ctx.state==='suspended') ctx.resume(); }\n              sfApplySound();\n          });\n      })();\n      \/\/ Browser erlauben Ton erst nach einer Nutzeraktion: beim ersten Klick\/Tippen\n      \/\/ freischalten und den Drossel-Zeitstempel zuruecksetzen.\n      ['click','touchstart','keydown'].forEach(function(evt){\n          document.addEventListener(evt, function(){\n              var ctx=sfGetAudioCtx();\n              if(ctx&&ctx.state!=='running'){ ctx.resume().then(function(){ _sfNextClack=0; }).catch(function(){}); }\n          }, {passive:true});\n      });\n\n      \/\/ \u2500\u2500 Init + Timer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n      (function(){\n          var l=document.getElementById('sfTabLive'), f=document.getElementById('sfTabFull');\n          if(l) l.addEventListener('click', function(){ setView('auto'); });\n          if(f) f.addEventListener('click', function(){ setView('full'); });\n      })();\n      paintColHeaders();\n      fetchBoard();\n      setInterval(fetchBoard, 60000);   \/\/ Daten\/Status aktualisieren\n      setInterval(flipView,   12000);   \/\/ Dep\/Arr-Wechsel (grosser Flip)\n      setInterval(rotateConnex,5000);   \/\/ Connex-Rotation\n\n      })();\n      <\/script>\n\n    <\/section>\n    <\/div>\n    <\/div>\n\n<\/div><!-- end wrap -->\n\n<link rel=\"stylesheet\" href=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\"\/>\n<script src=\"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\"><\/script>\n<script>\n(function(){\n\n\/\/ \u2500\u2500 MAP \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar map = L.map('aeroMap',{zoomControl:true,attributionControl:false}).setView([50.5,10],5);\n\n\/\/ Basiskarten: keyfreie Esri\/ArcGIS-Rasterkacheln (server.arcgisonline.com) \u2014\n\/\/ CARTO verlangt inzwischen einen API-Key und liefert sonst nur noch\n\/\/ \"API KEY REQUIRED\"-Kacheln. Dark\/Light Gray Canvas ist das keyfreie Pendant\n\/\/ zu carto dark_all\/light_all; gleicher Host wie die bew\u00e4hrte TERRAIN-Karte.\n\/\/ Esri-Kachelreihenfolge ist {z}\/{y}\/{x} (kein {s}\/{r}).\nvar _DARK  = 'https:\/\/server.arcgisonline.com\/ArcGIS\/rest\/services\/Canvas\/World_Dark_Gray_Base\/MapServer\/tile\/{z}\/{y}\/{x}';\nvar _LIGHT = 'https:\/\/server.arcgisonline.com\/ArcGIS\/rest\/services\/Canvas\/World_Light_Gray_Base\/MapServer\/tile\/{z}\/{y}\/{x}';\n\/\/ Echte Reliefkarte (topografisch, mit Gel\u00e4ndeschattierung) \u2014 damit sich TERRAIN\n\/\/ klar von der gebrandeten Basiskarte (DAY\/NIGHT) unterscheidet.\nvar _TERR  = 'https:\/\/server.arcgisonline.com\/ArcGIS\/rest\/services\/World_Topo_Map\/MapServer\/tile\/{z}\/{y}\/{x}';\nvar _TILE  = {maxNativeZoom:16,maxZoom:19};\n\nvar mapLayers = {\n    NIGHT:    L.tileLayer(_DARK,  _TILE),\n    DAY:      L.tileLayer(_LIGHT, _TILE),\n    TERRAIN:  L.tileLayer(_TERR,  {maxZoom:19}),   \/\/ echtes Relief statt Voyager\n};\nvar MODE_BTN = { NIGHT:'btnNight', TERRAIN:'btnTerrain', DAYNIGHT:'btnDayNight' };\n\n\/\/ Eigene Basis-Layer NUR f\u00fcr den DAY\/NIGHT-Auto-Modus (getrennt von den manuellen\n\/\/ Buttons, damit sich nichts in die Quere kommt): hell = Tag, dunkel = Nacht.\n\/\/ Die Tagseite nutzt die cleane Light-Gray-Karte, per CSS-Filter (.aol-brandmap)\n\/\/ in warmes Aero-Lloyd-Elfenbein\/Gold get\u00f6nt. Nur DIESER Layer wird get\u00f6nt \u2014\n\/\/ Flieger, Routen, Aurora und die Terminator-Linie bleiben originalfarben.\nvar _dnLight = L.tileLayer(_LIGHT, {maxNativeZoom:16,maxZoom:19,className:'aol-brandmap'});\nvar _dnDark  = L.tileLayer(_DARK,  _TILE);\n\nvar activeMapLayer = mapLayers.NIGHT;\nactiveMapLayer.addTo(map);\nvar currentMode = 'NIGHT';\n\n\/\/ \u2500\u2500 Sonnenstand (nach echter\/Systemzeit) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar _DEG = Math.PI\/180;\nfunction _julian(d){ return d\/86400000 + 2440587.5; }\nfunction _gmst(jd){ return (18.697374558 + 24.06570982441908*(jd-2451545.0)) % 24; }\nfunction _sunEclLng(jd){\n    var n=jd-2451545.0, L=(280.460+0.9856474*n)%360, g=(357.528+0.9856003*n)%360;\n    return L + 1.915*Math.sin(g*_DEG) + 0.020*Math.sin(2*g*_DEG);\n}\nfunction _eclObliq(jd){ return 23.439 - 0.0000004*(jd-2451545.0); }\nfunction _sunPosition(){\n    var jd=_julian(new Date()), gst=_gmst(jd);\n    var lambda=_sunEclLng(jd), obliq=_eclObliq(jd);\n    var alpha=Math.atan2(Math.cos(obliq*_DEG)*Math.sin(lambda*_DEG), Math.cos(lambda*_DEG))\/_DEG;\n    var delta=Math.asin(Math.sin(obliq*_DEG)*Math.sin(lambda*_DEG))\/_DEG;\n    return { gst:gst, alpha:alpha, delta:delta };\n}\n\/\/ Steht die Sonne an (lat,lng) \u00fcber dem Horizont? -> Tag = true.\nfunction _isDayAt(lat, lng, sun){\n    var ha=(sun.gst + lng\/15)*15 - sun.alpha;\n    var sinH = Math.sin(lat*_DEG)*Math.sin(sun.delta*_DEG)\n             + Math.cos(lat*_DEG)*Math.cos(sun.delta*_DEG)*Math.cos(ha*_DEG);\n    return sinH > 0;\n}\n\/\/ Terminator-Grenzpunkte = die eigentliche Tag\/Nacht-Linie (ohne Pol-Schluss).\nfunction _termBoundary(sun){\n    var line=[];\n    for(var i=0;i<=720;i++){\n        var lng=-360+i;\n        var ha=(sun.gst + lng\/15)*15 - sun.alpha;\n        line.push([ Math.atan(-Math.cos(ha*_DEG)\/Math.tan(sun.delta*_DEG))\/_DEG, lng ]);\n    }\n    return line;\n}\n\n\/\/ \u2500\u2500 Tag\/Nacht-Overlay (IMMER sichtbar, in ALLEN Modi) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\/\/ Nacht-Schatten (dunkle Fl\u00e4che \u00fcber der Nacht-Seite) + bernsteinfarbene\n\/\/ Grenzlinie, nach echter\/Systemzeit berechnet. Einmal angelegt, liegen beide\n\/\/ dauerhaft \u00fcber NIGHT \/ TERRAIN \/ DAY-NIGHT und werden jede Minute nachgef\u00fchrt.\n\/\/ Der Schatten wird NICHT nach vorn geholt -> Flugrouten\/Flieger bleiben sichtbar,\n\/\/ nur die Basiskarte auf der Nacht-Seite wird abgedunkelt.\nvar _termLine = null, _termShade = null, _termTimer = null;\nfunction _drawTerminator(){\n    var sun  = _sunPosition();\n    var line = _termBoundary(sun);\n    var poly = line.slice();\n    if (sun.delta < 0) { poly.unshift([90,-360]); poly.push([90,360]); }\n    else               { poly.unshift([-90,-360]); poly.push([-90,360]); }\n\n    if (_termShade && map.hasLayer(_termShade)) { _termShade.setLatLngs(poly); }\n    else {\n        _termShade = L.polygon(poly, {\n            stroke:false, fillColor:'#080b24', fillOpacity:.46, interactive:false\n        }).addTo(map);\n    }\n    if (_termLine && map.hasLayer(_termLine)) { _termLine.setLatLngs(line); }\n    else {\n        _termLine = L.polyline(line, {\n            color:'#F2A900', weight:1.8, opacity:.85, dashArray:'6,7', interactive:false\n        }).addTo(map);\n    }\n    _termLine.bringToFront();\n}\n\nfunction setMapMode(mode) {\n    if (!MODE_BTN[mode] || mode === currentMode) return;\n\n    if (activeMapLayer) map.removeLayer(activeMapLayer);\n    \/\/ DAY\/NIGHT nutzt die helle Voyager-Basis; sonst die jeweilige Mode-Basis.\n    activeMapLayer = (mode === 'DAYNIGHT') ? _dnLight : mapLayers[mode];\n    activeMapLayer.addTo(map);\n    currentMode = mode;\n\n    if (_termLine) _termLine.bringToFront();   \/\/ Grenzlinie in jedem Modus oben halten\n\n    Object.keys(MODE_BTN).forEach(function(m){\n        var b = document.getElementById(MODE_BTN[m]);\n        if(!b) return;\n        b.style.background = m===mode ? '#2D297A' : '#333';\n        b.style.color      = m===mode ? '#fff'    : '#aaa';\n    });\n}\n\nvar planeSvg='<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"30\" height=\"30\" viewBox=\"0 0 64 64\" style=\"filter:drop-shadow(0 2px 8px rgba(247,108,30,.8))\">'\n+'<ellipse cx=\"32\" cy=\"32\" rx=\"5\" ry=\"22\" fill=\"#F76C1E\" stroke=\"white\" stroke-width=\"1.5\"\/>'\n+'<path d=\"M32 28 L4 44 L4 48 L32 40 L60 48 L60 44 Z\" fill=\"#F76C1E\" stroke=\"white\" stroke-width=\"1.5\"\/>'\n+'<path d=\"M32 50 L20 58 L20 60 L32 56 L44 60 L44 58 Z\" fill=\"#F76C1E\" stroke=\"white\" stroke-width=\"1.5\"\/>'\n+'<ellipse cx=\"32\" cy=\"12\" rx=\"4\" ry=\"5\" fill=\"#F2A900\" stroke=\"white\" stroke-width=\"1\"\/>'\n+'<\/svg>';\n\nvar markers = {}, routeLines = {}, trailLines = {}, trailPts = {};\nvar activeRegs = {};\n\nfunction getOrCreateMarker(reg, d) {\n    var ll = [d.latitude, d.longitude];\n    if (!markers[reg]) {\n        var icon = L.divIcon({\n            html:'<div class=\"liveAc\" style=\"transform:rotate(0deg);transform-origin:center;width:30px;height:30px;\">'+planeSvg+'<\/div>',\n            iconSize:[30,30],iconAnchor:[15,15],className:''\n        });\n        var m = L.marker(ll, {icon:icon}).addTo(map);\n        \/\/ Click popup\n        m.on('click', function() {\n            var orig = icaoShort[d.origin]      || d.origin      || '?';\n            var dest = icaoShort[d.destination] || d.destination || '?';\n            var ph   = _phaseNames[d.phase]     || '';\n\n            \/\/ ETA calculation\n            var etaStr = '\u2014';\n            if (d.ground_speed > 10 && airportCoords[d.destination]) {\n                var dc = airportCoords[d.destination];\n                var R  = 6371;\n                var dLat = (dc[0] - d.latitude)  * Math.PI \/ 180;\n                var dLon = (dc[1] - d.longitude) * Math.PI \/ 180;\n                var a = Math.sin(dLat\/2)*Math.sin(dLat\/2)\n                      + Math.cos(d.latitude*Math.PI\/180)*Math.cos(dc[0]*Math.PI\/180)\n                      * Math.sin(dLon\/2)*Math.sin(dLon\/2);\n                var distKm = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));\n                var distNm = distKm \/ 1.852;\n                var etaMin = (distNm \/ d.ground_speed) * 60;\n                if (etaMin > 0 && etaMin < 1440) {\n                    var etaDt = new Date(Date.now() + etaMin * 60000);\n                    etaStr = etaDt.toUTCString().slice(17,22) + 'Z';\n                }\n            }\n\n            var content = '<div style=\"font-family:\\'Courier New\\',monospace;min-width:220px;\">'\n                + '<div style=\"font-size:14px;font-weight:700;color:#F2A900;margin-bottom:6px;\">'\n                + d.flight + '  &middot;  ' + d.registration + '<\/div>'\n                + '<div style=\"font-size:12px;color:#1a1a2e;margin-bottom:4px;\">'\n                + orig + ' &rarr; ' + dest + '<\/div>'\n                + '<div style=\"font-size:11px;color:#555;\">'\n                + 'FL' + Math.round(d.altitude\/100)\n                + '  &middot;  ' + d.ground_speed + ' kt'\n                + (ph ? '  &middot;  ' + ph : '')\n                + '<\/div>'\n                + '<div style=\"font-size:11px;color:#2D297A;margin-top:4px;font-weight:700;\">'\n                + 'ETA: ' + etaStr\n                + '<\/div>'\n                + '<\/div>';\n            m.bindPopup(content, {maxWidth:280}).openPopup();\n        });\n        markers[reg] = m;\n    }\n    return markers[reg];\n}\n\nfunction updateAircraft(d) {\n    var reg = d.registration;\n    var ll  = [d.latitude, d.longitude];\n    var m   = getOrCreateMarker(reg, d);\n    m.setLatLng(ll);\n    var el = m.getElement();\n    if (el) { var ac = el.querySelector('.liveAc'); if (ac) ac.style.transform = 'rotate('+d.heading+'deg)'; }\n\n    \/\/ Dashed route line (no destination label)\n    if (!routeLines[reg] && d.origin && d.destination && airportCoords[d.origin] && airportCoords[d.destination]) {\n        routeLines[reg] = L.polyline([airportCoords[d.origin], airportCoords[d.destination]],\n            {color:'#2D297A',weight:1.5,dashArray:'6,8',opacity:.5}).addTo(map);\n    }\n\n    if (!trailPts[reg]) trailPts[reg] = [];\n    trailPts[reg].push(ll);\n    if (trailPts[reg].length > 150) trailPts[reg].shift();\n    \/\/ Trail IN PLACE aktualisieren statt Layer zu l\u00f6schen + neu erzeugen \u2014 das\n    \/\/ L\u00f6schen\/Neuzeichnen war die Ursache f\u00fcrs periodische Flackern der Karte.\n    if (!trailLines[reg]) {\n        trailLines[reg] = L.polyline(trailPts[reg], {color:'#F76C1E',weight:1.5,opacity:.4}).addTo(map);\n    } else {\n        trailLines[reg].setLatLngs(trailPts[reg]);\n    }\n    activeRegs[reg] = Date.now();\n}\n\nfunction removeStaleAircraft(currentRegs) {\n    Object.keys(activeRegs).forEach(function(reg) {\n        if (currentRegs.indexOf(reg) === -1) {\n            if (markers[reg])    { map.removeLayer(markers[reg]);    delete markers[reg]; }\n            if (routeLines[reg]) { map.removeLayer(routeLines[reg]); delete routeLines[reg]; }\n            if (trailLines[reg]) { map.removeLayer(trailLines[reg]); delete trailLines[reg]; }\n            delete trailPts[reg];\n            delete activeRegs[reg];\n        }\n    });\n}\n\nvar airportCoords={\n    'EDDF':[50.0264,8.5431],'EDDH':[53.6304,9.9882],'LEPA':[39.5517,2.7388],\n    'LEIB':[38.8729,1.3731],'LEBL':[41.2974,2.0785],'GCFV':[28.4527,-13.8638],\n    'GCRR':[28.9455,-13.6052],'GCTS':[28.0445,-16.5726],'LGIR':[35.3397,25.1803],\n    'LGRP':[36.4054,28.0862],'LGKR':[39.6019,19.9117],'LGSR':[36.3992,25.4793],\n    'EGLL':[51.4775,-0.4614],'EGPH':[55.9500,-3.3725],'LIRN':[40.8860,14.2908],\n    'LFMN':[43.6584,7.2159],'LPMA':[32.6979,-16.7745],\n};\nvar icaoShort={\n    'EDDF':'Frankfurt\/Main','EDDH':'Hamburg','LEPA':'Palma de Mallorca',\n    'LEIB':'Ibiza','LEBL':'Barcelona','GCFV':'Fuerteventura',\n    'GCRR':'Lanzarote','GCTS':'Tenerife Sur','LGIR':'Heraklion',\n    'LGRP':'Rhodes','LGKR':'Corfu','LGSR':'Santorini',\n    'EGLL':'London Heathrow','EGPH':'Edinburgh','LIRN':'Naples',\n    'LFMN':'Nice','LPMA':'Funchal',\n};\nvar phaseNames=['Boarding','Departing','Takeoff','Climb','Cruise','Descent','Approach','Landing','Taxi In','On Block'];\n\n\n\n\/\/ \u2500\u2500 Info Card Carousel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar _carouselPositions = [];\nvar _carouselIndex     = 0;\nvar _carouselTimer     = null;\nvar _phaseNames = ['Boarding','Departing','Takeoff','Climbing','Cruise',\n                   'Descending','Approach','Landing','Taxi In','On Block'];\n\nfunction showCarouselSlide(idx) {\n    if (!_carouselPositions.length) return;\n    idx = ((idx % _carouselPositions.length) + _carouselPositions.length) % _carouselPositions.length;\n    _carouselIndex = idx;\n    var d    = _carouselPositions[idx];\n    var orig = icaoShort[d.origin]      || d.origin      || '?';\n    var dest = icaoShort[d.destination] || d.destination || '?';\n    var ph   = d.phase >= 0 ? (_phaseNames[d.phase] || '') : '';\n    var n    = _carouselPositions.length;\n    var el   = document.getElementById('mapFlight');\n    var er   = document.getElementById('mapRoute');\n    var ed   = document.getElementById('mapDetail');\n\n    \/\/ Fade out\n    [el, er, ed].forEach(function(e){ if(e) e.style.opacity = '0'; });\n\n    setTimeout(function(){\n        if (el) el.textContent = d.flight + '   ' + d.registration\n            + (n > 1 ? '   (' + (idx+1) + '\/' + n + ')' : '');\n        if (er) er.textContent = orig + ' \\u2192 ' + dest;\n        if (ed) ed.textContent = 'FL' + Math.round(d.altitude\/100)\n            + '  \\u00b7  ' + d.ground_speed + ' kt'\n            + (ph ? '  \\u00b7  ' + ph : '');\n        [el, er, ed].forEach(function(e){ if(e) e.style.transition='opacity .4s'; e.style.opacity='1'; });\n    }, 300);\n}\n\nfunction startCarousel(positions) {\n    _carouselPositions = positions;\n    if (_carouselTimer) clearInterval(_carouselTimer);\n    showCarouselSlide(0);\n    if (positions.length > 1) {\n        _carouselTimer = setInterval(function(){\n            showCarouselSlide(_carouselIndex + 1);\n        }, 10000);\n    }\n}\n\nfunction updateInfoCard(positions) {\n    if (!positions || positions.length === 0) {\n        if (_carouselTimer) { clearInterval(_carouselTimer); _carouselTimer = null; }\n        _carouselPositions = [];\n        document.getElementById('mapFlight').textContent = '\u2014\u2014';\n        document.getElementById('mapRoute').textContent  = 'Awaiting next departure';\n        document.getElementById('mapDetail').textContent = '\u2014\u2014';\n        document.getElementById('mapStatusDot').className = '';\n        document.getElementById('mapStatusTxt').textContent = 'No active flight';\n        document.getElementById('mapUpdated').textContent = '\u2014';\n        return;\n    }\n    startCarousel(positions);\n    var n = positions.length;\n    document.getElementById('mapStatusDot').className = 'active';\n    document.getElementById('mapStatusTxt').textContent = n > 1\n        ? n + ' pilots online'\n        : positions[0].flight + '  \\u00b7  '\n            + (icaoShort[positions[0].origin]||positions[0].origin)\n            + ' \\u2192 '\n            + (icaoShort[positions[0].destination]||positions[0].destination);\n    var t = new Date();\n    document.getElementById('mapUpdated').textContent =\n        'Updated ' + t.toLocaleTimeString('en-GB',{hour:'2-digit',minute:'2-digit',second:'2-digit'}) + ' UTC';\n}\n\nfunction fetchLive(){\n    fetch('https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/nexus\/v1\/live')\n        .then(function(r){ return r.json(); })\n        .then(function(data){\n            var positions = data.positions || [];\n            var currentRegs = positions.map(function(p){ return p.registration; });\n            positions.forEach(function(d){\n                if (d.latitude && d.longitude) updateAircraft(d);\n            });\n            removeStaleAircraft(currentRegs);\n            updateInfoCard(positions.filter(function(p){ return p.latitude && p.longitude; }));\n        }).catch(function(){});\n}\n\n\/\/ \u2500\u2500 FIDS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nfunction statusConfig(status){\n    var cfg={\n        'SCHEDULED':  {cls:'status-scheduled', txt:'SCHEDULED',  leds:''},\n        'GATE OPEN':  {cls:'status-gate-open', txt:'GATE OPEN',\n                       leds:'<span class=\"led led-green blink-green\"><\/span><span class=\"led led-green blink-green\"><\/span>'},\n        'BOARDING':   {cls:'status-boarding',  txt:'BOARDING',\n                       leds:'<span class=\"led led-amber blink-amber\"><\/span><span class=\"led led-amber blink-amber\"><\/span>'},\n        'FINAL CALL': {cls:'status-final-call',txt:'FINAL CALL',\n                       leds:'<span class=\"led led-red blink-red\"><\/span><span class=\"led led-red blink-red\"><\/span>'},\n        'IN FLIGHT':  {cls:'status-on-time',   txt:'IN FLIGHT',  leds:''},\n        'ARRIVED':    {cls:'status-landed',    txt:'ARRIVED',    leds:''},\n        'DIVERTED':   {cls:'status-delayed',   txt:'DIVERTED',   leds:''},\n        'DEPARTED':   {cls:'status-departed',  txt:'DEPARTED',   leds:''},\n        'SCHEDULED':  {cls:'status-scheduled', txt:'SCHEDULED',  leds:''},\n        'GATE OPEN':  {cls:'status-gate-open', txt:'GATE OPEN',  leds:''},\n        'BOARDING':   {cls:'status-boarding',  txt:'BOARDING',   leds:''},\n        'FINAL CALL': {cls:'status-final-call',txt:'FINAL CALL', leds:''},\n    };\n    return cfg[status]||{cls:'status-scheduled',txt:status,leds:''};\n}\n\n\/\/ \u2500\u2500 SPLIT-FLAP ENGINE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar CHARS = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\u2192\u00b7\/-';\nvar sfState = {}; \/\/ tracks current char per element id\n\nfunction sfMakeCell(id, text, width, cls) {\n    var padded = text.toUpperCase().padEnd(width, ' ').substring(0, width);\n    var html = '<span class=\"sf-cell'+(cls?' '+cls:'')+'\" id=\"sfc-'+id+'\">';\n    for (var i = 0; i < width; i++) {\n        html += '<span class=\"sf-char\" id=\"sfc-'+id+'-'+i+'\">'+escHtml(padded[i])+'<\/span>';\n    }\n    return html + '<\/span>';\n}\n\n\/\/ \u2500\u2500 Solari flip sound (Web Audio API) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar _sfAudioCtx = null;\nvar _sfSoundOn  = true;   \/\/ Sound-An\/Aus (Schalter im Board-Header). Default: an.\nfunction sfGetAudioCtx() {\n    if (!_sfAudioCtx) {\n        try { _sfAudioCtx = new (window.AudioContext || window.webkitAudioContext)(); } catch(e){}\n    }\n    return _sfAudioCtx;\n}\n\nfunction sfPlayClack(delayMs) {\n    if (!_sfSoundOn) return;   \/\/ stumm, wenn der Schalter auf OFF steht\n    var ctx = sfGetAudioCtx();\n    if (!ctx) return;\n    var when = ctx.currentTime + delayMs \/ 1000;\n    var bufSize = Math.floor(ctx.sampleRate * 0.055); \/\/ 55ms \u2014 slightly longer\n    var buf = ctx.createBuffer(1, bufSize, ctx.sampleRate);\n    var data = buf.getChannelData(0);\n    for (var i = 0; i < bufSize; i++) {\n        data[i] = (Math.random() * 2 - 1) * (1 - i \/ bufSize) * 0.9;\n    }\n    var src = ctx.createBufferSource();\n    src.buffer = buf;\n    var bpf = ctx.createBiquadFilter();\n    bpf.type = 'bandpass';\n    bpf.frequency.value = 1400; \/\/ slightly lower = more mechanical\n    bpf.Q.value = 0.6;\n    var gain = ctx.createGain();\n    gain.gain.value = 0.15;\n    src.connect(bpf);\n    bpf.connect(gain);\n    gain.connect(ctx.destination);\n    src.start(when);\n}\n\nfunction sfUpdate(id, newText, width) {\n    var padded = newText.toUpperCase().padEnd(width, ' ').substring(0, width);\n    var prev   = sfState[id] || ''.padEnd(width, ' ');\n    sfState[id] = padded;\n\n    for (var i = 0; i < width; i++) {\n        (function(idx) {\n            var el = document.getElementById('sfc-'+id+'-'+idx);\n            if (!el) return;\n            if (prev[idx] === padded[idx]) return;\n            var targetChar = padded[idx];\n            var delay = idx * 110; \/\/ Klack-Takt: 110ms pro Zeichen (langsamer als vorher 70ms)\n            sfPlayClack(delay);\n            setTimeout(function() {\n                el.classList.add('flipping');\n                setTimeout(function() {\n                    el.textContent = targetChar;\n                    el.classList.remove('flipping');\n                }, 160); \/\/ match animation duration\n            }, delay);\n        })(i);\n    }\n}\n\nfunction escHtml(c) {\n    if (c === '<') return '&lt;';\n    if (c === '>') return '&gt;';\n    if (c === '&') return '&amp;';\n    return c;\n}\n\n\/\/ Status LED config\nfunction sfLed(status) {\n    var g = '<span class=\"sf-led green led-a\" style=\"margin-right:3px;\"><\/span><span class=\"sf-led green led-b\"><\/span>';\n    var r = '<span class=\"sf-led\" style=\"background:#C8102E;display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:3px;box-shadow:0 0 5px #C8102E;\"><\/span><span class=\"sf-led\" style=\"background:#C8102E;display:inline-block;width:7px;height:7px;border-radius:50%;box-shadow:0 0 5px #C8102E;\"><\/span>';\n    var e = '<span class=\"sf-led grey\" style=\"margin-right:3px;opacity:0;\"><\/span><span class=\"sf-led grey\" style=\"opacity:0;\"><\/span>';\n    if (status === 'BOARDING')   return g;\n    if (status === 'DEPARTING')  return g;\n    if (status === 'GATE OPEN')  return g;\n    if (status === 'FINAL CALL') return g;\n    if (status === 'DIVERTED')   return r;\n    if (status === 'ARRIVED')    return e;\n    return e;\n}\n\nfunction sfStatusColor(status) {\n    var colors = {\n        'IN FLIGHT':  '#4ade80',\n        'ARRIVED':    '#555',\n        'DIVERTED':   '#C8102E',\n        'BOARDING':   '#4ade80',\n        'DEPARTING':  '#4ade80',\n        'GATE OPEN':  '#4ade80',\n        'FINAL CALL': '#F76C1E',\n        'LANDING':    '#4ade80',\n        'TAXI IN':    '#F2A900',\n        'DEPARTED':   '#333',\n        'SCHEDULED':  '#444',\n    };\n    return colors[status] || '#555';\n}\n\nfunction calcETA(f) {\n    if (!f.speed || f.speed < 10 || !f.dest_icao || !airportCoords[f.dest_icao]) return '\u2014';\n    var dc   = airportCoords[f.dest_icao];\n    var R    = 6371;\n    var dLat = (dc[0] - f.lat) * Math.PI \/ 180;\n    var dLon = (dc[1] - f.lon) * Math.PI \/ 180;\n    var a    = Math.sin(dLat\/2)*Math.sin(dLat\/2)\n             + Math.cos(f.lat*Math.PI\/180)*Math.cos(dc[0]*Math.PI\/180)\n             * Math.sin(dLon\/2)*Math.sin(dLon\/2);\n    var distNm = R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)) \/ 1.852;\n    var minLeft = (distNm \/ f.speed) * 60;\n    if (minLeft < 0 || minLeft > 1440) return '\u2014';\n    var eta = new Date(Date.now() + minLeft * 60000);\n    return eta.toUTCString().slice(17,22) + 'Z';\n}\n\nvar sfInitialized = false;\nvar sfLastData    = [];\n\nfunction renderFIDS(data) {\n    var board = document.getElementById('sfBoard');\n    if (!data.flights || !data.flights.length) {\n        board.innerHTML = '<div class=\"sf-empty\">NO FLIGHTS TODAY<\/div>';\n        sfInitialized = false;\n        sfLastData = [];\n        return;\n    }\n\n    if (!sfInitialized) {\n        \/\/ First render \u2014 build DOM with BLANK cells, then animate in\n        var html = '';\n        data.flights.forEach(function(f, i) {\n            html += '<div class=\"sf-row\" id=\"sfrow-'+i+'\">'\n                + '<div id=\"sfled-'+i+'\">' + sfLed('') + '<\/div>'\n                + sfMakeCell('fn'+i,       '', 8)\n                + sfMakeCell('reg'+i,      '', 6)\n                + '<span id=\"sfdep-'+i+'\" style=\"font-family:\\'Courier New\\',monospace;font-size:12px;font-weight:700;color:#F2A900;padding-left:12px;\"><\/span>'\n                + sfMakeCell('depgate'+i,  '', 4, 'gate-cell')\n                + '<span id=\"sfarr-'+i+'\" style=\"font-family:\\'Courier New\\',monospace;font-size:12px;font-weight:700;color:#aac4ff;text-align:right;\"><\/span>'\n                + '<span id=\"sfeta-'+i+'\" style=\"font-family:\\'Courier New\\',monospace;font-size:12px;color:#8888aa;text-align:right;padding-right:12px;\"><\/span>'\n                + sfMakeCell('arrgate'+i,  '', 4, 'gate-cell')\n                + '<div class=\"sf-status\" id=\"sfst-'+i+'\"><\/div>'\n                + '<\/div>';\n        });\n        board.innerHTML = html;\n        sfInitialized = true;\n        sfLastData = [];\n\n        \/\/ Animate each row in with staggered delay\n        data.flights.forEach(function(f, i) {\n            var rowDelay = i * 300;\n            setTimeout(function() {\n                \/\/ Flip in flight number + reg\n                sfUpdate('fn'+i,      f.flight||'',   8);\n                sfUpdate('reg'+i,     f.reg||'',      6);\n                var depEl = document.getElementById('sfdep-'+i);\n                if (depEl) depEl.textContent = f.dep||'';\n                sfUpdate('depgate'+i, f.dep_gate||'', 4);\n                var arrEl = document.getElementById('sfarr-'+i);\n                if (arrEl) arrEl.textContent = f.arr||'';\n                var etaEl = document.getElementById('sfeta-'+i);\n                if (etaEl) etaEl.textContent = calcETA(f);\n                sfUpdate('arrgate'+i, f.arr_gate||'', 4);\n                var ledEl = document.getElementById('sfled-'+i);\n                if (ledEl) ledEl.innerHTML = sfLed(f.status);\n                var stEl = document.getElementById('sfst-'+i);\n                if (stEl) {\n                    stEl.style.color = sfStatusColor(f.status);\n                    stEl.innerHTML = '<span style=\"font-family:\\'Courier New\\',monospace;font-size:12px;font-weight:700;letter-spacing:.1em;\">'+f.status+'<\/span>';\n                }\n            }, rowDelay);\n        });\n        sfLastData = data.flights;\n\n    } else {\n        \/\/ Update \u2014 animate only changed values\n        data.flights.forEach(function(f, i) {\n            var prev = sfLastData[i] || {};\n\n            \/\/ Update LED\n            if (prev.status !== f.status) {\n                var ledEl = document.getElementById('sfled-'+i);\n                if (ledEl) ledEl.innerHTML = sfLed(f.status);\n            }\n\n            \/\/ Update split-flap cells\n            if (prev.flight    !== f.flight)    sfUpdate('fn'+i,      f.flight||'',   8);\n            if (prev.reg       !== f.reg)       sfUpdate('reg'+i,     f.reg||'',      6);\n            if (prev.dep       !== f.dep)  { var de=document.getElementById('sfdep-'+i); if(de) de.textContent=f.dep||''; }\n            if (prev.dep_gate  !== f.dep_gate)  sfUpdate('depgate'+i, f.dep_gate||'', 4);\n            if (prev.arr       !== f.arr)  { var ae=document.getElementById('sfarr-'+i); if(ae) ae.textContent=f.arr||''; }\n            var etaEl = document.getElementById('sfeta-'+i);\n            if (etaEl) etaEl.textContent = calcETA(f);\n            if (prev.arr_gate  !== f.arr_gate)  sfUpdate('arrgate'+i, f.arr_gate||'', 4);\n            if (prev.route  !== f.route) {\n                var rtEl = document.getElementById('sfrt-'+i);\n                if (rtEl) rtEl.textContent = (f.route||'').replace(\/->\/g,'\\u2192');\n            }\n\n            \/\/ Update status\n            if (prev.status !== f.status) {\n                var stEl = document.getElementById('sfst-'+i);\n                if (stEl) {\n                    stEl.style.color = sfStatusColor(f.status);\n                    stEl.innerHTML = '<span style=\"font-family:\\'Courier New\\',monospace;font-size:12px;font-weight:700;letter-spacing:.1em;\">'+f.status+'<\/span>';\n                }\n            }\n        });\n        sfLastData = data.flights;\n    }\n}\n\nfunction fetchFIDS(){\n    fetch('https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/nexus\/v1\/fids')\n        .then(r=>r.json()).then(function(d){ renderFIDS(d); })\n        .catch(function(){});\n}\n\n\/\/ \u2500\u2500 CLOCK \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nsetInterval(function(){\n    var now = new Date();\n    var fra = now.toLocaleTimeString('en-GB',{timeZone:'Europe\/Berlin',hour:'2-digit',minute:'2-digit'});\n    var utc = now.toLocaleTimeString('en-GB',{timeZone:'UTC',hour:'2-digit',minute:'2-digit'});\n    var dat = now.toLocaleDateString('en-GB',{timeZone:'UTC',day:'2-digit',month:'short',year:'numeric'}).toUpperCase();\n    var el  = document.getElementById('sfClock');\n    var eu  = document.getElementById('sfUTC');\n    var ed  = document.getElementById('sfDate');\n    \/\/ Nur schreiben, wenn sich der angezeigte Wert wirklich aendert (HH:MM).\n    \/\/ Ein textContent-Write pro Sekunde erzwingt sonst einen Reflow des\n    \/\/ gesamten Boards und laesst es sichtbar \"zucken\".\n    var fraTxt = fra + ' FRA LOCAL', utcTxt = utc + 'Z';\n    if (el && el.textContent !== fraTxt) el.textContent = fraTxt;\n    if (eu && eu.textContent !== utcTxt) eu.textContent = utcTxt;\n    if (ed && ed.textContent !== dat)    ed.textContent = dat;\n},1000);\n\n\/\/ \u2500\u2500 MAP MODE BUTTONS \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ndocument.getElementById('btnNight')   .addEventListener('click', function(){ setMapMode('NIGHT');    });\ndocument.getElementById('btnTerrain') .addEventListener('click', function(){ setMapMode('TERRAIN');  });\ndocument.getElementById('btnDayNight').addEventListener('click', function(){ setMapMode('DAYNIGHT'); });\n\n\/\/ \u2500\u2500 AURORA (Live-Nordlicht-Zonen, NOAA OVATION) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nvar _auroraOn = false, _auroraLayer = null, _auroraTimer = null;\n\/\/ Eigener, weichgezeichneter Pane -> aus den gekachelten Zellen werden weiche,\n\/\/ organische Schleier (kein K\u00e4stchen-Look). Liegt \u00fcber dem Nacht-Schatten (damit\n\/\/ das Gr\u00fcn leuchtet), unter den Fliegern.\nmap.createPane('auroraPane');\n(function(){\n    var p = map.getPane('auroraPane');\n    p.style.zIndex = 410;\n    p.style.pointerEvents = 'none';\n    p.style.filter = 'blur(7px)';\n})();\nvar _auroraCanvas = L.canvas({ padding: 0.5, pane: 'auroraPane' });\nfunction _renderAurora(points){\n    if (_auroraLayer) { map.removeLayer(_auroraLayer); _auroraLayer = null; }\n    if (!points || !points.length) return;\n    var group = L.layerGroup();\n    points.forEach(function(p){\n        var lat = p[0], lng = p[1], val = p[2];\n        var op  = Math.min(0.90, (val\/100) * 1.8 + 0.16);   \/\/ Wahrscheinlichkeit -> Deckkraft\n        \/\/ Gef\u00fcllte Gitterzelle (~1\u00b0 lat x 2\u00b0 lon) statt Punkt -> zusammenh\u00e4ngende\n        \/\/ Fl\u00e4chen statt Streifen; die Zellen kacheln l\u00fcckenlos aneinander.\n        L.rectangle([[lat-0.5, lng-1],[lat+0.5, lng+1]], {\n            renderer: _auroraCanvas, stroke: false,\n            fillColor: '#127a38', fillOpacity: op, interactive: false   \/\/ dunkleres Gr\u00fcn\n        }).addTo(group);\n    });\n    _auroraLayer = group.addTo(map);\n    if (_termLine) _termLine.bringToFront();   \/\/ Grenzlinie \u00fcber der Aurora halten\n}\nfunction _fetchAurora(){\n    if (!_auroraOn) return;\n    fetch('https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/nexus\/v1\/aurora')\n        .then(function(r){ return r.json(); })\n        .then(function(d){ if (_auroraOn) _renderAurora(d.points || []); })\n        .catch(function(){});\n}\n(function(){\n    var btn = document.getElementById('btnAurora');\n    if (!btn) return;\n    btn.addEventListener('click', function(){\n        _auroraOn = !_auroraOn;\n        btn.style.background = _auroraOn ? '#12643a' : '#333';\n        btn.style.color      = _auroraOn ? '#5bff9d' : '#aaa';\n        if (_auroraOn) {\n            _fetchAurora();\n            if (!_auroraTimer) _auroraTimer = setInterval(_fetchAurora, 600000); \/\/ alle 10 Min\n        } else {\n            if (_auroraTimer) { clearInterval(_auroraTimer); _auroraTimer = null; }\n            if (_auroraLayer) { map.removeLayer(_auroraLayer); _auroraLayer = null; }\n        }\n    });\n})();\n\n\/\/ \u2500\u2500 SOUND ON\/OFF TOGGLE \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(function(){\n    var btn = document.getElementById('sfSoundToggle');\n    if (!btn) return;\n    btn.addEventListener('click', function(){\n        _sfSoundOn = !_sfSoundOn;\n        btn.textContent = _sfSoundOn ? '\u266a SOUND ON' : '\u266a SOUND OFF';\n        btn.style.color = _sfSoundOn ? '#F2A900' : '#666';\n        if (_sfSoundOn) {   \/\/ beim Einschalten Audio-Context freigeben\n            var ctx = sfGetAudioCtx();\n            if (ctx && ctx.state === 'suspended') ctx.resume();\n        }\n    });\n})();\n\n\/\/ Unlock Web Audio on first user interaction (browser requirement)\ndocument.addEventListener('click', function unlockAudio() {\n    var ctx = sfGetAudioCtx();\n    if (ctx && ctx.state === 'suspended') ctx.resume();\n    document.removeEventListener('click', unlockAudio);\n}, { once: true });\n\n\/\/ \u2500\u2500 INIT \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\/\/ Tag\/Nacht-Overlay (Nacht-Schatten + Grenzlinie) dauerhaft anlegen (in ALLEN Modi\n\/\/ sichtbar) + min\u00fctlich f\u00fchren.\n_drawTerminator();\nif (!_termTimer) _termTimer = setInterval(_drawTerminator, 60000);\n\n\/\/ Standard-Kartenmodus: DAY\/NIGHT (Auto) \u2014 die ganze Karte zeigt gleich beim Laden\n\/\/ die richtige Helligkeit nach echter Zeit (hell am Tag \/ dunkel nachts) statt fest \u201enight\".\nsetMapMode('DAYNIGHT');\n\nfetchLive();setInterval(fetchLive, 30000);\n\n})();\n<\/script>\n    \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-512","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/pages\/512","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/comments?post=512"}],"version-history":[{"count":1,"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/pages\/512\/revisions"}],"predecessor-version":[{"id":513,"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/pages\/512\/revisions\/513"}],"wp:attachment":[{"href":"https:\/\/flyaerolloydvirtual.com\/de\/wp-json\/wp\/v2\/media?parent=512"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}