PageSourceSearch

https://filmhaus.org/reconstruction/v8.js

js filmhaus.org collected 2026-10-02 23:24:39 UTC 39,743 bytes, 551 lines download raw bytes

1(()=>{
2'use strict';
3const q=(s,r=document)=>r.querySelector(s), qa=(s,r=document)=>Array.from(r.querySelectorAll(s));
4const clamp=(n,a,b)=>Math.max(a,Math.min(b,n));
5const directChild=(el,sel)=>Array.from(el?.children||[]).find(x=>x.matches(sel));
6
7/* Canonical navigation tree preserved from the full homepage menu.  Some policy
8   pages only carried a partial/broken mobile tree in the legacy source, so every
9   route receives the same permanent archive navigation before dropdowns are built. */
10const CANONICAL_MOBILE_MENU_HTML="<ul class=\"wsite-menu-default\">\n<li class=\"wsite-menu-item-wrap\" id=\"active\">\n<a class=\"wsite-menu-item\" href=\"/\">\n\t\t\t\tHome\n\t\t\t</a>\n</li>\n<li class=\"wsite-menu-item-wrap has-submenu\" id=\"pg586723196324815242\">\n<a class=\"wsite-menu-item\" href=\"/about.html\">\n\t\t\t\tAbout\n\t\t\t</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-425179657384509877\">\n<a class=\"wsite-menu-subitem\" href=\"/about.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWhy Compete?\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-822424364151753704\">\n<a class=\"wsite-menu-subitem\" href=\"/about.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tAwards Categories\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-484477609457991267\">\n<a class=\"wsite-menu-subitem\" href=\"/about.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tOur Jury Team\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-621411280795896699\">\n<a class=\"wsite-menu-subitem\" href=\"/about.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tTerms &amp; Conditions\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-item-wrap\" id=\"pg543697130636997019\">\n<a class=\"wsite-menu-item\" href=\"https://www.moviemaker.com/the-filmhaus-evolution-a-new-jury-and-a-vision-renewed/\" target=\"_blank\">\n\t\t\t\tNews\n\t\t\t</a>\n</li>\n<li class=\"wsite-menu-item-wrap has-submenu\" id=\"pg959143843760578545\">\n<a class=\"wsite-menu-item\">\n\t\t\t\tResults\n\t\t\t</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-845697680202976948\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t2025\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-199266912944601379\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t29-Oct Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-857135867177168178\">\n<a class=\"wsite-menu-subitem\" href=\"/2025-winners-nominees.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-520285231357968100\">\n<a class=\"wsite-menu-subitem\" href=\"/2025-semifinals.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-504473690237696038\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t2024\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-780505697483928801\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-3-results.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t31-Oct Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-755660665988087845\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-3-results.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-782904378461531749\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-3-results.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-745669139187034368\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t12-Jun Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-822118939255319373\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-2-results-winners-nominees.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-788935615212808216\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-2-results-semi-finalists.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-815510221843053569\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t4-Mar Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-677739252535721791\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-1-results-winners-nominees.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-989290623410691742\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-1-results-semi-finalists.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-714928568887149543\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t2023\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-893789841841106669\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t27-October Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-474328147730937123\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-2-results-winners-nominees.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-268379218119407032\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-2-results-semifinalists.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-809046856259107649\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t24-April Finalists\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-503540590736517328\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-1-results-winners-nominees.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-175023518219251338\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-1-results-finalists.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tOther Finalists\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-997608781809016125\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-1-results-semifinalists.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tSemi-Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap has-submenu\" id=\"wsite-nav-309632566330144511\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\t2022\n\t\t</span><span class=\"wsite-menu-arrow\">&gt;</span>\n</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-814066915420491933\">\n<a class=\"wsite-menu-subitem\" href=\"/2022-results.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tWinners &amp; Nominees\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-240569501811368432\">\n<a class=\"wsite-menu-subitem\" href=\"/2022-finals.html\">\n<span class=\"wsite-menu-title\">\n\t\t\tOther Finalists\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-945101594301954953\">
10\n<a class=\"wsite-menu-subitem\" href=\"/2021.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2021\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-850261941533089396\">\n<a class=\"wsite-menu-subitem\" href=\"/2020.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2020\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-item-wrap has-submenu\" id=\"pg513485669766347496\">\n<a class=\"wsite-menu-item\">\n\t\t\t\tShowcase\n\t\t\t</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-753341163433951676\">\n<a class=\"wsite-menu-subitem\" href=\"/2025-showcase.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2025\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-492352240527833258\">\n<a class=\"wsite-menu-subitem\" href=\"/2024-showcase.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2024 (Closed)\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-318611594281750498\">\n<a class=\"wsite-menu-subitem\" href=\"/2023-showcase.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2023 (Closed)\n\t\t</span>\n</a>\n</li>\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-711775656286941571\">\n<a class=\"wsite-menu-subitem\" href=\"/2022-showcase.html\">\n<span class=\"wsite-menu-title\">\n\t\t\t2022 (Closed)\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n<li class=\"wsite-menu-item-wrap\" id=\"pg973119840694798189\">\n<a class=\"wsite-menu-item\" href=\"https://filmfreeway.com/filmhaus\" rel=\"noopener noreferrer\" target=\"_blank\">\n\t\t\t\tSubmit\n\t\t\t</a>\n</li>\n<li class=\"wsite-menu-item-wrap has-submenu\" id=\"pg376864275210229934\">\n<a class=\"wsite-menu-item\">\n\t\t\t\tContact\n\t\t\t</a><span class=\"icon-caret\"></span>\n<div class=\"wsite-menu-wrap\" style=\"display:none\">\n<ul class=\"wsite-menu\">\n<li class=\"wsite-menu-subitem-wrap\" id=\"wsite-nav-930762605800218402\">\n<a class=\"wsite-menu-subitem\">\n<span class=\"wsite-menu-title\">\n\t\t\[email protected]\n\t\t</span>\n</a>\n</li>\n</ul>\n</div>\n</li>\n</ul>\n";
11
12/* ---------- Header order, sticky transition, menus ---------- */
13const banner=q('.banner-wrap');
14const header=q('.dusk-header');
15function syncAffix(){
16  if(!banner||!header||innerWidth<=992){document.body.classList.remove('affix');return;}
17  document.body.classList.toggle('affix',scrollY>=banner.offsetHeight);
18}
19addEventListener('scroll',syncAffix,{passive:true});
20addEventListener('resize',syncAffix);
21
22function stripCloneIds(node){
23  if(node.id)node.removeAttribute('id');
24  qa('[id]',node).forEach(x=>x.removeAttribute('id'));
25  qa('[style]',node).forEach(x=>{
26    const s=x.getAttribute('style')||'';
27    x.setAttribute('style',s.replace(/(^|;)\s*(display|position|top|left|right|bottom)\s*:[^;]*/gi,'$1'));
28  });
29}
30function labelOf(a){return (a?.textContent||'').replace(/\s+/g,' ').trim().toLowerCase();}
31function setupMenus(){
32  const burger=q('.hamburger');
33  if(burger){
34    burger.addEventListener('click',e=>{e.preventDefault();document.body.classList.toggle('nav-open');});
35  }
36
37  const mobile=q('.mobile-nav');
38  if(mobile){
39    mobile.innerHTML=CANONICAL_MOBILE_MENU_HTML;
40    qa('a',mobile).forEach(a=>{
41      if(labelOf(a)==='[email protected]')a.href='mailto:[email protected]';
42    });
43    qa('li.has-submenu',mobile).forEach(li=>{
44      const caret=directChild(li,'.icon-caret');
45      const wrap=directChild(li,'.wsite-menu-wrap');
46      const a=directChild(li,'a');
47      if(!wrap)return;
48      const toggle=e=>{
49        e&&e.preventDefault();e&&e.stopPropagation();
50        const open=!wrap.classList.contains('open');
51        wrap.classList.toggle('open',open);
52        li.classList.toggle('fh-submenu-open',open);
53        caret&&caret.setAttribute('aria-expanded',String(open));
54      };
55      caret&&caret.addEventListener('click',toggle);
56      if(a&&!a.getAttribute('href'))a.addEventListener('click',toggle);
57    });
58    qa('a[href]',mobile).forEach(a=>a.addEventListener('click',()=>{
59      if(a.getAttribute('href')&&a.getAttribute('href')!=='#')document.body.classList.remove('nav-open');
60    }));
61  }
62
63  const desktop=q('.desktop-nav');
64  if(desktop&&mobile){
65    const targets={about:'about',results:'results',showcase:'showcase',contact:'contact'};
66    qa(':scope > ul >
66 li',desktop).forEach(li=>{
67      const top=directChild(li,'a.wsite-menu-item');
68      const key=labelOf(top);
69      if(key==='contact'&&top&&!top.getAttribute('href'))top.href='mailto:[email protected]';
70      if(!targets[key])return;
71      if(directChild(li,'.fh-desktop-menu'))return;
72      const source=qa(':scope > ul > li',mobile).find(mli=>labelOf(directChild(mli,'a.wsite-menu-item'))===key);
73      const wrap=source&&directChild(source,'.wsite-menu-wrap');
74      if(!wrap)return;
75      const clone=wrap.cloneNode(true);
76      stripCloneIds(clone);
77      clone.classList.add('fh-desktop-menu');
78      li.classList.add('fh-has-submenu');
79      li.appendChild(clone);
80      qa('a',clone).forEach(a=>{if(labelOf(a)==='[email protected]')a.href='mailto:[email protected]';});
81    });
82  }
83  const runtime=q('#wsite-menus');
84  if(runtime)runtime.id='_filmhaus_runtime_menu_source';
85}
86setupMenus();
87
88/* Desktop menus must work on click/tap as well as hover. */
89function setupDesktopMenuClicks(){
90  const desktop=q('.desktop-nav');if(!desktop)return;
91  const closeAll=(except=null)=>qa('.fh-menu-open',desktop).forEach(li=>{if(li!==except)li.classList.remove('fh-menu-open');});
92  qa('li.fh-has-submenu',desktop).forEach(li=>{
93    const top=directChild(li,'a.wsite-menu-item');if(!top)return;
94    const label=labelOf(top);
95    top.setAttribute('aria-haspopup','true');top.setAttribute('aria-expanded','false');
96    /* About and Contact are genuine destinations and must remain normal links.
97       Results / Showcase use click as an explicit menu toggle; hover/focus still
98       works through CSS and their hrefs remain useful as no-JS fallbacks. */
99    if(label!=='results'&&label!=='showcase')return;
100    top.addEventListener('click',e=>{
101      e.preventDefault();e.stopPropagation();
102      const open=!li.classList.contains('fh-menu-open');
103      closeAll(li);li.classList.toggle('fh-menu-open',open);top.setAttribute('aria-expanded',String(open));
104    });
105  });
106  qa('.fh-desktop-menu li.has-submenu',desktop).forEach(li=>{
107    const a=directChild(li,'a.wsite-menu-subitem');if(!a)return;
108    a.addEventListener('click',e=>{
109      const nested=directChild(li,'.wsite-menu-wrap');
110      if(!nested)return;
111      e.preventDefault();e.stopPropagation();
112      const open=!li.classList.contains('fh-menu-open');
113      Array.from(li.parentElement?.children||[]).forEach(s=>{if(s!==li)s.classList.remove('fh-menu-open')});
114      li.classList.toggle('fh-menu-open',open);
115    });
116  });
117  document.addEventListener('click',e=>{if(!desktop.contains(e.target))closeAll();});
118  document.addEventListener('keydown',e=>{if(e.key==='Escape')closeAll();});
119}
120setupDesktopMenuClicks();
121
122/* Submission links are intentionally external and direct to FilmFreeway. */
123const FILMFREEWAY='https://filmfreeway.com/filmhaus';
124qa('a').forEach(a=>{
125  const label=(a.textContent||'').replace(/\s+/g,' ').trim().toLowerCase();
126  if((a.classList.contains('wsite-menu-item')&&label==='submit') || label==='here' && /submit your project/i.test(a.parentElement?.textContent||'')){
127    a.href=FILMFREEWAY;a.target='_blank';a.rel='noopener noreferrer';
128  }
129});
130
131/* ---------- Captured video hero heights ---------- */
132const hero=q('.wsite-header-section');
133function syncHero(){
134  if(!hero)return;
135  const d=parseFloat(document.body.dataset.fhHeroDesktop||'');
136  const m=parseFloat(document.body.dataset.fhHeroMobile||'');
137  const h=innerWidth<=992?(m||d):(d||m);
138  if(h)hero.style.setProperty('height',h+'px','important');
139}
140addEventListener('resize',syncHero);
141syncHero();
142
143/* ---------- Viewport-width marketplace elements ---------- */
144function syncFullWidth(){
145  qa('.wad_full_width_element:not(.content_width)').forEach(el=>{
146    el.style.setProperty('width','100vw','important');
147    el.style.setProperty('left','calc(50% - 50vw)','important');
148  });
149}
150addEventListener('resize',syncFullWidth);
151syncFullWidth();
152
153/* ---------- Local video playback ---------- */
154qa('.wsite-section-bg-video video').forEach(v=>{
155  v.muted=true;v.loop=true;v.autoplay=true;v.playsInline=true;
156  const p=v.play();if(p&&p.catch)p.catch(()=>{});
157});
158
159/* ---------- Boo/FlexSlider local runtime ---------- */
160qa('.booFullwidthSlider').forEach(slider=>{
161  const ul=q('.flex-viewport > ul.slides',slider);const viewport=q('.flex-viewport',slider);if(!ul||!viewport)return;
162  qa(':scope > li.clone',ul).forEach(x=>x.remove());
163  const slides=qa(':scope > li',ul);if(!slides.length)return;
164  let index=slides.findIndex(x=>x.classList.contains('flex-active-slide'));if(index<0)index=0;
165  const dots=qa('.flex-control-nav a',slider),prev=q('.flex-prev',slider),next=q('.flex-next',slider);
166  function naturalHeight(slide){
167    const img=q('.booImage img',slide);
168    const imageH=img?(img.getBoundingClientRect().width*(img.naturalHeight||9)/(img.naturalWidth||16)):0;
169    const content=q('.booSlideContent',slide);
170    let contentH=0;
171    if(content){
172      const oldH=content.style.height;content.style.height='auto';
173      contentH=content.scrollHeight+(slider.classList.contains('setWidth-normal')?100:0);
174      content.style.height=oldH;
175    }
176    return Math.max(100,Math.ceil(imageH),Math.ceil(contentH));
177  }
178  function capturedHeight(){
179    const pairs=Object.keys(slider.dataset).filter(k=>/^fhHeight-?\d+$/.test(k)).map(k=>[parseInt(k.replace(/\D/g,''),10),parseFloat(slider.dataset[k])]).filter(p=>Number.isFinite(p[0])&&Number.isFinite(p[1])).sort((a,b)=>a[0]-b[0]);
180    if(!pairs.length)return null;
181    const w=innerWidth;
182    const exact=pairs.find(p=>Math.abs(p[0]-w)<1);if(exact)return exact[1];
183    if(w<=pairs[0][0])return pairs[0][1];
184    if(w>=pairs[pairs.length-1][0])return pairs[pairs.length-1][1];
185    for(let i=1;i<pairs.length;i++)if(w<pairs[i][0]){
186      const [w0,h0]=pairs[i-1],[w1,h1]=pairs[i],t=(w-w0)/(w1-w0);
187      return h0+(h1-h0)*t;
188    }
189    return null;
190  }
191  function size(){
192    const h=Math.max(100,Math.round(capturedHeight()||naturalHeight(slides[index])));
193    slider.style.setProperty('height',h+'px','important');
194    viewport.style.setProperty('height',h+'px','important');
195    ul.style.setProperty('height',h+'px','important');
196    slides.forEach(s=>{
197      s.style.setProperty('height',h+'px','important');
198      const image=q('.booImage',s),img=q('.booImage img',s);
199      image?.style.setProperty('height',h+'px','important');
200      if(img){
201        img.style.setProperty('width','100%','important');
202        img.style.setProperty('height','100%','important');
203        img.style.setProperty('max-width','none','important');
204        img.style.setProperty('object-fit','cover','important');
205        img.style.setProperty('object-position','center center','important');
206      }
207    });
208  }
209  function show(i){
210    index=(i+slides.length)%slides.length;
211    ul.style.transform=`translate3d(${-index*100}%,0,0)`;
212    slides.forEach((s,j)=>s.classList.toggle('flex-active-slide',j===index));
213    dots.forEach((d,j)=>d.classList.toggle('flex-active',j===index));
214    requestAnimationFrame(size);
215  }
216  prev&&prev.addEventListener('click',e=>{e.preventDefault();show(index-1)});
217  next&&next.addEventListener('click',e=>{e.preventDefault();show(index+1)});
218  dots.forEach((d,j)=>d.addEventListener('click',e=>{e.preventDefault();show(j)}));
219  qa('img',slider).forEach(img=>{if(!img.complete)img.addEventListener('load',size,{once:true});});
220  addEventListener('resize',()=>show(index));
221  show(index);
222});
223
224/* ---------- WAddons/Owl local runtime ---------- */
225qa('.waddons_carousel_slider').forEach(car=>{
226  const outer=q('.waddons-car-wrapper-outer',car),track=q('.waddons-car-wrapper',car);if(!outer||!track)return;
227  const items=qa(':scope > .waddons-car-element',track);if(!items.length)return;
228  const prev=q('.owl-prev',car),next=q('.owl-next',car),controls=q('.owl-controls',car);
229  let index=0,itemW=0,visible=1,timer=null;
230
231  /* The captured PlatformElementSettings are embedded as data attributes by the
232     reconstruction pass. These are the original Owl Carousel responsive counts. */
233  const num=(name,fallback=1)=>Math.max(1,parseInt(car.dataset[name]||fallback,10)||fallback);
234  const flag=(name)=>String(car.dataset[name]||'false')==='true';
235  const px=(name)=>{const v=parseFloat(car.dataset[name]||'');return Number.isFinite(v)&&v>0?v:null};
236  function evidenceGeometry(){
237    const w=innerWidth;
238    let item=null,canvas=null,controls=null,visibleCount=null;
239    if(w>=993){
240      /* User-directed refinement: keep the audited number of visible cards, but
241         let that set span the actual browser width instead of the legacy 1024px
242         Weebly canvas.  249≈4-up, 341/338≈3-up, 507≈2-up, 169≈6-up. */
243      const sourceItem=px('fhDesktopItem')||px('fh1280Item');
244      const inferred=sourceItem?Math.max(1,Math.round(1024/sourceItem)):num('fhItemsLarge',4);
245      visibleCount=Math.max(1,Math.min(items.length,inferred));
246      canvas=Math.max(1,document.documentElement.clientWidth||w);
247      item=canvas/visibleCount;
248      controls=w>
248=1280?(car.dataset.fh1280Controls||car.dataset.fhDesktopControls):(car.dataset.fhDesktopControls||car.dataset.fh1280Controls);
249    } else if(w>=768){
250      item=px('fhTabletItem')||px('fhDesktopItem')||px('fhMobileItem');canvas=Math.min(698,Math.max(1,outer.clientWidth));controls=car.dataset.fhTabletControls||car.dataset.fhMobileControls;
251    } else if(w<=375){
252      item=px('fh375Item')||px('fhMobileItem')||px('fhDesktopItem');canvas=Math.min(306,Math.max(1,outer.clientWidth));controls=car.dataset.fh375Controls||car.dataset.fhMobileControls;
253    } else {
254      item=px('fhMobileItem')||px('fh375Item')||px('fhDesktopItem');canvas=Math.min(320,Math.max(1,outer.clientWidth));controls=car.dataset.fhMobileControls||car.dataset.fh375Controls;
255    }
256    if(!item){
257      const count=w>1000?num('fhItemsLarge',4):w>768?num('fhItemsTablets',2):num('fhItemsPhone',1);
258      item=Math.max(1,Math.floor((outer.clientWidth||canvas||320)/count));
259    }
260    if(w>=993){
261      const visible=visibleCount||Math.max(1,Math.min(items.length,Math.round(canvas/item)||1));
262      return {item,visible,canvas,controls};
263    }
264    canvas=Math.min(canvas||outer.clientWidth,item*items.length,outer.parentElement?.clientWidth||Infinity);
265    const visible=Math.max(1,Math.min(items.length,Math.round(canvas/item)||1));
266    return {item,visible,canvas:item*visible,controls};
267  }
268
269  /* The lazy audit preserved a builder-runtime artefact where later cards sometimes
270     inherited the first card's CSS background. The source upload image nested inside
271     each card is the authoritative, card-specific binary. Re-appl
271y it to the visible
272     background window exactly as the live add-on does after initialization. */
273  items.forEach(item=>{
274    const bg=q('.wad_full_width_element.use_fw_bg_img',item);
275    const src=q('.upload_img_bg_wad_fw_element img',item);
276    if(bg&&src){
277      const url=src.getAttribute('src')||src.currentSrc;
278      if(url)bg.style.setProperty('background-image',`url("${url}")`,'important');
279    }
280  });
281
282  function maxIndex(){return Math.max(0,items.length-visible)}
283  let evidenceControls=null;
284  function syncControls(){
285    const canMove=items.length>visible;
286    const hideArrows=flag('fhHideArrows');
287    const hideDots=flag('fhHideDots');
288    const auditAllows=evidenceControls!=='none';
289    if(controls)controls.style.setProperty('display',canMove&&auditAllows&&(!hideArrows||!hideDots)?'block':'none','important');
290    const buttons=q('.owl-buttons',car);
291    if(buttons)buttons.style.setProperty('display',canMove&&auditAllows&&!hideArrows?'block':'none','important');
292    const pagination=q('.owl-pagination',car);
293    if(pagination)pagination.style.setProperty('display',canMove&&auditAllows&&!hideDots?'block':'none','important');
294    prev?.classList.toggle('disabled',index<=0);
295    next?.classList.toggle('disabled',index>=maxIndex());
296  }
297  function place(animate=true){
298    track.style.transition=animate?'transform .55s ease':'none';
299    track.style.transform=`translate3d(${-index*itemW}px,0,0)`;
300    syncControls();
301  }
302  function sync(){
303    const g=evidenceGeometry();
304    visible=g.visible;itemW=g.item;evidenceControls=g.controls;
305    outer.style.setProperty('max-width',Math.round(g.canvas)+'px','important');
306    outer.style.setProperty('width',innerWidth>=993?Math.round(g.canvas)+'px':'100%','important');
307    car.style.setProperty('--fh-item-width',itemW+'px');
308    index=clamp(index,0,maxIndex());
309    place(false);
310    requestAnimationFrame(()=>{track.style.transition='transform .55s ease';});
311    restart();
312  }
313  function go(delta){
314    if(items.length<=visible)return;
315    index=clamp(index+delta,0,maxIndex());
316    place(true);
317  }
318  prev&&prev.addEventListener('click',e=>{e.preventDefault();go(-1);restart()});
319  next&&next.addEventListener('click',e=>{e.preventDefault();go(1);restart()});
320
321  function restart(){
322    clearInterval(timer);timer=null;
323    if(!flag('fhAutoplay')||items.length<=visible)return;
324    const interval=Math.max(1000,(parseFloat(car.dataset.fhInterval||'3')||3)*1000);
325    timer=setInterval(()=>{
326      index=index>=maxIndex()?0:index+1;
327      place(true);
328    },interval);
329  }
330  if(flag('fhStopOnHover')){
331    car.addEventListener('mouseenter',()=>{clearInterval(timer);timer=null});
332    car.addEventListener('mouseleave',restart);
333  }
334  addEventListener('resize',sync);
335  if('ResizeObserver' in window)new ResizeObserver(sync).observe(outer);
336  sync();
337});
338
339/* ---------- Classic Weebly thumbnail slideshow local runtime ---------- */
340qa('.wslide').forEach(root=>{
341  const slides=qa('.wslide-slides > .wslide-slide',root),links=qa('.wslide-links .wslide-link',root),linksBox=q('.wslide-links',root),linksInner=q('.wslide-links-inner',root);
342  if(!slides.length)return;
343  let index=slides.findIndex(s=>s.style.display!=='none');if(index<0)index=0;
344  let timer=null;
345  function size(){
346    const content=q('.wslide-content',root);if(!content)return;
347    const h=Math.round(content.clientWidth*9/16);
348    content.style.setProperty('height',h+'px','important');
349    if(linksBox)linksBox.style.setProperty('height',h+'px','important');
350  }
351  function keepLinkVisible(){
352    if(!linksBox||!linksInner||!links[index])return;
353    const a=links[index];const top=a.offsetTop,bottom=top+a.offsetHeight;
354    const current=-parseFloat(linksInner.style.top||'0')||0;
355    let nextTop=current;
356    if(top<current)nextTop=top;else if(bottom>current+linksBox.clientHeight)nextTop=bottom-linksBox.clientHeight;
357    linksInner.style.top=-Math.max(0,nextTop)+'px';
358  }
359  function show(i){
360    index=(i+slides.length)%slides.length;
361    slides.forEach((s,j)=>s.style.display=j===index?'block':'none');
362    links.forEach((a,j)=>a.classList.toggle('wslide-link-active',j===index));
363    keepLinkVisible();
364  }
365  links.forEach((a,j)=>a.addEventListener('click',e=>{e.preventDefault();show(j);restart();}));
366  q('.wslide-prev',root)?.addEventListener('click',e=>{e.preventDefault();show(index-1);restart();});
367  q('.wslide-next',root)?.addEventListener('click',e=>{e.preventDefault();show(index+1);restart();});
368  function restart(){clearInterval(timer);timer=setInterval(()=>show(index+1),5000);}
369  root.addEventListener('mouseenter',()=>clearInterval(timer));root.addEventListener('mouseleave',restart);
370  addEventListener('resize',()=>{size();keepLinkVisible();});
371  size();show(index);restart();
372});
373
374
375/* ---------- Compact tabbed results runtime (2023 archive) ---------- */
376qa('.tabbed-box').forEach(box=>{
377  const tabs=qa('.tabbed-box-tab',box),contents=qa('.tabbed-box-content',box);if(!tabs.length||!contents.length)return;
378  function show(tab){
379    const rel=tab.getAttribute('rel')||'';
380    tabs.forEach(t=>t.classList.toggle('active',t===tab));
381    contents.forEach(c=>{const on=c.classList.contains(rel);c.style.display=on?'block':'none';c.setAttribute('aria-hidden',String(!on));});
382    tab.setAttribute('aria-selected','true');
383    tabs.forEach(t=>{if(t!==tab)t.setAttribute('aria-selected','false')});
384    const rail=tab.parentElement;if(rail){const left=tab.offsetLeft-Math.max(0,(rail.clientWidth-tab.offsetWidth)/2);rail.scrollTo?.({left:Math.max(0,left),behavior:'smooth'});}
385  }
386  tabs.forEach(tab=>{tab.setAttribute('role','tab');tab.addEventListener('click',e=>{e.preventDefault();show(tab)});});
387  const active=tabs.find(t=>t.classList.contains('active'))||tabs[0];show(active);
388});
389
390/* ---------- Consistent footer signature ---------- */
391function enhanceFooter(){
392  let wrap=q('.footer-wrap');
393  if(!wrap){wrap=document.createElement('div');wrap.className='footer-wrap';const mobile=q('.mobile-nav');(mobile||document.body.lastChild)?.parentNode?.insertBefore(wrap,mobile||null);}
394  wrap.classList.add('fh-footer-enhanced');
395  wrap.innerHTML=`<div class="container"><footer class="fh-signature-footer" aria-label="FilmHaus footer">
396    <div class="fh-signature-top">
397      <a class="fh-signature-logo" href="/" aria-label="FilmHaus home"><img src="/assets/source-filmhaus/uploads/1/2/9/9/129999471/published/2022-filmhaus-logo2__q-3f45dcf0.png" alt="FilmHaus"></a>
398      <div class="fh-signature-tagline">Home of Hidden Cinematic Treasures</div>
399      <nav class="fh-signature-links" aria-label="Legal"><a href="/cookies-policy.html">Cookies</a><a href="/legal-notice.html">Legal Notice</a><a href="/privacy-policy.html">Privacy</a><a href="/intellectual-property-policy.html">Content Rights</a></nav>
400    </div>
401    <div class="fh-signature-rule"></div>
402    <div class="fh-signature-bottom"><strong>FILMHAUS · DIGITAL BERLIN · EST. 2020</strong><span>© 2020–2026 FilmHaus · FILMFINITY SL · All Rights Reserved</span></div>
403  </footer></div>`;
404}
405enhanceFooter();
406
407if(['/cookies-policy.html','/legal-notice.html','/privacy-policy.html','/intellectual-property-policy.html'].includes(document.body.dataset.fhRoute||'')){
408  document.body.classList.add('fh-legal-route');
409  qa('[class*=\"elfsight-app-\"],.eui-tooltip,#newsvd_popupMenu,#newsvdPrice,#newvtPopupMenu').forEach(el=>el.remove());
410  qa('.fh-legal-route .main-wrap a[href]').forEach(a=>{
411    const href=a.getAttribute('href')||'';
412    if(/^https?:/i.test(href)){a.target='_blank';a.rel='noopener noreferrer';}
413  });
414}
415
416/* v5 final navigation safety: native destinations remain independently usable. */
417const fhDesktop=q('.desktop-nav');
418if(fhDesktop){
419  const destinations={home:'/',about:'/about.html',news:'https://www.moviemaker.com/the-filmhaus-evolution-a-new-jury-and-a-vision-renewed/',results:'/2025-winners-nominees.html',showcase:'/2025-showcase.html',submit:'https://filmfreeway.com/filmhaus',contact:'mailto:[email protected]'};
420  qa(':scope > ul > li',fhDesktop).forEach(li=>{
421    const a=directChild(li,'a.wsite-menu-item');if(!a)return;
422    const label=labelOf(a);if(destinations[label])a.href=destinations[label];
423    a.style.pointerEvents='auto';
424  });
425}
426
427syncAffix();
428})();
429
430/* ========================================================================== */
431/* FilmHaus v6 — final archive/navigation refinement                          */
432/* ========================================================================== */
433(()=>{
434'use strict';
435const q=(s,r=document)=>r.querySelector(s), qa=(s,r=document)=>Array.from(r.querySelectorAll(s));
436const direct=(el,sel)=>Array.from(el?.children||[]).find(x=>x.matches(sel));
437const label=a=>(a?.textContent||'').replace(/\s+/g,' ').trim().toLowerCase();
438
439/* Rebuild only the two archive dropdowns. This deliberately supersedes the
440   deeply-nested legacy Weebly menu with the broad Results panel visible in the
441   supplied reference screenshots. */
442const desktop=q('.desktop-nav');
443if(desktop){
444  const topItems=qa(':scope > ul > li',desktop);
445  const resultsLi=topItems.find(li=>label(direct(li,'a.wsite-menu-item'))==='results');
446  const showcaseLi=topItems.find(li=>label(direct(li,'a.wsite-menu-item'))==='showcase');
447
448  if(resultsLi){
449    direct(resultsLi,'.fh-desktop-menu')?.remove();
450    const mega=document.createElement('div');
451    mega.className='fh-desktop-menu fh-results-mega';
452    mega.setAttribute('role','menu');
453    mega.innerHTML=`<div class="fh-results-grid">
454      <section class="fh-results-group"><h3>2025</h3><a href="/2025-winners-nominees.html">29-Oct · Winners &amp; Nominees</a><a href="/2025-semifinals.html">29-Oct · Semi-Finalists</a></section>
455      <section class="fh-results-group"><h3>2024</h3><a href="/2024-3-results.html">31-Oct Finalists</a><a href="/2024-2-results-winners-nominees.html">12-Jun · Winners &amp; Nominees</a><a href="/2024-2-results-semi-finalists.html">12-Jun · Semi-Finalists</a><a href="/2024-1-results-winners-nominees.html">4-Mar · Winners &amp; Nominees</a><a href="/2024-1-results-semi-finalists.html">4-Mar · Semi-Finalists</a></section>
456      <section class="fh-results-group"><h3>2023</h3><a href="/2023-2-results-winners-nominees.html">27-Oct · Winners &amp; Nominees</a><a href="/2023-2-results-semifinalists.html">27-Oct · Semi-Finalists</a><a href="/2023-1-results-winners-nominees.html">24-Apr · Winners &amp; Nominees</a><a href="/2023-1-results-finalists.html">24-Apr · Other Finalists</a><a href="/2023-1-results-semifinalists.html">24-Apr · Semi-Finalists</a></section>
457      <section class="fh-results-group"><h3>2022</h3><a href="/2022-results.html">Winners &amp; Nominees</a><a href="/2022-finals.html">Other Finalists</a></section>
458      <section class="fh-results-group"><h3>2021</h3><a href="/2021.html">Results Archive</a></section>
459      <section class="fh-results-group"><h3>2020</h3><a href="/2020.html">Results Archive</a></section>
460    </div>`;
461    resultsLi.appendChild(mega);
462  }
463
464  if(showcaseLi){
465    direct(showcaseLi,'.fh-desktop-menu')?.remove();
466    const menu=document.createElement('div');
467    menu.className='fh-desktop-menu fh-showcase-menu';
468    menu.setAttribute('role','menu');
469    menu.innerHTML=`<a href="/2025-showcase.html">2025 (Closed)</a><a href="/2024-showcase.html">2024 (Closed)</a><a href="/2023-showcase.html">2023 (Closed)</a><a href="/2022-showcase.html">2022 (Closed)</a>`;
470    showcaseLi.appendChild(menu);
471  }
472
473  const syncMenuTop=()=>{
474    const header=q('.dusk-header');
475    if(!header)return;
476    const bottom=Math.max(0,Math.round(header.getBoundingClientRect().bottom));
477    document.documentElement.style.setProperty('--fh-nav-bottom',bottom+'px');
478  };
479  syncMenuTop();
480  addEventListener('scroll',syncMenuTop,{passive:true});
481  addEventListener('resize',syncMenuTop);
482}
483
484/* Keep the Results year neutral; the closed state belongs to Showcase. */
485const mobile=q('.mobile-nav');
486if(mobile){
487  qa(':scope > ul > li',mobile).forEach(li=>{
488    const top=direct(li,'a.wsite-menu-item');
489    const topLabel=label(top);
490    const wrap=direct(li,'.wsite-menu-wrap');
491    if(!wrap)return;
492    if(topLabel==='results'){
493      const y=qa(':scope > ul > li',wrap).find(yearLi=>label(direct(yearLi,'a.wsite-menu-subitem')).startsWith('2025'));
494      const title=y&&q('.wsite-menu-title',y); if(title)title.textContent='2025';
495    }
496    if(topLabel==='showcase'){
497      const y=qa(':scope > ul > li',wrap).find(yearLi=>label(direct(yearLi,'a.wsite-menu-subitem')).startsWith('2025'));
498      const title=y&&q('.wsite-menu-title',y); if(title)title.textContent='2025 (Closed)';
499    }
500  });
501}
502
503/* The six empty 31-Oct-2024 builder carousels contain literal template tokens
504   rather than content. Remove only those broken widgets; the page layout itself
505   is intentionally left untouched. */
506if((document.body.dataset.fhRoute||'')==='/2024-3-results.html'){
507  qa('.inner_content_car').forEach(inner=>{
508    if(!/\{slide_0:content\}/i.test(inner.textContent||''))return;
509    const platform=inner.closest('.platform-element-contents');
510    if(platform)platform.remove();
511    else inner.closest('.waddons_carousel_slider')?.remove();
512  });
513}
514
515/* Consistent archive presentation begins with the 12-Jun-2024 results and runs
516   backward. 2025, 31-Oct-2024 and every Showcase route are excluded by design. */
517const legacyResults=new Set([
518  '/2024-2-results-winners-nominees.html','/2024-2-results-semi-finalists.html',
519  '/2024-1-results-winners-nominees.html','/2024-1-results-semi-finalists.html',
520  '/2023-2-results-winners-nominees.html','/2023-2-results-semifinalists.html',
521  '/2023-1-results-winners-nominees.html','/2023-1-results-finalists.html','/2023-1-results-semifinalists.html',
522  '/2022-results.html','/2022-finals.html','/2021.html','/2020.html'
523]);
524if(legacyResults.has(document.body.dataset.fhRoute||''))document.body.classList.add('fh-unified-results');
525})();
526
527
528/* FilmHaus v8 — normalize the selected archive pages to the 2022 result shell. */
529(()=>{
530  const routes=new Set([
531    '/2024-2-results-winners-nominees.html','/2024-2-results-semi-finalists.html',
532    '/2024-1-results-winners-nominees.html','/2024-1-results-semi-finalists.html',
533    '/2023-2-results-winners-nominees.html','/2023-2-results-semifinalists.html',
534    '/2023-1-results-winners-nominees.html','/2023-1-results-finalists.html','/2023-1-results-semifinalists.html',
535    '/2022-finals.html'
536  ]);
537  if(!routes.has(document.body.dataset.fhRoute||''))return;
538  document.body.classList.add('fh-2022-layout');
539
540  // Keep the top result slideshow proportional when the viewport changes.
541  const resizeSlides=()=>{
542    document.querySelectorAll('#wsite-content .wslide').forEach(root=>{
543      const content=root.querySelector('.wslide-content');
544      if(!content)return;
545      const h=Math.round(content.clientWidth*9/16);
546      content.style.setProperty('height',h+'px','important');
547    });
548  };
549  resizeSlides();
550  addEventListener('resize',resizeSlides,{passive:true});
551})();

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.