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>© 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.