PageSourceSearch

https://media-atelier.tv/projekte.html

html media-atelier.tv collected 2026-10-08 10:56:21 UTC 30,554 bytes, 440 lines download raw bytes

1<!DOCTYPE html>
2<html lang="de">
3<head>
4  <style>
5    html, body { background-color: #f0f2f5; }
6  </style>
7    <meta charset="UTF-8">
8    <meta name="viewport" content="width=device-width, initial-scale=1.0">
9    <title>Projekte – Ausgewählte Arbeiten für ZDF, SWR, ARTE & mehr | Media Atelier</title>
10    <meta name="description" content="Unsere Projekte: Postproduktion für ZDF, SWR, ARTE, 3sat und weitere. Schnitt, Sounddesign, Color Grading und VFX für Dokumentationen und Magazine.">
11    <meta name="robots" content="index, follow">
12    <link rel="canonical" href="https://www.media-atelier.tv/projekte.html">
13    <meta property="og:type" content="website">
14    <meta property="og:url" content="https://www.media-atelier.tv/projekte.html">
15    <meta property="og:title" content="Projekte – Media Atelier Mainz">
16    <meta property="og:description" content="Ausgewählte Arbeiten für ZDF, SWR, ARTE und weitere Sender.">
17    <meta property="twitter:card" content="summary_large_image">
18    <link rel="stylesheet" href="tailwind-built.css">
19    <link rel="stylesheet" href="fonts.css">
20    
20<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.js"></script>
20
21    
21<script src="data.js"></script>
21
22    <link rel="stylesheet" href="styles.css?v=2.0">
23    <style>
24        .format-btn {
25            padding: 0.75rem 1.75rem;
26            border-radius: 50px;
27            border: 1px solid rgba(255,255,255,0.15);
28            background: rgba(255,255,255,0.05);
29            color: rgba(255,255,255,0.8);
30            font-size: 0.9rem;
31            font-weight: 700;
32            cursor: pointer;
33            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
34            text-transform: uppercase;
35            letter-spacing: 0.05em;
36            box-shadow: 0 4px 15px rgba(0,0,0,0.1);
37        }
38        .format-btn:hover {
39            border-color: #fedf00;
40            color: #fedf00;
41            background: rgba(254, 223, 0, 0.05);
42            transform: translateY(-2px);
43        }
44        .format-btn.active {
45            background: #fedf00;
46            color: #4d4f53;
47            border-color: #fedf00;
48            font-weight: 800;
49            box-shadow: 0 4px 20px rgba(254, 223, 0, 0.25);
50            transform: translateY(-2px);
51        }
52    </style>
53    <link rel="icon" type="image/png" href="Bilder/MA/m_hellgrau_rgb_small_wabe.webp">
54    
54<script defer src="https://cloud.umami.is/script.js" data-website-id="b75518e1-7dc1-43ef-8c1e-9a261a686e78"></script>
54
55</head>
56<body class="antialiased flex flex-col min-h-screen">
57    <!-- HEADER_START -->
58<header>
59    <div class="container mx-auto px-6 flex items-center justify-between w-full h-full">
60        <a href="index.html" class="shrink-0 z-50 flex items-center">
61            <img src="Bilder/MA/m_hellgrau_rgb_small_wabe.webp" alt="Media Atelier Logo" class="h-8 md:h-10 w-auto hover:opacity-80 transition-opacity">
62        </a>
63        <div class="hidden md:flex items-center justify-center flex-grow">
64            <nav class="flex gap-2 items-center">
65                <a href="index.html" class="nav-link">Home</a>
66                <a href="ueber-uns.html" class="nav-link">Über Uns</a>
67                <a href="leistungen.html" class="nav-link">Leistungen</a>
68                <a href="projekte.html" class="nav-link active">Projekte</a>
69            </nav>
70        </div>
71        <div class="hidden md:flex items-center shrink-0">
72            <a href="kontakt.html" class="btn-contact shadow-lg">Kontakt</a>
73        </div>
74        <button id="mobile-menu-btn" class="md:hidden text-white hover:text-brand-yellow p-2 focus:outline-none ml-auto">
75            <i data-lucide="menu" class="w-8 h-8"></i>
76        </button>
77    </div>
78    <div id="mobile-menu" class="hidden absolute top-[90px] left-0 w-full bg-[#4d4f53] border-t border-gray-600 shadow-2xl p-6 z-40">
79        <div class="flex flex-col space-y-4">
80            <a href="index.html" class="text-white font-bold text-lg py-3 border-b border-gray-600 uppercase">Home</a>
81            <a href="ueber-uns.html" class="text-white font-bold text-lg py-3 border-b border-gray-600 uppercase">Über Uns</a>
82            <a href="leistungen.html" class="text-white font-bold text-lg py-3 border-b border-gray-600 uppercase">Leistungen</a>
83            <a href="projekte.html" class="text-brand-yellow font-bold text-lg py-3 border-b border-gray-600 uppercase">Projekte</a>
84            <a href="kontakt.html" class="text-brand-yellow font-bold text-lg py-3 uppercase">Kontakt</a>
85        </div>
86    </div>
87</header>
88<!-- HEADER_END -->
89
90    <main class="flex-grow">
91        <!-- HERO -->
92        <section class="bg-brand-dark text-white pt-32 pb-16 -mt-[90px]" style="padding-top: calc(90px + 5rem);">
93            <div class="container mx-auto px-6">
94                <div class="text-center mb-12 reveal-on-scroll">
95                    <span class="eyebrow" style="color:#ffffff;">Portfolio</span>
96                    <h1 class="section-title !text-white text-4xl md:text-5xl">Ausgewählte Arbeiten</h1>
97                </div>
98
99                <!-- SHOWREEL -->
100                <div class="mb-12 reveal-on-scroll" style="max-width: 900px; margin-left: auto; margin-right: auto;">
101                    <div class="text-center mb-6">
102                        <h2 class="text-brand-yellow font-bold tracking-wider uppercase text-xs mb-1">Showreel</h2>
103                        <p class="text-gray-400 text-sm">Ein Blick hinter die Kulissen unserer Postproduktion</p>
104                    </div>
105                    <div class="relative rounded-2xl overflow-hidden bg-black shadow-2xl shadow-brand-yellow/10 border border-white/10" id="showreel-wrapper">
106                        <video id="showreel-video" class="block mx-auto" preload="metadata" style="width: 100%; height: auto; max-height: 540px; object-fit: contain; background:#000;">
107                            <source src="Videos/MA_showreel_noBlack.mp4" type="video/mp4">
108                        </video>
109                        <div id="showreel-controls" class="absolute bottom-0 left-0 right-0 px-6 py-4 flex items-center gap-4" style="background: linear-gradient(transparent, rgba(0,0,0,0.85));">
110                            <button id="sr-play" class="text-white hover:text-brand-yellow transition-colors shrink-0">
111                                <svg id="sr-icon-play" xmlns="http://www.w3.org/2000/svg" class="w-8 h-8" fill="currentColor" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
112                                <svg id="sr-icon-pause" xmlns="http://www.w3.org/2000/svg" class="w-8 h-8 hidden" fill="currentColor" viewBox="0 0 24 24">
112<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
113                            </button>
114                            <div class="flex-grow relative h-1.5 bg-white/20 rounded-full cursor-pointer group" id="sr-progress-bar">
115                                <div id="sr-progress" class="h-full bg-brand-yellow rounded-full pointer-events-none" style="width:0%"></div>
116                                <div id="sr-thumb" class="absolute top-1/2 -translate-y-1/2 w-3.5 h-3.5 bg-brand-yellow rounded-full -translate-x-1/2 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" style="left:0%"></div>
117                            </div>
118                            <span id="sr-time" class="text-white/70 text-xs font-mono shrink-0">0:00 / 0:00</span>
119                            <div class="flex items-center gap-2 shrink-0">
120                                <button id="sr-mute" class="text-white/70 hover:text-white transition-colors">
121                                    <svg id="sr-icon-vol" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>
122                                    <svg id="sr-icon-muted" xmlns="http://www.w3.org/2000/svg" class="w-5 h-5 hidden" fill="currentColor" viewBox="0 0 24 24"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>
123                                </button>
124                                <input id="sr-volume" type="range" min="0" max="1" step="0.05" value="1" class="w-20 accent-brand-yellow cursor-pointer">
125                            </div>
126                            <button id="sr-fullscreen" class="text-white/70 hover:text-white transition-colors shrink-0">
127                                <svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/></svg>
128                            </button>
129                        </div>
130                        <div id="sr-play-overlay" class="absolute inset-0 flex items-center justify-center cursor-pointer" onclick="document.getElementById('sr-play').click()">
131                            <div class="w-20 h-20 bg-brand-yellow/90 rounded-full flex items-center justify-center shadow-2xl hover:scale-110 transition-transform">
132                                <svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-brand-dark ml-1" fill="currentColor" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>
133                            </div>
134                        </div>
135                    </div>
136                </div>
137
138                <!-- Quote -->
139                <div class="max-w-3xl mx-auto text-center mb-16 reveal-on-scroll">
140                    <p class="text-xl text-gray-300 leading-relaxed italic">
141                        „Jedes Projekt ist einzigartig. Wir kombinieren technisches Handwerk mit kreativer Vision, um Geschichten zu erzählen, die im Gedächtnis bleiben."
142                    </p>
143                    <div class="w-12 h-1 bg-brand-yellow mx-auto mt-6"></div>
144                </div>
145
146                <!-- Filters -->
147                <div class="bg-white/5 rounded-2xl p-8 mb-12 backdrop-blur-sm border border-white/10 reveal-on-scroll">
148                    <div class="mb-6">
149                        <h3 class="text-sm font-bold text-gray-400 uppercase tracking-widest mb-4 text-center">Format</h3>
150                        <div id="format-filters" class="flex flex-wrap justify-center gap-3">
151                            <button class="format-btn active" data-format="Fernsehen">Fernsehen & TV</button>
152                            <button class="format-btn" data-format="Imagefilm">Imagefilm & Corporate</button>
153                            <button class="format-btn" data-format="Hörbuch">Hörbücher & Podcast</button>
154                        </div>
155                    </div>
156                    <hr class="border-white/10" style="margin-top: 2rem; margin-bottom: 3.5rem;">
157                    <div id="sender-filter-row" class="mb-8">
158                        <h3 class="text-sm font-bold text-gray-400 uppercase tracking-widest mb-4 text-center">Sender</h3>
159                        <div id="sender-filters" class="flex flex-wrap justify-center gap-3">
160                            <button class="filter-btn active" data-filter="all">Alle</button>
161                        </div>
162                    </div>
163                    <div id="service-filter-row">
164                        <h3 class="text-sm font-bold text-gray-400 uppercase tracking-widest mb-4 text-center">Leistungen</h3>
165                        <div id="service-filters" class="flex flex-wrap justify-center gap-2"></div>
166                    </div>
167                </div>
168
169                <!-- Project Grid -->
170                <div id="project-grid" class="grid sm:grid-cols-2 lg:grid-cols-3 gap-8">
171                    <!-- JS Content -->
172                </div>
173            </div>
174        </section>
175
176        <!-- CTA SECTION -->
177        <section class="py-24 bg-brand-dark text-white text-center">
178            <div class="container mx-auto px-6 reveal-on-scroll">
179                <h2 class="text-3xl md:text-4xl font-serif font-bold mb-6">Sie planen ein ähnliches Projekt?</h2>
180                <p class="text-gray-300 max-w-xl mx-auto mb-10 text-lg">Lassen Sie uns gemeinsam besprechen, wie wir Ihre Produktion in Bild und Ton veredeln können.</p>
181                <a href="kontakt.html" class="btn-primary text-lg">Jetzt unverbindlich anfragen</a>
182            </div>
183        </section>
184    </main>
185
186    <!-- FOOTER_START -->
187<footer>
188    <div class="container mx-auto px-6">
189        <div class="grid md:grid-cols-3 gap-12 mb-12">
190            <div>
191                <img src="Bilder/MA/m_hellgrau_rgb_small_wabe.webp" alt="Media Atelier" class="h-10 mb-4 opacity-70">
192                <p class="text-sm leading-relaxed mb-6">Postproduktion für Film, Fernsehen und Audio in Mainz. Seit über 25 Jahren.</p>
193                <div class="flex items-center gap-3">
194                    <a href="https://www.instagram.com/media_atelier_gmbh/" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-full bg-white/15 border border-white/20 flex items-center justify-center text-white hover:bg-brand-yellow hover:text-brand-dark hover:border-brand-yellow transition-all duration-300 shadow-md" title="Instagram">
195                        <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 fill-current" viewBox="0 0 24 24">
195<path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
196                    </a>
197                    <a href="https://www.facebook.com/MediaAtelierGmbH/?locale=de_DE" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-full bg-white/15 border border-white/20 flex items-center justify-center text-white hover:bg-brand-yellow hover:text-brand-dark hover:border-brand-yellow transition-all duration-300 shadow-md" title="Facebook">
198                        <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 fill-current" viewBox="0 0 24 24"><path d="M9 8H6v4h3v12h5V12h3.642L18 8h-4V6.333C14 5.374 14.5 5 15.5 5H18V0h-3.808C10.592 0 9 1.583 9 4.615V8z"/></svg>
199                    </a>
200                    <a href="https://de.linkedin.com/company/media-atelier-gmbh" target="_blank" rel="noopener noreferrer" class="w-10 h-10 rounded-full bg-white/15 border border-white/20 flex items-center justify-center text-white hover:bg-brand-yellow hover:text-brand-dark hover:border-brand-yellow transition-all duration-300 shadow-md" title="LinkedIn">
201                        <svg xmlns="http://www.w3.org/2000/svg" class="w-4 h-4 fill-current" viewBox="0 0 24 24"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
202                    </a>
203                </div>
204            </div>
205            <div>
206                <h4 class="text-white font-bold mb-4 text-sm uppercase tracking-wider">Seiten</h4>
207                <nav class="flex flex-col gap-2 text-sm">
208                    <a href="leistungen.html">Leistungen</a>
209                    <a href="projekte.html">Projekte</a>
210                    <a href="hoerbuchproduktion.html">Hörbuchmanufaktur</a>
211                    <a href="ueber-uns.html">Über Uns</a>
212                </nav>
213            </div>
214            <div>
215                <h4 class="text-white font-bold mb-4 text-sm uppercase tracking-wider">Kontakt</h4>
216                <div class="text-sm space-y-2">
217                    <p>Media Atelier GmbH</p>
218                    <p>Poststraße 37, 55126 Mainz</p>
219                    <p>Telefon: 06131-6692480</p>
220                    <p><a href="mailto:[email protected]" class="hover:text-brand-yellow">[email protected]</a></p>
221                </div>
222            </div>
223        </div>
224        <div class="border-t border-white/10 pt-8 flex flex-col md:flex-row justify-between items-center gap-4 text-sm">
225            <p>&copy; 1999–2026 Media Atelier GmbH.</p>
226            <div class="flex gap-6">
227                <a href="impressum.html" class="hover:text-white">Impressum</a>
228                <a href="datenschutz.html" class="hover:text-white">Datenschutz</a>
229            </div>
230        </div>
231    </div>
232</footer>
233<!-- FOOTER_END -->
234
235    
235<script src="shared.js"></script>
235
236    
236<script>
237        document.addEventListener('DOMContentLoaded', function() {
238            // Dynamic fallback for database format initialization
239            mockData.projects.forEach(p => {
240                p.format = p.format || "Fernsehen";
241            });
242
243            const serviceNames = { 'scissors':'Schnitt','palette':'Grading','music':'Sounddesign','mic':'Sprache','speaker':'Mischung','video':'Regie','pen-tool':'Konzept','clapperboard':'Produktion','layers':'Animation','sparkles':'VFX','file-text':'Text' };
244
245            let currentFormat = "Fernsehen";
246            let currentSubFilter = "all";
247
248            function renderProjectFilters(activeFormat = "Fernsehen") {
249                const senderRow = document.getElementById('sender-filter-row');
250                const sendercontainer = document.getElementById('sender-filters');
251                const servicecontainer = document.getElementById('service-filters');
252                
253                // Reset dynamic container content
254                if (sendercontainer) {
255                    sendercontainer.innerHTML = '<button class="filter-btn active" data-filter="all">Alle</button>';
256                }
257                if (servicecontainer) {
258                    servicecontainer.innerHTML = '<button class="filter-btn active" data-filter="all">Alle</button>';
259                }
260
261                // Show/Hide broadcaster row based on format
262                if (activeFormat === "Fernsehen") {
263                    if (senderRow) senderRow.style.display = "block";
264                    const formatProjects = mockData.projects.filter(p => p.format === "Fernsehen");
265                    const senders = [...new Set(formatProjects.map(p => p.sender).filter(Boolean))];
266                    if (sendercontainer) {
267                        senders.forEach(sender => {
268                            const btn = document.createElement('button');
269                            btn.className = 'filter-btn';
270                            btn.dataset.filter = sender;
271                            btn.innerText = sender;
272                            sendercontainer.appendChild(btn);
273                        });
274                    }
275                } else {
276                    if (senderRow) senderRow.style.display = "none";
277                }
278
279                // Gather unique services icons for this format
280                const formatProjects = mockData.projects.filter(p => p.format === activeFormat);
281                const services = new Set();
282                formatProjects.forEach(p => p.icons && p.icons.forEach(i => services.add(i)));
283
284                if (servicecontainer) {
285                    let filteredServices = Array.from(services);
286                    // For Audiobooks, user specifically requested ONLY speech ("Sprache") and mix ("Mischung")
287                    if (activeFormat === "Hörbuch") {
288                        filteredServices = filteredServices.filter(icon => icon === "mic" || icon === "speaker");
289                    }
290                    
291                    filteredServices.forEach(icon => {
292                        const label = serviceNames[icon] || icon;
293                        const btn = document.createElement('button');
294                        btn.className = 'filter-btn';
295                        btn.dataset.filter = icon;
296                        btn.innerHTML = `<i data-lucide="${icon}" class="w-4 h-4 inline-block mr-1"></i>${label}`;
297                        servicecontainer.appendChild(btn);
298                    });
299                }
300                
301                attachFilterListeners();
302                if (servicecontainer) {
303                    lucide.createIcons();
304                }
305            }
306
307            function attachFilterListeners() {
308                const btns = document.querySelectorAll('#sender-filters .filter-btn, #service-filters .filter-btn');
309                btns.forEach(btn => {
310                    btn.addEventListener('click', () => {
311                        btns.forEach(b => b.classList.remove('active'));
312                        btn.classList.add('active');
313                        renderProjects(currentFormat, btn.dataset.filter);
314                    });
315                });
316            }
317
318            function attachFormatListeners() {
319                const formatBtns = document.querySelectorAll('.format-btn');
320                formatBtns.forEach(btn => {
321                    btn.addEventListener('click', () => {
322                        formatBtns.forEach(b => b.classList.remove('active'));
323                        btn.classList.add('active');
324                        const selectedFormat = btn.dataset.format;
325                        renderProjects(selectedFormat, "all");
326                        renderProjectFilters(selectedFormat);
327                    });
328                });
329            }
330
331            function renderProjects(formatFilter = "Fernsehen", subFilter = "all") {
332                currentFormat = formatFilter;
333                currentSubFilter = subFilter;
334
335                const grid = document.getElementById('project-grid');
336                if (!grid) return;
337
338                // Dynamically adjust grid columns for Audiobook format (4 columns) vs others (3 columns)
339                if (formatFilter === "Hörbuch") {
340                    grid.className = "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 gap-6";
341                } else {
342                    grid.className = "grid sm:grid-cols-2 lg:grid-cols-3 gap-8";
343                }
344
345                // 1. Filter by active format
346                let filtered = mockData.projects.filter(p => p.format === formatFilter);
347
348                // 2. Filter by dynamic broadcaster or service
349                const safeFilter = subFilter ? subFilter.toLowerCase() : 'all';
350                if (safeFilter !== 'all' && safeFilter !== 'alle') {
351                    const isSender = filtered.some(p => p.sender === subFilter);
352                    if (isSender) {
353                        filtered = filtered.filter(p => p.sender === subFilter);
354                    } else {
355                        filtered = filtered.filter(p => p.icons && p.icons.includes(subFilter));
356                    }
357                }
358
359                grid.innerHTML = filtered.map((p, index) => {
360                    // Only draw sender badge if it's set
361                    const senderBadge = p.sender ? `<div class="project-sender">${p.sender}</div>` : '';
362                    
363                    const imgContainerClass = formatFilter === "Hörbuch" ? "relative aspect-square overflow-hidden" : "relative h-56 overflow-hidden";
364                    const imgClass = formatFilter === "Hörbuch" ? "w-full h-full object-cover" : (p.img.includes('Bilder/Kunden') || p.img.includes('Cover') ? 'w-full h-full object-contain p-8 bg-brand-dark' : 'w-full h-full object-cover');
365                    
366                    return `
367                        <a href="${p.url}" target="_blank" class="project-card group reveal-on-scroll flex flex-col justify-between h-full" data-sender="${p.sender || ''}" style="transition-delay: ${(index % 3) * 75}ms;">
368                            <div class="${imgContainerClass} shrink-0 bg-[#2d2e30]">
369                                <img src="${p.img}" loading="lazy" class="${imgClass}"
370                                     onerror="if(this.src.includes('maxresdefault')){this.src=this.src.replace('maxresdefault','hqdefault');}else{this.src='https://placehold.co/600x400/4d4f53/fedf00?text=Postproduktion';}">
371                                ${senderBadge}
372                            </div>
373                            <div class="project-info flex-grow flex flex-col justify-between bg-[#2d2e30] p-5">
374                                <h3 class="font-bold text-base sm:text-lg text-white mb-3 leading-snug">${p.title}</h3>
375                                <div class="flex items-center gap-2 mt-auto pt-2">${(p.icons || []).map(i => `<i data-lucide="${i}" class="w-4 h-4 text-gray-400"></i>`).join('')}</div>
376                            </div>
377                        </a>
378                    `;
379                }).join('');
380                
381                if (grid) {
382                    lucide.createIcons();
383                }
384
385                // Scroll Reveal Observer for individual project cards
386                const projectObserver = new IntersectionObserver((entries) => {
387                    entries.forEach(entry => {
388                        if (entry.isIntersecting) {
389                            entry.target.classList.add('reveal-visible');
390                            projectObserver.unobserve(entry.target);
391                        }
392                    });
393                }, { root: null, rootMargin: '0px 0px -50px 0px', threshold: 0.1 });
394
395                grid.querySelectorAll('.reveal-on-scroll').forEach(card => {
396                    projectObserver.observe(card);
397                });
398            }
399
400            // Start up portfolio initialization
401            renderProjects("Fernsehen", "all");
402            renderProjectFilters("Fernsehen");
403            attachFormatListeners();
404
405            // --- SHOWREEL PLAYER ---
406            const srVideo = document.getElementById('showreel-video');
407            const srPlay = document.getElementById('sr-play');
408            const srIconPlay = document.getElementById('sr-icon-play');
409            const srIconPause = document.getElementById('sr-icon-pause');
410            const srOverlay = document.getElementById('sr-play-overlay');
411            const srProgress = document.getElementById('sr-progress');
412            const srThumb = document.getElementById('sr-thumb');
413            const srBar = document.getElementById('sr-progress-bar');
414            const srTime = document.getElementById('sr-time');
415            const srVolume = document.getElementById('sr-volume');
416            const srMute = document.getElementById('sr-mute');
417            const srIconVol = document.getElementById('sr-icon-vol');
418            const srIconMuted = document.getElementById('sr-icon-muted');
419            const srFS = document.getElementById('sr-fullscreen');
420            const srWrapper = document.getElementById('showreel-wrapper');
421
422            if (srVideo && srPlay) {
423                const fmt = s => `${Math.floor(s/60)}:${String(Math.floor(s%60)).padStart(2,'0')}`;
424                srPlay.addEventListener('click', () => {
425                    if (srVideo.paused) { srVideo.play(); srIconPlay.classList.add('hidden'); srIconPause.classList.remove('hidden'); if(srOverlay) srOverlay.style.display='none'; }
426                    else { srVideo.pause(); srIconPlay.classList.remove('hidden'); srIconPause.classList.add('hidden'); }
427                });
428                srVideo.addEventListener('timeupdate', () => { if(!srVideo.duration) return; const pct=(srVideo.currentTime/srVideo.duration)*100; srProgress.style.width=pct+'%'; srThumb.style.left=pct+'%'; srTime.textContent=`${fmt(srVideo.currentTime)} / ${fmt(srVideo.duration)}`; });
429                srVideo.addEventListener('loadedmetadata', () => { srTime.textContent=`0:00 / ${fmt(srVideo.duration)}`; });
430                srBar.addEventListener('click', e => { const rect=srBar.getBoundingClientRect(); srVideo.currentTime=((e.clientX-rect.left)/rect.width)*srVideo.duration; });
431                srVolume.addEventListener('input', () => { srVideo.volume=srVolume.value; srVideo.muted=srVolume.value==0; updateMuteIcon(); });
432                srMute.addEventListener('click', () => { srVideo.muted=!srVideo.muted; srVolume.value=srVideo.muted?0:srVideo.volume; updateMuteIcon(); });
433                function updateMuteIcon() { if(srVideo.muted||srVideo.volume===0){srIconVol.classList.add('hidden');srIconMuted.classList.remove('hidden');}else{srIconVol.classList.remove('hidden');srIconMuted.classList.add('hidden');} }
434                srFS.addEventListener('click', () => { if(!document.fullscreenElement){(srWrapper.requestFullscreen||srWrapper.webkitRequestFullscreen).call(srWrapper);}else{(document.exitFullscreen||document.webkitExitFullscreen).call(document);} });
435                srVideo.addEventListener('ended', () => { srIconPlay.classList.remove('hidden'); srIconPause.classList.add('hidden'); if(srOverlay){srOverlay.style.display='flex';} srProgress.style.width='0%'; srThumb.style.left='0%'; });
436            }
437        });
438    </script>
438
439</body>
440</html>

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