1import{r as D,j as o}from"./react-Cs8zWWH2.js";import{u as Re}from"./usePageMeta-BvB62zv-.js";import{C as ze}from"./ConsoleShell-CVP__-c-.js";import{P as Ye,S as $e,C as Ge,E as me,B as H,i as Fe,d as P,b as G,c as ge,g as Je,L as qe}from"./ui-7Dq56kbI.js";import{a_ as Ve,a$ as Ke,b0 as Qe}from"./console-C0DROSzo.js";import"./auth-DM2PqoGT.js";import"./supabase-e9Wsjn9L.js";import"./supabase-CSIM0fnT.js";import"./auth-hint-D8tyCaun.js";import"./motion-ok-BZHsZT9U.js";import"./description-LBYd-IuB.js";import"./index-BGOdKNd7.js";import"./useInstallPrompt-7DVThT4Y.js";import"./errors-CFnE8RFP.js";const O=e=>String(e).padStart(2,"0");function w(e){if(e==null)return"";const a=(e%1440+1440)%1440;return O(Math.floor(a/60))+":"+O(a%60)}function I(e){if(e==null)return null;const a=String(e).trim();if(!a||a==="--:--"||a==="-"||a==="--")return null;const t=/^(\d{1,2})[:.](\d{2})$/.exec(a);if(!t)return null;const s=+t[1],n=+t[2];return s>23||n>59?null:s*60+n}const Xe=(e,a)=>e==null?null:Math.ceil(e/a)*a,Ze=(e,a)=>e==null?null:Math.floor(e/a)*a;function R(e,a,t){return new Date(Date.UTC(e,a-1,t))}function ae(e){const a=String(e||"").trim();let t;return(t=/^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(a))?R(+t[1],+t[2],+t[3]):(t=/^(\d{1,2})[-./](\d{1,2})[-./](\d{4})$/.exec(a))?R(+t[3],+t[2],+t[1]):(t=/^(\d{1,2})[-./](\d{1,2})[-./](\d{2})$/.exec(a))?R(2e3+ +t[3],+t[2],+t[1]):null}const _=e=>e.toISOString().slice(0,10),z=(e,a)=>new Date(e.getTime()+a*864e5),je=(e,a)=>{const t=new Date(Date.UTC(e,a,0));return z(t,-t.getUTCDay())};function et(e){const a=e.getUTCFullYear();return e>=je(a,3)&&e<je(a,10)}function tt(e){const a=new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth(),e.getUTCDate())),t=(a.getUTCDay()+6)%7;a.setUTCDate(a.getUTCDate()-t+3);const s=a.getUTCFullYear(),n=Date.UTC(s,0,4),l=1+Math.round(((a.getTime()-n)/864e5-3+(new Date(n).getUTCDay()+6)%7)/7);return{year:s,week:l}}const ye=["jan.","feb.","mars","apr.","mai","juni","juli","aug.","sep.","okt.","nov.","des."],q=["januar","februar","mars","april","mai","juni","juli","august","september","oktober","november","desember"],se=["January","February","March","April","May","June","July","August","September","October","November","December"],Ue=["søn","man","tir","ons","tor","fre","lør"],be=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],Le=["søndag","mandag","tirsdag","onsdag","torsdag","fredag","lørdag"],at=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],ve=e=>e.getUTCDate()+". "+ye[e.getUTCMonth()],Y=e=>O(e.getUTCDate())+"-"+O(e.getUTCMonth()+1),L=e=>Y(e)+"-"+e.getUTCFullYear(),Me=e=>O(e.getUTCDate())+"."+O(e.getUTCMonth()+1)+"."+e.getUTCFullYear();function nt(e){const a=[",",";"," ","|"];let t=",",s=-1;for(const n of a){const l=e.split(n).length;l>s&&(s=l,t=n)}return s>1?t:","}function le(e,a){const t=[];let s="",n=!1;for(let l=0;l<e.length;l++){const i=e[l];n?i==='"'?e[l+1]==='"'?(s+='"',l++):n=!1:s+=i:i==='"'?n=!0:i===a?(t.push(s),s=""):s+=i}return t.push(s),t.map(l=>l.trim())}const Oe={date:["date","dato","datum","day","dag"],fajr:["fajr","fadjr","fajr_begins","fajr_start","morgen"],sunrise:["sunrise","fajr_endtime","fajr_end","shuruq","shuruk","soloppgang","solopp","solopgang"],dhuhr:["dhuhr","duhr","zuhr","zohr","dhuhur","duhur","zuhur","migdag"],asrShafi:["asr_shafi","asr_shafii","asr_shafi_i","asr_1x_shadow","asr_1x","asr1","asr"],asrHanafi:["asr_hanafi","asr_2x_shadow","asr_2x","asr2","asr"],maghrib:["maghrib","mahgrib","magrib","maghreb","solnedgang"],isha:["isha","ishaa","isya","esha","esha","nattbonn"]},Be=e=>e.replace(/^\uFEFF/,"").trim().toLowerCase().replace(/ø/g,"o").replace(/[æå]/g,"a").replace(/[^a-z0-9]+/g,"_").replace(/^_|_$/g,"");function We(e){const a=[],s=e.replace(/^\uFEFF/,"").replace(/\r\n?/g,` 2`).split(` 3`).filter(g=>g.trim()!=="");if(s.length<2)throw new Error("Filen har ingen datarader. / The file contains no data rows.");const n=nt(s[0]),l=le(s[0],n).map(Be),i={},m={};for(const[g,u]of Object.entries(Oe))for(const b of u){const x=l.indexOf(b);if(x>=0){i[g]=x,m[g]=le(s[0],n)[x].replace(/^\uFEFF/,"").trim();break}}const d=["date","dhuhr","maghrib"].filter(g=>i[g]===void 0);if(d.length)throw new Error("Fant ikke kolonnen(e): "+d.join(", ")+". Kolonner i f
3ilen: "+l.join(", ")+" / Missing column(s): "+d.join(", "));i.asrShafi!==void 0&&i.asrShafi===i.asrHanafi&&a.push({level:"warn",scope:"file",no:"Filen har bare én Asr-kolonne («"+m.asrShafi+"»). BÃ¥de Shafi og Hanafi leses fra den.",en:'The file has only one Asr column ("'+m.asrShafi+'"). Both Shafi and Hanafi are read from it.'});const p=[],y=new Map,c=(g,u)=>i[u]===void 0?"":g[i[u]]??"";for(let g=1;g<s.length;g++){const u=le(s[g],n),b=ae(c(u,"date"));if(!b){a.push({level:"error",scope:"file",no:"Linje "+(g+1)+": ugyldig dato «"+c(u,"date")+"» â raden ble hoppet over.",en:"Line "+(g+1)+': invalid date "'+c(u,"date")+'" â row skipped.'});continue}const x={date:b,fajr:I(c(u,"fajr")),sunrise:I(c(u,"sunrise")),dhuhr:I(c(u,"dhuhr")),asrShafi:I(c(u,"asrShafi")),asrHanafi:I(c(u,"asrHanafi")),maghrib:I(c(u,"maghrib")),isha:I(c(u,"isha")),line:g+1};x.asrShafi==null&&(x.asrShafi=x.asrHanafi),x.asrHanafi==null&&(x.asrHanafi=x.asrShafi),x.maghrib!=null&&x.dhuhr!=null&&x.maghrib<x.dhuhr&&(x.maghrib+=1440),x.isha!=null&&x.maghrib!=null&&x.isha<x.maghrib&&(x.isha+=1440),y.has(_(b))&&a.push({level:"warn",scope:"file",no:"Linje "+(g+1)+": datoen "+L(b)+" finnes flere ganger â den siste brukes.",en:"Line "+(g+1)+": date "+L(b)+" appears more than once â the last one is used."}),y.set(_(b),x)}for(const g of y.values())p.push(g);if(p.sort((g,u)=>g.date-u.date),!p.length)throw new Error("Ingen gyldige datorader. / No valid date rows.");let f=0;for(let g=1;g<p.length;g++){const u=(p[g].date-p[g-1].date)/864e5;u>1&&(f+=u-1)}return f>0&&a.push({level:"warn",scope:"file",no:f+" dato(er) mangler i filen. Uker med hull fÃ¥r tider basert pÃ¥ færre dager enn normalt.",en:f+" date(s) are missing from the file. Weeks with holes are planned from fewer days than normal."}),{rows:p,issues:a,delim:n,usedHeader:m,headers:l}}const st=101010256,rt=33639248;function ot(e){const a=new Uint8Array(e),t=new DataView(e);let s=-1;for(let d=a.length-22;d>=Math.max(0,a.length-66e3);d--)if(t.getUint32(d,!0)===st){s=d;break}if(s<0)throw new Error("Filen ser ikke ut som en gyldig Excel-fil. / Not a readable Excel file.");const n=t.getUint16(s+10,!0);let l=t.getUint32(s+16,!0);const i=new Map,m=new TextDecoder("utf-8");for(let d=0;d<n&&t.getUint32(l,!0)===rt;d++){const p=t.getUint16(l+10,!0),y=t.getUint32(l+20,!0),c=t.getUint16(l+28,!0),f=t.getUint16(l+30,!0),g=t.getUint16(l+32,!0),u=t.getUint32(l+42,!0);i.set(m.decode(a.subarray(l+46,l+46+c)),{method:p,csize:y,lho:u}),l+=46+c+f+g}return{u8:a,dv:t,files:i}}async function Z(e,a){const t=e.files.get(a.replace(/^\//,""));if(!t)return null;const s=e.dv.getUint16(t.lho+26,!0),n=e.dv.getUint16(t.lho+28,!0),l=t.lho+30+s+n,i=e.u8.subarray(l,l+t.csize);if(t.method===0)return new TextDecoder("utf-8").decode(i);if(typeof DecompressionStream>"u")throw new Error("Nettleseren din kan ikke pakke ut Excel-filer. Lagre arket som CSV og prøv igjen. / This browser cannot unzip Excel files â save the sheet as CSV instead.");const m=new Blob([i]).stream().pipeThrough(new DecompressionStream("deflate-raw"));return new TextDecoder("utf-8").decode(await new Response(m).arrayBuffer())}const $=(e,a)=>{const t=new RegExp("(?:^|\\s)"+a+'="([^"]*)"').exec(e);return t?t[1]:null};function ne(e){return e.replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/&#x([0-9a-f]+);/gi,(a,t)=>String.fromCharCode(parseInt(t,16))).replace(/&#(\d+);/g,(a,t)=>String.fromCharCode(+t)).replace(/&/g,"&")}function it(e){if(!e)return[];const a=[],t=/<si\b[^>]*>([\s\S]*?)<\/si>/g;let s;for(;s=t.exec(e);){let n="";const l=/<t\b[^>]*>([\s\S]*?)<\/t>/g;let i;for(;i=l.exec(s[1]);)n+=ne(i[1]);a.push(n)}return a}function lt(e){let a="";for(e++;e>0;){const t=(e-1)%26;a=String.fromCharCode(65+t)+a,e=(e-1-t)/26}return a}function ht(e){let a=0;for(const t of e)a=a*26+(t.charCodeAt(0)-64);return a-1}function dt(e,a){const t=[],s=/<row\b[^>]*>([\s\S]*?)<\/row>/g;let n;for(;n=s.exec(e);){const l={},i=/<c\b([^>]*?)(?:\/>|>([\s\S]*?)<\/c>)/g;let m,d=0;for(;m=i.exec(n[1]);){const p=m[1],y=m[2]||"",c=(/^[A-Z]+/.exec($(p,"r")||"")||[""])[0],f=c||lt(d);d=(c?ht(c):d)+1;const g=$(p,"t");let u="";if(g==="inlineStr"){let b="";const x=/<t\b[^>]*>([\s\S]*?)<\/t>/g;let j;for(;j=x.exec(y);)b+=ne(j[1]);u=b}else{const b=/<v\b[^>]*>([\s\S]*?)<\/v>/.exec(y);u=b?ne(b[1]):"",g==="s"&&(u=a[+u]!==void 0?a[+u]:"")}l[f]=String(u).trim()}t.push(l)}return t}async function ct(e){const a=ot(e),t=it(await Z(a,"xl/sharedStrings.xml")),s=await Z(a,"xl/_rels/workbook.xml.rels")||"",n=new Map;let l;const i=/<Relationship\b([^>]*)\/?>/g;for(;l=i.exec(s);){const u=$(l[1],"Id"),b=$(l[1],"Target");u&&b&&n.set(u,b.replace(/^\//,"").replace(/^(?!xl\/)/,"xl/"))}const m=await Z(a,"xl/workbook.xml")||"",d=[],p=/<sheet\b([^>]*)\/?>/g;for(;l=p.exec(m);){const u=ne($(l[1],"name")||""),b=$(l[1],"r:id")||$(l[1],"id"),x=n.get(b);x&&d.push({name:u,path:x})}if(!d.length)throw new Error("Fant ingen ark i Excel-filen. / No sheets found in the Excel file.");const y=q.map((u,b)=>
3({i:b+1,re:new RegExp("^"+u.slice(0,3),"i")})),c=[],f=[];let g=null;for(const u of d){const b=await Z(a,u.path);if(!b)continue;const x=dt(b,t),j=u.name+" "+x.slice(0,3).map(r=>Object.values(r).join(" ")).join(" "),A=/\b(19|20)\d{2}\b/.exec(j);A&&(g=+A[0]);const M=A?+A[0]:g;let k=null;const C=/^\s*(\d{1,2})\b/.exec(u.name);if(C&&+C[1]>=1&&+C[1]<=12&&(k=+C[1]),k==null){for(const r of y)if(r.re.test(u.name.replace(/^\s*\d+\s*/,""))){k=r.i;break}}if(k==null){for(const r of y)if(r.re.test((j.match(/-\s*([A-Za-zÃÃà æøå]+)/)||[])[1]||"")){k=r.i;break}}if(k==null||!M){f.push(u.name);continue}let S=-1,E={};for(let r=0;r<Math.min(x.length,8);r++){const h={};for(const[v,T]of Object.entries(x[r])){const N=Be(T);for(const[U,F]of Object.entries(Oe))h[U]===void 0&&F.includes(N)&&(h[U]=v)}if(h.dhuhr!==void 0&&h.maghrib!==void 0){S=r,E=h;break}}if(S<0){f.push(u.name);continue}for(let r=S+1;r<x.length;r++){const h=x[r],v=E.date!==void 0?E.date:"A",T=/^\s*(\d{1,2})\s*$/.exec(h[v]||"");if(!T)continue;const N=+T[1];if(N<1||N>31)continue;const U={date:O(N)+"-"+O(k)+"-"+M};for(const F of["fajr","sunrise","dhuhr","asrShafi","asrHanafi","maghrib","isha"])U[F]=E[F]!==void 0&&h[E[F]]||"";c.push(U)}}if(!c.length)throw new Error("Fant ingen bønnetider i Excel-filen. / No prayer times found in the Excel file.");return{records:c,skipped:f,sheets:d.length}}async function ft(e){const{records:a,skipped:t,sheets:s}=await ct(e),l=[["date","fajr","sunrise","dhuhr","asr_shafi","asr_hanafi","maghrib","isha"].join(",")];for(const i of a)l.push([i.date,i.fajr,i.sunrise,i.dhuhr,i.asrShafi,i.asrHanafi,i.maghrib,i.isha].join(","));return{csv:l.join(` 4`),skipped:t,sheets:s,count:a.length}}async function mt(e){const a=/\.xlsx$/i.test(e.name);let t,s=[];if(a){const l=await ft(await e.arrayBuffer());t=l.csv,s=l.skipped}else t=await e.text();const n=We(t);return a&&s.length&&n.issues.push({level:"warn",scope:"file",no:"Hoppet over ark: "+s.join(", "),en:"Skipped sheets that could not be read as a month: "+s.join(", ")}),{name:e.name,text:t,...n,year:n.rows[0].date.getUTCFullYear(),saved:!1}}const ut=e=>String(e).split(" / ").pop();function pt({years:e,source:a,saving:t,dirty:s,onFile:n,onPick:l,onSave:i}){var b,x;const m=D.useRef(null),[d,p]=D.useState(!1),[y,c]=D.useState(null),f=async j=>{if(j){c(null);try{n(await mt(j))}catch(A){c(ut(A.message))}}},g=(b=a==null?void 0:a.rows[0])==null?void 0:b.date,u=(x=a==null?void 0:a.rows[a.rows.length-1])==null?void 0:x.date;return o.jsxs(Ye,{className:"p-4",children:[o.jsx($e,{children:"The year"}),e.length>0&&o.jsx("div",{className:"flex flex-wrap gap-2 mb-3",children:e.map(j=>o.jsx("button",{type:"button",onClick:()=>l(j.year),className:"rounded-full","aria-pressed":(a==null?void 0:a.saved)&&a.year===j.year,children:o.jsxs(Ge,{tone:a!=null&&a.saved&&a.year===j.year?"accent":"neutral",dot:!1,children:[j.year," · ",j.source_name]})},j.year))}),o.jsxs("div",{role:"button",tabIndex:0,onClick:()=>{var j;return(j=m.current)==null?void 0:j.click()},onKeyDown:j=>{var A;(j.key==="Enter"||j.key===" ")&&(j.preventDefault(),(A=m.current)==null||A.click())},onDragEnter:j=>{j.preventDefault(),p(!0)},onDragOver:j=>{j.preventDefault(),p(!0)},onDragLeave:j=>{j.preventDefault(),p(!1)},onDrop:j=>{j.preventDefault(),p(!1),f(j.dataTransfer.files[0])},className:"rounded-[6px] px-4 py-6 text-center cursor-pointer",style:{border:`2px dashed ${d?"var(--c-accent)":"var(--c-line)"}`,background:d?"var(--c-accent-soft)":"var(--c-sunk)"},children:[o.jsx("p",{className:"font-display font-semibold",style:{fontSize:".98rem"},children:"Drop the yearâs file here, or click to choose it"}),o.jsx("p",{className:"font-serif mt-1",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:"The CSV from Islamsk RÃ¥d Norge, one row per day, or the mawaqeet.no workbook (.xlsx). Nothing leaves your browser until you save."}),o.jsx("input",{ref:m,type:"file",accept:".xlsx,.csv,.txt,text/csv",hidden:!0,onChange:j=>{f(j.target.files[0]),j.target.value=""}})]}),y&&o.jsx("div",{className:"mt-3",children:o.jsx(me,{children:y})}),a&&o.jsxs("div",{className:"flex flex-wrap items-center gap-3 mt-3",children:[o.jsxs("p",{className:"font-serif flex-1 min-w-0",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:[o.jsx("b",{style:{color:"var(--c-text)"},children:a.name})," ","· ",a.rows.length," days, ",L(g)," to ",L(u),a.saved&&!s?" · saved for the board":""]}),o.jsx(H,{tone:"primary",onClick:i,disabled:t||a.saved&&!s,children:t?"Savingâ¦":a.saved?"Save changes":e.some(j=>j.year===a.year)?`Replace the saved ${a.year} file`:"Save for the board"})]})]})}const gt=[{value:"preferred",label:"Follow the preferred order: earliest suitable break, shorter waiting"},{value:"fewest",label:"Fewest possible changes: keep one time as long as possible"}],yt=[{id:"general",title:"General",hint:"The defaults are the rules used so far. Change them here; the settings are saved with the year.",fields:[{key:"rangeFrom",label:"From date (optional)",type:"text",placeholder:"12-08-2026"},{key:"rangeTo",label:"To date (optional)",type:"text",placeholder:"31-08-2026",hint:"Leave both empty to use the whole file. Fill in one or both to plan part of it, say from 12-08 to the end of August. This trims the jamaah times, the room bookings, the iBønn file and the poster."}
4,{key:"closedMonths",label:"Months with no prayers",type:"months"},{key:"closedWeekdays",label:"Weekdays with no prayers",type:"weekdays"},{key:"earliestAllowed",label:"Earliest allowed time",type:"text"},{key:"latestAllowed",label:"Latest allowed time",type:"text"},{key:"latestDayPrayer",label:"Latest time for Dhuhr / Asr",type:"text",hint:"How late people realistically are on campus. If a valid Asr cannot be placed before this, the tool says so instead of inventing a time nobody attends."},{key:"roundTo",label:"Rounding (minutes)",type:"number",min:1,max:30},{key:"slotLeadMin",label:"Booking starts before jamaah (min)",type:"number",min:0,max:60},{key:"slotLengthMin",label:"Booking length (min)",type:"number",min:5,max:180},{key:"slotPhaseMin",label:"Minutes past the slot",type:"number",min:0,max:30,hint:"Times land on the slot grid plus these minutes. 0 keeps every time after 16:00 on a quarter hour (:00, :15, :30, :45), which students can predict. 5 puts it on :05, :20, :35 or :50, so the booking starts on the quarter and the prayer five past it; the board stopped needing that in November 2026."},{key:"stability",label:"When choosing the fixed weekly times",type:"select",options:gt,hint:'"Fewest changes" means fewer room bookings to apply for, but the jamaah sits further after the adhan on the earliest days of each stretch.'}]},{id:"closed",title:"Holidays and closed dates",fields:[{key:"autoNorwegianHolidays",label:"Norwegian public holidays (automatic)",type:"toggle",hint:"New Year's Day, Maundy Thursday, Good Friday, Easter, 1 May, 17 May, Ascension, Whitsun and Christmas. Easter is calculated for each year, so it stays right for any file."},{key:"closedDatesText",label:"Your own closed dates, one per line, single days or ranges",type:"textarea",placeholder:`Juleferie: 21-12-2026 til 02-01-2027 5Vinterferie: 15-02-2027 - 19-02-2027 6Sommerferie: 22-06-2026 til 09-08-2026 706-04-2026`,hint:"Write it however you like: a label in front is fine, and dates may be dd-MM-yyyy or yyyy-MM-dd. Two dates on one line means everything between them is closed."}]},{id:"fajr",title:"Fajr",fields:[{key:"fajrEnabled",label:"Fajr jamaah on",type:"toggle"},{key:"fajrFixed",label:"Fixed time",type:"text"},{key:"fajrMinSunrise",label:"Only when sunrise is at or after",type:"text",hint:"A fixed Fajr jamaah only makes sense in winter, when sunrise is late enough that the prayer time is still valid at that hour."}]},{id:"dhuhr",title:"Dhuhr and Friday prayer",fields:[{key:"dhuhrEnabled",label:"Dhuhr jamaah on",type:"toggle"},{key:"dhuhrPreferred",label:"Preferred times (in priority order)",type:"text",hint:"The break slots, comma separated, e.g. 11:05, 12:05, 13:05. The first one that is valid all week is used; the time only changes when it has to."},{key:"dhuhrGapToAsrMin",label:"Minutes to pray before Asr begins",type:"number",min:0,max:120},{key:"dhuhrMaxWaitMin",label:"Max wait after adhan (min)",type:"number",min:0,max:360},{key:"freeAfter",label:"No classes after",type:"text"},{key:"noDhuhrWeekdays",label:"No Dhuhr on these weekdays",type:"weekdays"},{key:"jumuahEnabled",label:"Friday prayer at a fixed time",type:"toggle",hint:'Without a fixed time, Friday simply reads "Jummuah" in the timetable and on the poster, the way the tables have always done it.'},{key:"jumuahTime",label:"Friday prayer time",type:"text"},{key:"jumuahLabel",label:"Word used on Fridays",type:"text"}]},{id:"asr",title:"Asr",fields:[{key:"asrEnabled",label:"Asr jamaah on",type:"toggle"},{key:"asrBasis",label:"Asr based on",type:"select",options:[{value:"hanafi",label:"Hanafi (2à shadow): valid for everyone"},{value:"shafi",label:"Shafi (1à shadow): earlier"}],hint:"Hanafi is the safe default: a jamaah after the Hanafi Asr time is valid for both. In summer the Hanafi Asr falls after campus hours, so Asr may not be schedulable at all; the tool will say so."},{key:"asrStability",label:"How the Asr time is chosen",type:"select",options:[{value:"earliest-free",label:"Closest to the adhan, but never during teaching"},{value:"earliest",label:"Closest to the adhan, whatever is on the timetable"},{value:"",label:"Follow the general setting"}],hint:"Asr moves six hours across the year, so it gets its own choice. The first option takes the earliest time that is valid on every open day of the week and lands on one of the breaks below or after the last lecture. That way nobody has to choose between jamaah and class."},{key:"asrPreferred",label:"Preferred times (in priority order)",type:"text"},{key:"asrGapToMaghribMin",label:"Minutes to pray before Maghrib",type:"number",min:0,max:120},{key:"asrMaxWaitMin",label:"Max wait after adhan (min)",type:"number",min:0,max:360},{key:"asrStepMin",label:"Slot grid (min)",type:"number",min:1,max:60,hint:"How simple the year reads once teaching is over for the day. Over 2026, 15 keeps the jamaah on the quarter hours: 17 times, 26 changes, 20 min after the adhan on average. 30 keeps it on the hour or the half: 10 times, 17 changes, 24 min. 60 keeps it on the hour: 9 times, 14 changes, 28 min."}]},{id:"maghrib",title:"Maghrib",fields:[{key:"maghribEnabled",label:"Maghrib jamaah on",type:"toggle"},{key:"maghribOffsetMin",label:"Minutes after adhan",type:"number",min:0,max:60,hint:"Maghrib follows the sun and moves every day, so it is not held fixed across a week."}]},{id:"isha",title:"Isha",fields:[{key:"ishaEnabled",label:"Isha jamaah on",type:"toggle"},{key:"ishaRoundTo",label:"Round to (min)",type:"number",min:1,max:60,hint:"15 keeps Isha on the quarter hours, like Asr after 16:00."},{key:"ishaMaxWaitMin",label:"Max wait after adhan (min)",type:"number",min:0,max:360,hint:"Lower: the fixed Isha follows the adhan more closely but changes more often. Higher: fewer changes, longer waiting on the earliest days. On quarter hours Isha needs 30: at 20, fifteen weeks of 2026 lose Isha altogether."}]},{id:"files",title:"Output files",fields:[{key:"ibonnDateFormat",label:"Date format in the iBønn file",type:"select",options:[{value:"dd-MM",label:"dd-MM"},{value:"dd-MM-yyyy",label:"dd-MM-yyyy"}]},{key:"ibonnAsrBasis",label:"Asr in the iBønn file counts from",type:"select",options:[{value:"clock",label:"Standard in summer time, Hanafi in winter time: what iBønn does"},{value:"shafi",label:"Standard (1à shadow) all year"},{value:"hanafi",label:"Hanafi (2à shadow) all year"}],hint:"iBønn ignores the times in this file and adds each offset to its own prayer time. For Asr that has been Standard (1Ã) in summer time and Hanafi (2Ã) in winter time, whatever the admin panel says. After uploading, check one day on each side of a clock change in the admin panel against the poster. If both match, leave this alone."}]}],Te={fontSize:"var(--c-micro)",letterSpacing:".08em",color:"var(--c-faint)"},Se={fontSize:"var(--c-fine)",color:"var(--c-faint)"};function Ne({items:e,value:a,onChange:t}){const s=new Set(a||[]);return o.jsx("div",{className:"flex flex-wrap gap-1.5",children:e.map(n=>{const l=s.has(n.value);return o.jsx("button",{type:"button","aria-pressed":l,onClick:()=>{const i=new Set(s);l?i.delete(n.value):i.add(n.value),t([...i].sort((m,d)=>m-d))},className:"rounded-full px-3 min-h-[36px] font-display",style:{fontSize:"var(--c-label)",background:l?"var(--c-accent-soft)":"var(--c-panel)",color:l?"var(--c-accent)":"var(--c-text)",border:`1px solid ${l?"var(--c-accent)":"var(--c-line)"}`},children:n.label},n.value)})})}const bt=se.map((e,a)=>({value:a+1,label:e})),xt=[1,2,3,4,5,6,0].map(e=>({value:e,label:be[e]}));function wt({field:e,value:a,onChange:t}){const{key:s,type:n,placeholder:l,min:i,max:m,step:d,options:p}=e;return n==="toggle"?o.jsxs("label",{className:"flex items-center gap-3 cursor-pointer min-h-[44px]",children:[o.jsx("input",{type:"checkbox",checked:!!a,onChange:y=>t(y.target.checked),className:"w-4 h-4 flex-shrink-0",style:{accentColor:"var(--c-accent)"}}),o.jsx("span",{className:"font-serif",style:{fontSize:".95rem"},children:e.label})]}):n==="months"?o.jsx(Ne,{items:bt,value:a,onChange:t}):n==="weekdays"?o.jsx(Ne,{items:xt,value:a,onChange:t}):n==="select"?o.jsx("select",{value:a??"",onChange:y=>t(y.target.value),className:"rounded-[4px] px-3 w-full",style:P,children:p.map(y=>o.jsx("option",{value:y.value,children:y.label},y.value))}):n==="textarea"?o.jsx("textarea",{value:a??"",onChange:y=>t(y.target.value),rows:5,spellCheck:!1,placeholder:l,className:"rounded-[4px] px-3 py-2 w-full font-serif",style:{...P,minHeight:120}}):o.jsx("input",{type:n==="number"?"number":"text",value:a??"",min:i,max:m,step:d,placeholder:l,onChange:y=>t(n==="number"?y.target.value===""?"":Number(y.target.value):y.target.value),className:"rounded-[4px] px-3 w-full",style:P,"data-key":s})}function kt({settings:e,onChange:a,onReset:t,year:s}){return o.jsxs("section",{children:[o.jsxs("div",{className:"flex items-baseline justify-between gap-3 mb-2.5",children:[o.jsxs("p",{className:"font-display font-semibold uppercase",style:Te,children:["Settings · ",s]}),o.jsx(H,{size:"sm",onClick:t,children:"Reset to the defaults"})]}),yt.map((n,l)=>o.jsxs(Fe,{title:n.title,defaultOpen:l===0,children:[n.hint&&o.jsx("p",{className:"font-serif mb-3",style:Se,children:n.hint}),o.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[n.fields.map(i=>{const m=["months","weekdays","textarea","select"].includes(i.type)||["dhuhrPreferred","asrPreferred"].includes(i.key);return o.jsxs("div",{className:m?"sm:col-span-2":"",children:[i.type!=="toggle"&&o.jsx("p",{className:"font-display font-semibold uppercase mb-1.5",style:Te,children:i.label}),o.jsx(wt,{field:i,value:e[i.key],onChange:d=>
7a({[i.key]:d})}),i.hint&&o.jsx("p",{className:"font-serif mt-1.5",style:Se,children:i.hint})]},i.key)}),n.id==="closed"&&o.jsxs("div",{className:"sm:col-span-2 flex flex-wrap gap-2",children:[o.jsx(H,{size:"sm",onClick:()=>a({closedDatesText:De(e.closedDatesText,`Sommerferie: 22-06-${s} - 09-08-${s}`)}),children:"Add summer break"}),o.jsx(H,{size:"sm",onClick:()=>a({closedDatesText:De(e.closedDatesText,`Juleferie: 21-12-${s} - 02-01-${s+1}`)}),children:"Add Christmas break"})]})]})]},n.id))]})}function De(e,a){const t=String(e||"");return t.split(` 8`).some(s=>s.trim()===a.trim())?t:(t.trim()?t.replace(/\s*$/,"")+` 9`:"")+a}function ee(e,a,{bom:t=!0}={}){const s=new Blob([t?"\uFEFF":"",a],{type:"text/plain;charset=utf-8"}),n=URL.createObjectURL(s),l=document.createElement("a");l.href=n,l.download=e,document.body.appendChild(l),l.click(),l.remove(),setTimeout(()=>URL.revokeObjectURL(n),1e3)}function jt(e){const a=e%19,t=Math.floor(e/100),s=e%100,n=Math.floor(t/4),l=t%4,i=Math.floor((t+8)/25),m=Math.floor((t-i+1)/3),d=(19*a+t-n-m+15)%30,p=Math.floor(s/4),y=s%4,c=(32+2*l+2*p-d-y)%7,f=Math.floor((a+11*d+22*c)/451);return R(e,Math.floor((d+c-7*f+114)/31),(d+c-7*f+114)%31+1)}function vt(e){const a=jt(e),t=[],s=(n,l,i)=>t.push({date:n,no:l,en:i});return s(R(e,1,1),"NyttÃ¥rsdag","New Year's Day"),s(z(a,-3),"Skjærtorsdag","Maundy Thursday"),s(z(a,-2),"Langfredag","Good Friday"),s(a,"1. pÃ¥skedag","Easter Sunday"),s(z(a,1),"2. pÃ¥skedag","Easter Monday"),s(R(e,5,1),"1. mai","Labour Day"),s(R(e,5,17),"17. mai","Constitution Day"),s(z(a,39),"Kristi himmelfartsdag","Ascension Day"),s(z(a,49),"1. pinsedag","Whit Sunday"),s(z(a,50),"2. pinsedag","Whit Monday"),s(R(e,12,25),"1. juledag","Christmas Day"),s(R(e,12,26),"2. juledag","Boxing Day"),t}function Mt(e){const a=new Map,t=[],s=/\d{4}-\d{1,2}-\d{1,2}|\d{1,2}[-./]\d{1,2}[-./]\d{2,4}/g;for(const n of String(e||"").split(/[\n;,]+/)){const l=n.trim();if(!l)continue;const m=(l.match(s)||[]).map(ae).filter(Boolean);if(!m.length){t.push(l);continue}const d=l.replace(s,"").replace(/\b(til|to|through|and|og)\b/gi,"").replace(/[-ââ:]+/g," ").trim();if(m.length===1)a.set(_(m[0]),d||null);else{let p=m[0],y=m[m.length-1];if(p>y){const c=p;p=y,y=c}if((y-p)/864e5>400){t.push(l);continue}for(let c=p;c<=y;c=z(c,1))a.set(_(c),d||null)}}return{dates:a,bad:t}}const Ce=4;function xe(e,a){return Math.min(a-e.slotLeadMin+e.slotLengthMin,e.latestAllowed)}const Tt=15,St=45;function Pe(e,a){const t=Tt,s=e.slotLeadMin,n=e.slotLengthMin,l=Math.min(...a),i=Math.max(...a),m=Math.max(St,Math.ceil(n/t)*t);let d=null;for(let p=Math.floor((l-s)/t)*t;p<=Math.floor((i-s)/t)*t;p+=t)for(let y=t;y<=m;y+=t){const c=p+y;
9if(c>e.latestAllowed)continue;const f=a.filter(u=>u-s>=p&&u-s+n<=c).length,g=a.filter(u=>u>=p&&u<=c).length;g&&(!d||f>d.served||f===d.served&&g>d.held||f===d.served&&g===d.held&&y<d.len)&&(d={start:p,end:c,served:f,held:g,len:y})}return d?{start:d.start,end:d.end}:{start:Math.floor((l-s)/t)*t,end:e.latestAllowed}}function Nt(e){const a=l=>I(e[l]),t=l=>String(l||"").split(/[,;\s]+/).map(I).filter(i=>i!=null),s=(l,i)=>{const m=Number(e[l]);return Number.isFinite(m)?m:i},n=l=>String(e[l]||"").trim();return{rangeFrom:ae(e.rangeFrom),rangeTo:ae(e.rangeTo),rangeFromRaw:n("rangeFrom"),rangeToRaw:n("rangeTo"),closedMonths:new Set(e.closedMonths||[]),closedWeekdays:new Set(e.closedWeekdays||[]),autoNorwegianHolidays:!!e.autoNorwegianHolidays,closedDatesText:e.closedDatesText||"",noDhuhrWeekdays:new Set(e.noDhuhrWeekdays||[]),earliestAllowed:a("earliestAllowed")??0,latestAllowed:a("latestAllowed")??1320,latestDayPrayer:a("latestDayPrayer")??1080,roundTo:Math.max(1,s("roundTo",5)),slotLeadMin:s("slotLeadMin",5),slotLengthMin:Math.max(5,s("slotLengthMin",30)),slotPhaseMin:s("slotPhaseMin",5),stability:e.stability==="fewest"?"fewest":"preferred",fajrEnabled:!!e.fajrEnabled,fajrFixed:a("fajrFixed"),fajrMinSunrise:a("fajrMinSunrise"),dhuhrEnabled:!!e.dhuhrEnabled,dhuhrPreferred:t(e.dhuhrPreferred),dhuhrGapToAsrMin:s("dhuhrGapToAsrMin",15),dhuhrMaxWaitMin:s("dhuhrMaxWaitMin",90),freeAfter:a("freeAfter")??975,jumuahEnabled:!!e.jumuahEnabled,jumuahTime:a("jumuahTime"),jumuahLabel:(e.jumuahLabel===void 0?"Jummah":String(e.jumuahLabel)).trim(),asrEnabled:!!e.asrEnabled,asrBasis:e.asrBasis==="shafi"?"shafi":"hanafi",asrPreferred:t(e.asrPreferred),asrGapToMaghribMin:s("asrGapToMaghribMin",20),asrMaxWaitMin:s("asrMaxWaitMin",90),asrStepMin:Math.max(1,s("asrStepMin",15)),asrStability:["earliest-free","earliest","preferred","fewest"].includes(e.asrStability)?e.asrStability:"",maghribEnabled:!!e.maghribEnabled,maghribOffsetMin:s("maghribOffsetMin",3),ishaEnabled:!!e.ishaEnabled,ishaRoundTo:Math.max(1,s("ishaRoundTo",15)),ishaMaxWaitMin:s("ishaMaxWaitMin",60),ibonnDateFormat:e.ibonnDateFormat==="dd-MM-yyyy"?"dd-MM-yyyy":"dd-MM",ibonnAsrBasis:["shafi","hanafi"].includes(e.ibonnAsrBasis)?e.ibonnAsrBasis:"clock"}}function Dt(e,a){const t=e.length,s=new Array(t).fill(null),n=(y,c)=>{const f=e[c].win;return!(!f.valid||y<f.lo||y>f.hi||a.maxWait>0&&f.minAdhan!=null&&y-f.minAdhan>a.maxWait)},l=y=>{const c=e[y].win;if(!c.valid)return{tier0:[],tier1:[]};const f=a.preferred.filter(x=>n(x,y)),g=[],u=a.step,b=((a.phase||0)%u+u)%u;for(let x=Math.ceil((c.lo-b)/u)*u+b;x<=c.hi;x+=u)n(x,y)&&g.push(x);return!g.length&&n(c.lo,y)&&g.push(c.lo),{tier0:f,tier1:g}};if(a.stability==="earliest"||a.stability==="earliest-free"){const y=a.stability==="earliest-free"&&a.freeAfter!=null;for(let c=0;c<t;c++){const{tier0:f,tier1:g}=l(c);let u=f.concat(g);if(y&&n(a.freeAfter,c)&&(u=u.concat(a.freeAfter)),!u.length)continue;const b=y?u.filter(x=>x>=a.freeAfter||a.preferred.includes(x)):[];s[c]=Math.min(...b.length?b:u)}return s}const i=y=>{const c=a.preferred.indexOf(y);return c<0?a.preferred.length:c},m=(y,c)=>{const f=i(y);return a.preferred.some((g,u)=>u<f&&n(g,c))},d=(y,c)=>n(y,c)&&!m(y,c);let p=0;for(;p<t;){if(!e[p].win.valid){p++;continue}const y=e[p].win,{tier0:c,tier1:f}=l(p),g=c.length?c:f;if(!g.length){p++;continue}const u=a.stability==="fewest";let b=null;if(c.length&&!u){const x=g[0];let j=1;for(;p+j<t&&d(x,p+j);)j++;b={t:x,run:j}}else for(const x of g){let j=1;for(;p+j<t&&d(x,p+j);)j++;const A=y.minAdhan==null?0:x-y.minAdhan;(!b||j>b.run||j===b.run&&A<b.wait)&&(b={t:x,run:j,wait:A})}for(let x=0;x<b.run;x++)s[p+x]=b.t;p+=b.run}return s}function he(e,a){let t=null,s=null,n=null,l=0,i=0;for(const y of e){const c=a.pick(y);if(c==null){i++;continue}if(l++,t=t==null?c:Math.max(t,c),s=s==null?c:Math.min(s,c),a.limitOf){const f=a.limitOf(y);f!=null&&(n=n==null?f:Math.min(n,f))}}if(t==null)return{valid:!1,reason:"nodata",nDays:0,nMissing:i};const m=Math.max(Xe(t,a.round),a.earliest);let d=a.hardCap;n!=null&&(d=Math.min(d,Ze(n-a.gap,a.round)));const p=m<=d;return{valid:p,lo:m,hi:d,maxAdhan:t,minAdhan:s,nDays:l,nMissing:i,reason:p?null:"nowindow",limit:n}}function Ct(e,a){const t=Nt(a),s=[],n=(r,h)=>s.push(Object.assign({level:r},h));for(const[r,h]of[["rangeFrom","Fra dato / From date"],["rangeTo","Til dato / To date"]]
9)t[r+"Raw"]&&t[r]==null&&n("error",{scope:"file",no:"Forsto ikke «"+h.split(" / ")[0]+"»: «"+t[r+"Raw"]+"». Skriv den som 12-08-2026.",en:'Could not read "'+h.split(" / ")[1]+'": "'+t[r+"Raw"]+'". Write it as 12-08-2026.'});if(t.rangeFrom||t.rangeTo){const r=e.length;e=e.filter(h=>(!t.rangeFrom||h.date>=t.rangeFrom)&&(!t.rangeTo||h.date<=t.rangeTo)),t.rangeFrom&&t.rangeTo&&t.rangeFrom>t.rangeTo?n("error",{scope:"file",no:"«Fra dato» er etter «Til dato», sÃ¥ det blir ingen dager igjen.",en:'"From date" is after "To date", so no days are left.'}):e.length?n("info",{scope:"file",no:"Bruker "+e.length+" av "+r+" dager i filen: "+L(e[0].date)+"â"+L(e[e.length-1].date)+".",en:"Using "+e.length+" of "+r+" days from the file: "+L(e[0].date)+"â"+L(e[e.length-1].date)+"."}):n("error",{scope:"file",no:"Ingen datoer i filen ligger i perioden du valgte.",en:"No dates in the file fall inside the period you chose."})}const l=new Map,i=Mt(t.closedDatesText);for(const[r,h]of i.dates)l.set(r,h?{no:h,en:h}:null);if(i.bad.length&&n("warn",{scope:"file",no:"Forsto ikke disse linjene under «stengte datoer»: "+i.bad.join(" / ")+".",en:'Could not read these lines under "closed dates": '+i.bad.join(" / ")+"."}),t.autoNorwegianHolidays&&e.length){const r=e[0].date.getUTCFullYear(),h=e[e.length-1].date.getUTCFullYear();for(let v=r;v<=h;v++)for(const T of vt(v))l.has(_(T.date))||l.set(_(T.date),{no:T.no,en:T.en})}const m=r=>t.closedMonths.has(r.getUTCMonth()+1)||t.closedWeekdays.has(r.getUTCDay())||l.has(_(r)),d=[],p=new Map;for(const r of e){const{year:h,week:v}=tt(r.date),T=h+"-W"+O(v);let N=p.get(T);N||(N={key:T,year:h,week:v,all:[],open:[]},p.set(T,N),d.push(N)),N.all.push(r),m(r.date)||N.open.push(r)}const y=r=>t.asrBasis==="shafi"?r.asrShafi:r.asrHanafi;for(const r of d){const h=r.open.filter(v=>!t.noDhuhrWeekdays.has(v.date.getUTCDay()));r.dhuhr={win:he(h,{pick:v=>v.dhuhr,limitOf:v=>v.asrShafi,gap:t.dhuhrGapToAsrMin,hardCap:Math.min(t.latestDayPrayer,t.latestAllowed),round:t.roundTo,earliest:t.earliestAllowed})},r.asr={win:he(r.open,{pick:y,limitOf:v=>v.maghrib,gap:t.asrGapToMaghribMin,hardCap:Math.min(t.latestDayPrayer,t.latestAllowed),round:t.roundTo,earliest:t.earliestAllowed})},r.isha={win:he(r.open,{pick:v=>v.isha,limitOf:null,gap:0,hardCap:t.latestAllowed,round:t.ishaRoundTo,earliest:t.earliestAllowed})}}const c=(r,h)=>{const v=d.map(N=>({win:N[r].win})),T=Dt(v,Object.assign({},h,{stability:h.stability||t.stability}));d.forEach((N,U)=>{N[r].time=T[U]})},f=t.slotPhaseMin;t.dhuhrEnabled&&c("dhuhr",{preferred:t.dhuhrPreferred,step:15,phase:f,maxWait:t.dhuhrMaxWaitMin}),t.asrEnabled&&c("asr",{preferred:t.asrPreferred,step:t.asrStepMin,phase:f,maxWait:t.asrMaxWaitMin,stability:t.asrStability,freeAfter:t.freeAfter}),t.ishaEnabled&&c("isha",{preferred:[],step:t.ishaRoundTo,phase:f,maxWait:t.ishaMaxWaitMin});const g=[];d.forEach((r,h)=>{if(!r.open.length)return;const v=(T,N,U)=>{if(!T||r[N].time!=null)return;const F=r[N].win;g.push({pi:h,key:N,name:U,kind:F.reason==="nodata"?"nodata":F.valid?"nofit":"toolate",lo:F.lo,hi:F.hi,cap:N==="isha"?t.latestAllowed:Math.min(t.latestDayPrayer,t.latestAllowed),week:r.week,from:r.open[0].date,to:r.open[r.open.length-1].date})};v(t.dhuhrEnabled,"dhuhr","Dhuhr"),v(t.asrEnabled,"asr","Asr"),v(t.ishaEnabled,"isha","Isha")});const u={dhuhr:0,asr:1,isha:2};g.sort((r,h)=>u[r.key]-u[h.key]||r.pi-h.pi);for(let r=0;r<g.length;){const h=g[r];let v=r+1;for(;v<g.length&&g[v].key===h.key&&g[v].kind===h.kind&&g[v].pi===g[v-1].pi+1;)v++;const T=g[v-1],N=v-r===1,U=N?"Uke "+h.week:"Uke "+h.week+"â"+T.week,F=N?"Week "+h.week:"Weeks "+h.week+"â"+T.week,B=" ("+Y(h.from)+"â"+Y(T.to)+")",W=g.slice(r,v).map(ie=>ie.lo).filter(ie=>ie!=null),ke=W.length?Math.min(...W)===Math.max(...W)?w(W[0]):w(Math.min(...W))+"â"+w(Math.max(...W)):"";h.kind==="nodata"?n("info",{scope:"week",no:U+B+": ingen "+h.name+"-tid i filen (normalt om sommeren i Norge).",en:F+B+": no "+h.name+" time in the file (normal in a Norwegian summer)."}):h.kind==="nofit"?n("warn",{scope:"week",no:U+B+": "+h.name+" droppet â ingen foretrukket tid passer, og ventetiden etter adhan ville blitt for lang. Gyldig vindu: "+w(h.lo)+"â"+w(h.hi)+".",en:F+B+": "+h.name+" dropped â no preferred time fits and the wait after the adhan would be too long. Valid window: "+w(h.lo)+"â"+w(h.hi)+"."}):n("warn",{scope:"week",no:U+B+": "+h.name+" kan ikke legges. Tidligste gyldige tid er "+ke+", som er etter grensen "+w(h.cap)+".",en:F+B+": "+h.name+" cannot be scheduled. The earliest valid time is "+ke+", which is past the "+w(h.cap)+" cut-off."}),r=v}const b=[];d.forEach((r,h)=>{const v=(T,N,U,F,B)=>{const W=r[N]?r[N].time:null;!T||W==null||!r.open.length||W>=t.freeAfter||U.includes(W)||b.push({pi:h,key:N,name:F,t:W,mode:B,week:r.week,from:r.open[0].date,to:r.open[r.open.length-1].date})};v(t.dhuhrEnabled,"dhuhr",t.dhuhrPreferred,"Dhuhr",""),v(t.asrEnabled,"asr",t.asrPreferred,"Asr",t.asrStability||t.stability)});const x={dhuhr:0,asr:1};b.sort((r,h)=>x[r.key]-x[h.key]||r.pi-h.pi);for(let r=0;r<b.length;){const h=b[r];let v=r+1;for(;v<b.length&&b[v].key===h.key&&b[v].t===h.t&&b[v].pi===b[v-1].pi+1;)v++;const T=b[v-1],N=v-r===1,U=N?"Uke "+h.week:"Uke "+h.week+"â"+T.week,F=N?"Week "+h.week:"Weeks "+h.week+"â"+T.week,B=" ("+Y(h.from)+"â"+Y(T.to)+")",W=h.mode==="earliest-free"?{no:", og denne uka finnes det ingen tid som ikke gjør det: hele Asr-vinduet ("+w(h.t)+"â"+w(t.freeAfter)+") ligger inne i undervisningen, fordi adhan kommer etter siste pause og Maghrib kommer før siste forelesning er ute. Ingen innstilling løser denne â dere mÃ¥ enten be midt i en forelesning, droppe jamaah denne uka, eller regne Asr fra Shafi (1à skygge) her.",en:", and this week has no time that does not: the whole Asr window ("+w(h.t)+"â"+w(t.freeAfter)+") sits inside teaching hours, because the adhan arrives after the last break and Maghrib arrives before the last lecture ends. No setting solves this one â either pray during a lecture, drop the jamaah this week, or base Asr on Shafi (1à shadow) here."}:h.mode==="earliest"?{no:" fordi den legges nærmest mulig adhan. Vil du heller ha pausen her, bytt «hvordan Asr-tiden velges» til «aldri i undervisningstiden».",en:' because it is placed as close to the adhan as possible. If you would rather have the break here, switch "how the Asr time is chosen" to "never during teaching".'}
9:{no:". Bønnetidene tillater ikke noe bedre denne perioden â regn med lavere oppmøte, eller legg inn en pause som passer under «foretrukne tidspunkter».",en:'. The prayer times allow nothing better in this period â expect lower attendance, or add a matching break under "preferred times".'};n("info",{scope:"week",no:U+B+": "+h.name+" kl. "+w(h.t)+" faller utenom pausene"+W.no,en:F+B+": "+h.name+" at "+w(h.t)+" falls outside the breaks"+W.en}),r=v}const j=new Map;for(const r of d)for(const h of r.all)j.set(_(h.date),r);const A=e.map(r=>{const h=j.get(_(r.date)),v=r.date.getUTCDay(),T={row:r,date:r.date,period:h,closed:m(r.date),closedName:l.get(_(r.date))||null,fajr:null,dhuhr:null,asr:null,maghrib:null,isha:null,asrBase:y(r)};if(T.closed)return T;if(t.fajrEnabled&&t.fajrFixed!=null&&r.sunrise!=null&&(t.fajrMinSunrise==null||r.sunrise>=t.fajrMinSunrise)&&(T.fajr=t.fajrFixed),t.noDhuhrWeekdays.has(v)?(T.jumuah=!0,t.jumuahEnabled&&t.jumuahTime!=null&&(T.dhuhr=t.jumuahTime)):t.dhuhrEnabled&&h&&(T.dhuhr=h.dhuhr.time),t.asrEnabled&&h&&(T.asr=h.asr.time),t.ishaEnabled&&h&&(T.isha=h.isha.time),t.maghribEnabled&&r.maghrib!=null){const N=r.maghrib+t.maghribOffsetMin;N<=t.latestAllowed&&(T.maghrib=N)}return T});let M=0;const k=(r,h,v)=>n("error",{scope:"day",no:L(r)+": "+h,en:L(r)+": "+v});for(const r of A){const h=r.row;r.fajr!=null&&(M++,h.fajr!=null&&r.fajr<h.fajr&&k(r.date,"Fajr-jamaat "+w(r.fajr)+" er før adhan "+w(h.fajr)+".","Fajr jamaat "+w(r.fajr)+" is before the adhan "+w(h.fajr)+"."),h.sunrise!=null&&r.fajr>=h.sunrise&&k(r.date,"Fajr-jamaat "+w(r.fajr)+" er etter soloppgang "+w(h.sunrise)+".","Fajr jamaat "+w(r.fajr)+" is after sunrise "+w(h.sunrise)+".")),r.dhuhr!=null&&(M++,h.dhuhr!=null&&r.dhuhr<h.dhuhr&&k(r.date,"Dhuhr-jamaat "+w(r.dhuhr)+" er før adhan "+w(h.dhuhr)+".","Dhuhr jamaat "+w(r.dhuhr)+" is before the adhan "+w(h.dhuhr)+"."),h.asrShafi!=null&&r.dhuhr>=h.asrShafi&&k(r.date,"Dhuhr-jamaat "+w(r.dhuhr)+" er etter Asr (Shafi) "+w(h.asrShafi)+".","Dhuhr jamaat "+w(r.dhuhr)+" is after Asr (Shafi) "+w(h.asrShafi)+".")),r.asr!=null&&(M++,r.asrBase!=null&&r.asr<r.asrBase&&k(r.date,"Asr-jamaat "+w(r.asr)+" er før Asr-tiden "+w(r.asrBase)+".","Asr jamaat "+w(r.asr)+" is before the Asr time "+w(r.asrBase)+"."),h.maghrib!=null&&r.asr>=h.maghrib&&k(r.date,"Asr-jamaat "+w(r.asr)+" er etter Maghrib "+w(h.maghrib)+".","Asr jamaat "+w(r.asr)+" is after Maghrib "+w(h.maghrib)+".")),r.maghrib!=null&&(M++,h.maghrib!=null&&r.maghrib<h.maghrib&&k(r.date,"Maghrib-jamaat før adhan.","Maghrib jamaat before the adhan."),h.isha!=null&&r.maghrib>=h.isha&&k(r.date,"Maghrib-jamaat "+w(r.maghrib)+" er etter Isha "+w(h.isha)+".","Maghrib jamaat "+w(r.maghrib)+" is after Isha "+w(h.isha)+".")),r.isha!=null&&(M++,h.isha!=null&&r.isha<h.isha&&k(r.date,"Isha-jamaat "+w(r.isha)+" er før adhan "+w(h.isha)+".","Isha jamaat "+w(r.isha)+" is before the adhan "+w(h.isha)+"."),h.isha==null&&k(r.date,"Isha-jamaat satt, men filen har ingen Isha-tid denne dagen.","Isha jamaat set, but the file has no Isha time for this day.")),r.dhuhr!=null&&r.asr!=null&&r.asr<=r.dhuhr&&k(r.date,"Asr-jamaat "+w(r.asr)+" er ikke etter Dhuhr-jamaat "+w(r.dhuhr)+".","Asr jamaat "+w(r.asr)+" is not after the Dhuhr jamaat "+w(r.dhuhr)+".")}const C=(r,h)=>{const v=[];let T=null;for(const N of d){const U=N[r]?N[r].time:null,F=N.open.filter(B=>r!=="dhuhr"||!t.noDhuhrWeekdays.has(B.date.getUTCDay()));if(U==null||!F.length){T=null;continue}T&&T.time===U&&T.lastWeekIdx===d.indexOf(N)-1?(T.to=F[F.length-1].date,T.weeks++,T.lastWeekIdx=d.indexOf(N),F.forEach(B=>T.dows.add(B.date.getUTCDay()))):(T={prayer:h,time:U,from:F[0].date,to:F[F.length-1].date,weeks:1,lastWeekIdx:d.indexOf(N),dows:new Set(F.map(B=>B.date.getUTCDay()))},v.push(T))}return v},S=[];if(t.fajrEnabled){let r=null;for(const h of A)h.fajr!=null&&(r&&r.time===h.fajr&&(h.date-r.lastDate)/864e5<=Ce?(r.to=h.date,r.lastDate=h.date,r.dows.add(h.date.getUTCDay())):(r={prayer:"Fajr",time:h.fajr,from:h.date,to:h.date,weeks:0,lastDate:h.date,dows:new Set([h.date.getUTCDay()])},S.push(r)))}if(t.dhuhrEnabled&&S.push(...C("dhuhr","Dhuhr")),t.jumuahEnabled&&t.jumuahTime!=null){let r=null;for(const h of A)!t.noDhuhrWeekdays.has(h.date.getUTCDay())||h.closed||(r&&(h.date-r.lastDate)/864e5<=8+Ce?(r.to=h.date,r.lastDate=h.date):(r={prayer:"Jumu'ah",time:t.jumuahTime,from:h.date,to:h.date,weeks:0,lastDate:h.date,dows:new Set([h.date.getUTCDay()])},S.push(r)))}t.asrEnabled&&S.push(...C("asr","Asr")),t.ishaEnabled&&S.push(...C("isha","Isha")),S.sort((r,h)=>r.from-h.from||r.time-h.time);for(const r of S)r.start=r.time-t.slotLeadMin,r.end=xe(t,r.time);const E=[...l.keys()].filter(r=>j.has(r)).length;return{settings:t,periods:d,dayPlans:A,issues:s,bookings:S,checked:M,closedNames:l,closedInRange:E}}function At(e){const a=e.all[0].date,t=e.all[e.all.length-1].date,s=a.getUTCFullYear()===t.getUTCFullYear()?" "+a.getUTCFullYear():" "+a.getUTCFullYear()+"/"+t.getUTCFullYear();return"Uke "+e.week+" ("+ve(a)+" â "+ve(t)+s+")"}function we(e,a){a=a||Ue;const t=[1,2,3,4,5,6,0].filter(m=>e.has(m));if(!t.length)return"";const s=t.map(m=>a[m]),n=[1,2,3,4,5,6,0],l=t.map(m=>n.indexOf(m));return l.every((m,d)=>d===0||m===l[d-1]+1)&&s.length>2?s[0]+"â"+s[s.length-1]:s.join(", ")}function Ae(e){const a=e.settings,t=[];t.push("BÃNNETIDER OG ROMBOOKING â "+re(e)),t.push("====================================="),t.push("");const s=n=>w(n-a.slotLeadMin)+"â"+w(xe(a,n))+" (Jamaat "+w(n)+")";for(const n of e.periods){if(t.push(At(n)),t.push("-------------------------------------"),!n.open.length){t.push("Ingen bønner denne uken."),t.pu
9sh("");continue}if(n.open.length<n.all.length){const m=new Set(n.open.map(d=>d.date.getUTCDay()));t.push("Aktive dager: "+we(m)+" ("+Y(n.open[0].date)+"â"+Y(n.open[n.open.length-1].date)+")")}const l=e.dayPlans.filter(m=>m.period===n&&m.fajr!=null);t.push("Fajr: "+(l.length?s(l[0].fajr)+" ["+l.length+" dager]":"â")),t.push("Dhuhr: "+(n.dhuhr.time!=null?s(n.dhuhr.time):"â")),a.jumuahEnabled&&a.jumuahTime!=null&&n.open.some(m=>a.noDhuhrWeekdays.has(m.date.getUTCDay()))&&t.push("Jumu'ah: "+s(a.jumuahTime)),t.push("Asr: "+(n.asr.time!=null?s(n.asr.time):"â"));const i=e.dayPlans.filter(m=>m.period===n&&m.maghrib!=null).map(m=>m.maghrib);if(i.length){const m=Math.min(...i),d=Math.max(...i),p=Pe(a,i);t.push("Maghrib: "+w(p.start)+"â"+w(p.end)+" (Jamaat "+w(m)+(m===d?"":" â "+w(d))+", flytter seg daglig)")}else t.push("Maghrib: â");t.push("Isha: "+(n.isha.time!=null?s(n.isha.time):"â")),t.push("")}return t.join(`\r 10`)}function Et(e){const a=e.settings,t=[],s=n=>n.getUTCFullYear()+"-"+O(n.getUTCMonth()+1);for(const n of e.periods){if(!n.open.length)continue;const l=e.dayPlans.filter(d=>d.period===n&&!d.closed);if(!l.length)continue;const i=[];for(const d of l){const p=s(d.date);let y=i.length&&i[i.length-1].key===p?i[i.length-1]:null;y||(y={key:p,days:[]},i.push(y)),y.days.push(d)}const m=d=>{if(!d.length)return null;const p=k=>k.length?{lo:Math.min(...k),hi:Math.max(...k)}:null,y=k=>p(d.map(C=>C[k]).filter(C=>C!=null)),c=p(d.filter(k=>!k.jumuah).map(k=>k.dhuhr).filter(k=>k!=null)),f=p(d.filter(k=>k.jumuah).map(k=>k.dhuhr).filter(k=>k!=null)),g=[],u=(k,C,S)=>{if(!C)return;const E=S?Pe(a,S):{start:C.lo-a.slotLeadMin,end:xe(a,C.hi)};g.push({label:k,lo:C.lo,hi:C.hi,start:E.start,end:E.end})},b=d.map(k=>k.maghrib).filter(k=>k!=null);if(u("Fajr",y("fajr")),u("Dhuhr",c),u(a.jumuahLabel||"Jummuah",f),u("Asr",y("asr")),u("Maghrib",p(b),b.length?b:null),u("Isha",y("isha")),!g.length)return null;const x=d[0].date,j=d[d.length-1].date,A=new Set(d.map(k=>k.date.getTime())),M=n.all.filter(k=>k.date>x&&k.date<j&&!A.has(k.date.getTime())).map(k=>k.date);return{pd:n,first:x,last:j,slots:g,gaps:M}};for(const d of i){const p=m(d.days);p&&t.push(p)}}return t}function Ft(e,a){const t=q,s=ye,n=f=>f.replace(/^./,g=>g.toUpperCase()),l=f=>f.getUTCFullYear()+"-"+O(f.getUTCMonth()+1),i=f=>f.getUTCDate()+". "+s[f.getUTCMonth()],m=(f,g)=>{const u=n(t[f.getUTCMonth()]);return f.getTime()===g.getTime()?O(f.getUTCDate())+" "+u:f.getUTCMonth()===g.getUTCMonth()&&f.getUTCFullYear()===g.getUTCFullYear()?O(f.getUTCDate())+"â"+O(g.getUTCDate())+" "+u:O(f.getUTCDate())+" "+u+" â "+O(g.getUTCDate())+" "+n(t[g.getUTCMonth()])},d=Et(e).filter(f=>a.month==="all"||l(f.first)===a.month),p=[],y=String(a.greeting||"").trim();if(y&&(p.push(y),p.push("")),!d.length)p.push("Ingen rombookinger i dette utvalget.");else{d.forEach(u=>u.cells=u.slots.map(b=>b.label+": "+w(b.start)+" â "+w(b.end)));let f=0;d.forEach(u=>u.cells.forEach(b=>{b.length>f&&(f=b.length)}));let g=null;d.forEach(u=>{const b=l(u.first);b!==g?(g!==null&&p.push(""),g=b,p.push("Her er bookingtidene for "+n(t[u.first.getUTCMonth()])+":")):p.push(""),p.push(m(u.first,u.last)+" (Uke "+u.pd.week+"):");for(let x=0;x<u.cells.length;x+=3)p.push(u.cells.slice(x,x+3).map(j=>j.padEnd(f)).join(" ").replace(/\s+$/,""));u.gaps.length&&p.push("Unntatt: "+u.gaps.map(i).join(", "))})}const c=String(a.signoff||"").replace(/\s+$/,"");return c&&(p.push(""),c.split(/\r?\n/).forEach(f=>p.push(f))),p.join(`\r 11`)}function Ut(e){const a=String(e??"");return/[",;\r\n]/.test(a)?'"'+a.replace(/"/g,'""')+'"':a}const Q=e=>e.map(Ut).join(",");function re(e){if(!e.dayPlans.length)return String(new Date().getUTCFullYear());const a=e.dayPlans[0].date.getUTCFullYear(),t=e.dayPlans[e.dayPlans.length-1].date.getUTCFullYear();return a===t?String(a):a+"-"+t}function Lt(e,a){const t=Ue,s=l=>l.end-l.start,n=[Q(["Bønn","Fra dato","Til dato","Ukedager","Book fra","Book til","Minutter","Jamaat","Antall uker"])];for(const l of e.bookings)n.push(Q([l.prayer,L(l.from),L(l.to),we(l.dows,t),w(l.start),w(l.end),s(l),w(l.time),l.weeks||""]));return n.join(`\r 12`)}function Ot(e,a){const t=Le,s=[Q(["Dato","Ukedag","Fajr","Dhuhr","Asr","Maghrib","Isha","Merknad"])];for(const n of e.dayPlans){const l=t[n.date.getUTCDay()];if(n.closed){const i=n.closedName?n.closedName.no:"stengt";s.push(Q([Me(n.date),l,"","","","","",i]))}else{const i=n.dhuhr!=null?w(n.dhuhr):n.jumuah?e.settings.jumuahLabel:"";s.push(Q([Me(n.date),l,w(n.fajr),i,w(n.asr),w(n.maghrib),w(n.isha),""]))}}return s.join(`\r 13`)}function Bt(e){const a=e.settings,t=a.ibonnDateFormat==="dd-MM-yyyy"?L:Y,s=i=>a.ibonnAsrBasis==="hanafi"?i.asrHanafi:a.ibonnAsrBasis==="shafi"||et(i.date)?i.asrShafi:i.asrHanafi,n=["startDate,fajr,duhr,asr,maghrib,isha,fajrJamatOffset,duhrJamatOffset,asrJamatOffset,maghribJamatOffset,ishaJamatOffset"],l=(i,m)=>i==null||m==null?-1:Math.max(0,m-i);for(const i of e.dayPlans){const m=i.row;if(i.closed){n.push([t(i.date),"","","","","","-1","-1","-1","-1","-1"].join(","));continue}const d=(p,y)=>p!=null&&y!=null?w(y):"";n.push([t(i.date),d(i.fajr,m.fajr),d(i.dhuhr,m.dhuhr),d(i.asr,s(m)),d(i.maghrib,m.maghrib),d(i.isha,m.isha),l(i.fajr!=null?m.fajr:null,i.fajr),l(i.dhuhr!=null?m.dhuhr:null,i.dhuhr),l(i.asr!=null?s(m):null,i.asr),l(i.maghrib!=null?m.maghrib:null,i.maghrib),l(i.isha!=null?m.isha:null,i.isha)].join(","))}return n.join(`\r 14`)}const Wt='<svg class="qrsvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 27 27" shape-rendering="crispEdges"><path stroke="#04394E" d="M1 1.5h7m2 0h1m3 0h1m2 0h1m1 0h7M1 2.5h1m5 0h1m4 0h1m3 0h2m1 0h1m5 0h1M1 3.5h1m1 0h3m1 0h1m1 0h2m2 0h1m2 0h2m1 0h1m1 0h3m1 0h1M1 4.5h1m1 0h3m1 0h1m1 0h1m1 0h5m3 0h1m1 0h3m1 0h1M1 5.5h1m1 0h3m1 0h1m1 0h4m2 0h1m3 0h1m1 0h3m1 0h1M1 6.5h1m5 0h1m1 0h1m2 0h3m1 0h1m2 0h1m5 0h1M1 7.5h7m1 0h1m1 0h1m1 0h1m1 0h1m1 0h1m1 0h7M9 8.5h1m1 0h3m3 0h1M1 9.5h1m1 0h5m2 0h2m2 0h2m3 0h5M1 10.5
14h1m1 0h1m1 0h2m1 0h1m1 0h1m1 0h2m3 0h1m2 0h1m3 0h1M3 11.5h2m2 0h2m1 0h1m2 0h1m2 0h1m1 0h1m3 0h1m1 0h2M6 12.5h1m4 0h3m1 0h1m1 0h1m3 0h1m3 0h1M1 13.5h1m2 0h1m1 0h3m4 0h2m4 0h3m1 0h3M1 14.5h2m1 0h1m1 0h1m2 0h3m2 0h1m2 0h1m2 0h1m1 0h1m1 0h1M1 15.5h1m4 0h11m1 0h1m1 0h3m1 0h2M1 16.5h1m1 0h1m1 0h1m2 0h2m1 0h2m5 0h4m3 0h1M1 17.5h1m2 0h1m1 0h2m2 0h1m1 0h1m1 0h8m1 0h1M9 18.5h3m1 0h2m1 0h2m3 0h2M1 19.5h7m6 0h2m1 0h1m1 0h1m1 0h1m1 0h3M1 20.5h1m5 0h1m1 0h2m2 0h1m3 0h1m3 0h2m1 0h1M1 21.5h1m1 0h3m1 0h1m1 0h3m1 0h9m1 0h3M1 22.5h1m1 0h3m1 0h1m1 0h1m4 0h1m4 0h1m1 0h5M1 23.5h1m1 0h3m1 0h1m1 0h1m2 0h6m4 0h2m1 0h1M1 24.5h1m5 0h1m2 0h1m1 0h1m2 0h4m1 0h3m2 0h1M1 25.5h7m1 0h1m1 0h3m4 0h8"></path></svg>',Pt="/assets/fonts/poster",J=(e,a,t,s)=>`@font-face{font-family:${e};font-style:${a};font-weight:${t};font-display:block;src:url(${Pt}/${s}.woff2) format('woff2')}`,_t=J("Bitter","normal",700,"bitter-700")+J("Lato","normal",400,"lato-400")+J("Lato","italic",400,"lato-400i")+J("Lato","normal",700,"lato-700")+J("Lato","italic",700,"lato-700i")+J("Lato","normal",900,"lato-900"),Ht=_t+` 15.sheet{ 16 --teal:#00a69c; --ink:#123c45; --time:#077f76; --muted:#a2b9bb; 17 --tint:#f1f9f8; --sunday:#f6faf9; --hair:#bcdedb; 18 --on-teal-2:rgba(255,255,255,.85); --on-teal-3:rgba(255,255,255,.28); 19 --on-teal-tick:rgba(255,255,255,.55); 20 --font-sans:Lato,"Helvetica Neue",Helvetica,Arial,sans-serif; 21 --font-serif:Bitter,Georgia,"Times New Roman",serif; 22 /* 44 px is the drawn side gutter; top and bottom hold the drawn 40:44:30 23 ratio to it, so one setting moves the whole frame without skewing it. */ 24 --pad-x:11.6mm; --pad-top:calc(var(--pad-x)*40/44); --pad-bot:calc(var(--pad-x)*30/44); 25 width:210mm; height:297mm; box-sizing:border-box; 26 padding:var(--pad-top) var(--pad-x) var(--pad-bot); 27 margin:0 auto; background:#fff; color:var(--ink); 28 font-family:var(--font-sans); font-size:14.5px; line-height:1.2; 29 display:flex; flex-direction:column; overflow:hidden; 30 -webkit-font-smoothing:antialiased; 31 -webkit-print-color-adjust:exact; print-color-adjust:exact} 32.sheet+.sheet{margin-top:8mm} 33.sheet *{box-sizing:border-box} 34.sheet h1,.sheet p,.sheet dl,.sheet dt,.sheet dd{margin:0} 35 36/* Kept from the generator; no longer true here (see the header): fonts are files and the sheet is in an iframe. */ 37/* The generator styles its own tables and page footer with bare element 38 selectors â table, th, td, thead th, tbody tr:hover, footer â and those reach 39 into the sheet too, because the preview lives in the same document. An 40 element selector always beats an inherited value, so every property they 41 touch is restated here. Miss one and the preview quietly stops matching the 42 HTML that gets downloaded and printed, which is the one thing this pane is 43 for. The reset sits above the table rules so those can override it in turn. */ 44.sheet table.times th, 45.sheet table.times td{position:static;border:0;padding:0;text-align:center; 46 white-space:nowrap;font-style:normal;background:none} 47.sheet tr:hover{background:none} 48.sheet .footer{color:inherit;font-size:14.5px;line-height:1.2} 49 50/* ââ Tittel ââ */ 51.sheet .masthead{flex:none;display:flex;align-items:center;gap:26px; 52 padding-bottom:19px;border-bottom:2px solid var(--teal);margin-bottom:22px} 53.sheet .masthead img{height:88px;width:auto;display:block;flex:none} 54.sheet .masthead .mtext{flex:1;min-width:0} 55.sheet .masthead .wordmark{font-family:var(--font-serif);font-size:17px;font-weight:700; 56 line-height:1.1;color:var(--time);margin-bottom:7px} 57.sheet .masthead h1{font-family:var(--font-serif);font-weight:700;font-size:43px; 58 line-height:1;letter-spacing:-0.8px;color:var(--ink);margin-bottom:9px} 59/* MÃ¥neden bærer fargen â tittelen stÃ¥r i blekk. */ 60.sheet .masthead h1 span{color:var(--teal)} 61.sheet .masthead h1:last-child{margin-bottom:0} 62.sheet .masthead .notice{font-size:13.5px;line-height:1.35;color:var(--time)} 63.sheet .masthead .notice b{font-weight:700} 64 65/* ââ Tabell ââ */ 66.sheet .tablewrap{flex:1 1 auto;min-height:0;display:flex} 67.sheet table.times{flex:1 1 auto;width:100%;border-collapse:collapse;table-layout:fixed; 68 border:1px solid var(--hair);font-size:14.5px;color:var(--time);text-align:center; 69 font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1} 70.sheet table.times thead th{background:var(--teal);color:#fff;padding:13px 0; 71 font-size:10.5px;font-weight:700;letter-spacing:1.8px;text-align:center; 72 text-transform:uppercase} 73.sheet table.times thead th.h-day{text-align:left;padding-left:22px} 74/* No row height anywhere: the table is the flex child that swallows whatever 75 the masthead and the band leave over, and the browser hands that height out 76 evenly across the rows. Hard-code one and the sheet over- or under-runs. */ 77.sheet table.times tbody th, 78.sheet table.times tbody td{padding:0;font-size:14.5px;font-weight:400} 79.sheet table.times tbody th{text-align:left;padding-left:22px;color:var(--ink)} 80.sheet table.times td.date{font-weight:700;color:var(--ink)} 81.sheet table.times td.jummah{font-style:italic;font-weight:700} 82/* Annenhver hverdag tonet, slik at øyet klarer Ã¥ følge en rad tvers over arket. */ 83.sheet table.times tbody tr.tint th, 84.sheet table.times tbody tr.tint td{background:var(--tint)} 85.sheet table.times tbody tr.friday th{font-weight:700} 86/* Søndagen lukker uken: den eneste vannrette delingen i tabellen. */ 87.sheet table.times tbody tr.sunday th, 88.sheet table.times tbody tr.sunday td{background:var(--sunday); 89 border-bottom:2px solid var(--teal)} 90/* Stengt â søndag, helligdag eller ferie: dempet skrift og kursiv dato. */ 91.sheet table.times tbody tr.closed th, 92.sheet table.times tbody tr.closed td{color:var(--muted)} 93.sheet table.times tbody tr.closed td.date{font-weight:400;font-style:italic} 94 95/* ââ Bunnbjelke ââ */ 96.sheet .footer{flex:none;margin-top:22px} 97.sheet .footer .bar{display:grid;gap:26px;background:var(--teal);color:#fff; 98 padding:26px 30px} 99.sheet .footer .bdiv{background:var(--on-teal-3)} 100.sheet .footer .binfo{min-width:0;display:flex;flex-direction:column;gap:18px} 101.sheet .footer .btitle{display:flex;align-items:baseline;gap:12px;font-size:15px; 102 font-weight:700;letter-spacing:2.2px;text-transform:uppercase} 103.sheet .footer .btitle span{font-size:12px;font-weight:400;letter-spacing:normal; 104 text-transform:none;white-space:nowrap;color:var(--on-teal-2)} 105/* etikett over verdi â lettere Ã¥ lese enn én lang streng */ 106.sheet .footer .btimes{display:flex;gap:20px} 107.sheet .footer .btimes dt{font-size:10px;font-weight:700;letter-spacing:1.6px; 108 text-transform:uppercase;color:var(--on-teal-2);margin-bottom:6px} 109.sheet .footer .btimes dd{font-size:18px;font-weight:700;white-space:nowrap; 110 font-variant-numeric:tabular-nums} 111.sheet .footer .venue{display:flex;align-items:center;gap:11px;margin-top:2px} 112.sheet .footer .venue i{width:22px;height:2px;background:var(--on-teal-tick);flex:none} 113.sheet .footer .venue span{font-family:var(--font-serif);font-weight:700;font-size:19px; 114 letter-spacing:-0.2px;white-space:nowrap} 115.sheet .footer .app{display:flex;align-items:center;gap:12px} 116.sheet .footer .app>img{width:30px;height:30px;border-radius:7px;flex:none; 117 border:1px solid var(--on-teal-3)} 118.sheet .footer .apptext{width:162px;display:flex;flex-direction:column;gap:7px} 119.sheet .footer .applead{font-size:9.5px;font-weight:700;letter-spacing:1.4px; 120 text-transform:uppercase;white-space:nowrap;color:var(--on-teal-2)} 121.sheet .footer .appbody{font-size:11.5px;line-height:1.45;text-wrap:pretty} 122.sheet .footer .appbody b{font-weight:900} 123.sheet .footer .qr{flex:none;background:#fff;border-radius:12px;padding:11px 11px 8px; 124 text-align:center} 125.sheet .footer .qr .qrsvg{display:block;width:80px;height:80px} 126.sheet .footer .qr p{margin-top:6px;font-size:9.5px;font-weight:700;letter-spacing:.3px; 127 color:var(--ink)} 128/* Kanal-linjen stÃ¥r ikke i designet, men feltet finnes i generatoren: en stille 129 linje under bjelken, pÃ¥ samme venstrekant som masthead og tabell. */ 130.sheet .footer .channels{margin-top:10px;font-size:10.5px;line-height:1.4;color:var(--time)} 131.sheet .footer .channels b{font-weight:700;color:var(--ink)} 132 133/* Oversiktsplakaten har en hÃ¥ndfull rader, ikke 31. à strekke dem over et halvt 134 ark ville gitt seks kjempehøye striper, sÃ¥ den tabellen beholder sin egen 135 høyde øverst i feltet og lar bjelken bli stÃ¥ende i bunnen. */ 136.sheet .tablewrap.short{align-items:flex-start} 137.sheet table.times.short{flex:0 1 auto} 138.sheet table.times.short tbody tr{height:34px} 139 140@media print{ 141 /* .sheet+.sheet out-specifies .sheet, so the screen gap has to be cleared by 142 name or every month after the first starts 8 mm down its page. 143 Height drops to 295 mm: a sheet exactly as tall as the paper rounds over the 144 page edge on real printers and throws a blank second sheet. */ 145 .sheet,.sheet+.sheet{margin:0;height:295mm;page-break-after:always;break-after:page} 146 .sheet:last-child{page-break-after:auto;break-after:auto} 147}`;function X(e){return String(e??"").replace(/[&<>"]/g,a=>({"&":"&","<":"<",">":">",'"':"""})[a])}function ue(e){return X(e).replace(/\*\*([^*]+)\*\*/g,"<b>$1</b>")}function oe(e){const a=new Map;for(const t of e.dayPlans){const s=t.date.getUTCFullYear()+"-"+O(t.date.getUTCMonth()+1);a.has(s)||a.set(s,{key:s,y:t.date.getUTCFullYear(),m:t.date.getUTCMonth()})}return[...a.values()]}function _e(e){return"<div class='sheet' style='--pad-x:"+Math.min(25,Math.max(6,Number(e.marginMm)||11.6))+"mm'>"}const It="/assets/logo/full-onpaper.svg",Rt="/assets/prayer/ibonn.png";function He(e,a,t){const s=X;return"<header class='masthead'>"+("<img src='"+It+"' alt='Muslimsk Studentsamfunn'>")+"<div class='mtext'>"+""+"<h1>"+s(e)+(a?" <span>"+s(a)+"</span>":"")+"</h1>"+(t.notice?"<p class='notice'>"+ue(t.notice)+"</p>":"")+"</div></header>"}function Ie(e){const a=e.lang==="en",t=X,s=e.jumTitle!==void 0?e.jumTitle:a?"Friday prayer":"Jummuah",n=e.jumWho!==void 0?e.jumWho:a?"men & women":"menn & kvinner",l=[];e.jumSummer&&l.push([a?"Summer time":"Sommertid",e.jumSummer]),e.jumWinter&&l.push([a?"Winter time":"Vintertid",e.jumWinter]);const i=[];s&&i.push("<p class='btitle'>"+t(s)+(n?"<span>"+t(n)+"</span>":"")+"</p>
147"),l.length&&i.push("<dl class='btimes'>"+l.map(c=>"<div><dt>"+t(c[0])+"</dt><dd>"+t(c[1])+"</dd></div>").join("")+"</dl>"),e.location&&i.push("<p class='venue'><i></i><span>"+t(e.location)+"</span></p>");const m=[];(e.appLead||e.appBody)&&m.push("<img src='"+Rt+"' alt='iBønn'><div class='apptext'>"+(e.appLead?"<p class='applead'>"+t(e.appLead)+"</p>":"")+(e.appBody?"<p class='appbody'>"+ue(e.appBody)+"</p>":"")+"</div>"),e.qrCaption!==""&&m.push("<div class='qr'>"+Wt+(e.qrCaption?"<p>"+t(e.qrCaption)+"</p>":"")+"</div>");const d=[];i.length&&d.push("<div class='binfo'>"+i.join("")+"</div>"),m.length&&d.push("<div class='app'>"+m.join("")+"</div>");let p="";d.length===2?p="<div class='bar' style='grid-template-columns:1fr 1px auto'>"+d[0]+"<div class='bdiv'></div>"+d[1]+"</div>":d.length===1&&(p="<div class='bar' style='grid-template-columns:1fr'>"+d[0]+"</div>");const y=e.contact?"<p class='channels'>"+ue(e.contact)+"</p>":"";return!p&&!y?"":"<footer class='footer'>"+p+y+"</footer>"}function zt(e,a,t){const s=t.lang==="en",n=X,l=s?at:Le,i=s?se:q,m=e.dayPlans.filter(b=>b.date.getUTCFullYear()+"-"+O(b.date.getUTCMonth()+1)===a);if(!m.length)return"";const d=s?["Day","Date","Fajr","Dhuhr","Asr","Maghrib","Isha"]:["Dag","Dato","Fajr","Dhuhr","Asr","Maghreb","Isha"];let p=0;const y=m.map(b=>{const x=b.date.getUTCDay(),j=[];x===0?(j.push("sunday"),p=0):(p%2===1&&j.push("tint"),p++),b.closed?j.push("closed"):b.jumuah&&j.push("friday");const A="<th scope='row'>"+l[x]+"</th><td class='date'>"+b.date.getUTCDate()+".</td>";let M;if(b.closed)M="<td></td><td></td><td></td><td></td><td></td>";else{const k=S=>"<td>"+(S==null?"":w(S))+"</td>",C=b.dhuhr!=null?k(b.dhuhr):b.jumuah?"<td class='jummah'>"+n(e.settings.jumuahLabel)+"</td>":"<td></td>";M=k(b.fajr)+C+k(b.asr)+k(b.maghrib)+k(b.isha)}return"<tr"+(j.length?" class='"+j.join(" ")+"'":"")+">"+A+M+"</tr>"}).join(""),c=m.length<20?" short":"",f=m[0].date,g=t.title||(s?"Prayer times":"Bønnetider"),u=i[f.getUTCMonth()]+" "+f.getUTCFullYear();return _e(t)+He(g,u,t)+"<div class='tablewrap"+c+"'><table class='times"+c+"'><colgroup><col style='width:19%'><col style='width:11%'><col style='width:14%'><col style='width:14%'><col style='width:14%'><col style='width:14%'><col style='width:14%'></colgroup><thead><tr>"+d.map((b,x)=>"<th scope='col'"+(x===0?" class='h-day'":"")+">"+b+"</th>").join("")+"</tr></thead><tbody>"+y+"</tbody></table></div>"+Ie(t)+"</div>"}function Yt(e,a){const t=a.lang==="en",s=t?se.map(c=>c.slice(0,3)+"."):ye,n=c=>c.getUTCDate()+". "+s[c.getUTCMonth()],l=[];for(const c of e.periods){if(!c.open.length)continue;const f=e.dayPlans.find(x=>x.period===c&&x.fajr!=null),g=f?f.fajr:null,u=[g,c.dhuhr.time,c.asr.time,c.isha.time].join("|"),b=l[l.length-1];b&&b.sig===u?b.to=c.open[c.open.length-1].date:l.push({sig:u,fajr:g,dhuhr:c.dhuhr.time,asr:c.asr.time,isha:c.isha.time,from:c.open[0].date,to:c.open[c.open.length-1].date})}const i=t?["Period","Fajr","Dhuhr","Asr","Maghrib","Isha"]:["Periode","Fajr","Dhuhr","Asr","Maghreb","Isha"],m="+"+e.settings.maghribOffsetMin+" min",d=l.map((c,f)=>{const g=u=>
147"<td>"+(u==null?"":w(u))+"</td>";return"<tr"+(f%2?" class='tint'":"")+"><th scope='row'>"+n(c.from)+" â "+n(c.to)+"</th><td class='date'></td>"+g(c.fajr)+g(c.dhuhr)+g(c.asr)+"<td>"+m+"</td>"+g(c.isha)+"</tr>"}).join(""),p=a.title||(t?"Prayer times":"Bønnetider"),y=t?"Maghrib is held "+e.settings.maghribOffsetMin+" minutes after sunset and moves every day":"Maghreb holdes "+e.settings.maghribOffsetMin+" minutter etter solnedgang og flytter seg hver dag";return _e(a)+He(p,re(e),Object.assign({},a,{notice:a.notice||y}))+"<div class='tablewrap short'><table class='times short'><colgroup><col style='width:30%'><col style='width:0'><col style='width:14%'><col style='width:14%'><col style='width:14%'><col style='width:14%'><col style='width:14%'></colgroup><thead><tr><th scope='col' class='h-day'>"+i[0]+"</th><th scope='col'></th>"+i.slice(1).map(c=>"<th scope='col'>"+c+"</th>").join("")+"</tr></thead><tbody>"+d+"</tbody></table></div>"+Ie(a)+"</div>"}function $t(e,a){if(a.type==="periods")return Yt(e,a);const t=oe(e);return(a.month==="all"?t.map(n=>n.key):[a.month]).map(n=>zt(e,n,a)).join("")}function pe(e,a){const t=oe(e).find(n=>n.key===a.month);return a.type==="periods"||a.month==="all"||!t?"Bønnetabell "+re(e):"Bønnetabell "+(a.lang==="en"?se:q)[t.m].replace(/^./,n=>n.toUpperCase())}function Gt(e,a){return`<!DOCTYPE html> 148<html lang="`+(a.lang==="en"?"en":"nb")+'"><head><meta charset="utf-8"><title>'+X(pe(e,a))+"</title><style>@page{size:A4 portrait;margin:0}html,body{margin:0;padding:0;background:#DDE1E0}body{-webkit-print-color-adjust:exact;print-color-adjust:exact}@media print{html,body{background:#fff}}"+Ht+"</style></head><body>"+$t(e,a)+"</body></html>"}function Jt(e,{month:a="all",lang:t="no"}={}){return{type:e.posterType||"month",month:a,title:e.posterTitle,marginMm:e.posterMarginMm,notice:e.posterNotice,location:e.posterLocation,jumTitle:e.posterJumTitle,jumWho:e.posterJumWho,jumSummer:e.posterJumSummer,jumWinter:e.posterJumWinter,appLead:e.posterAppLead,appBody:e.posterAppBody,qrCaption:e.posterQrCaption,contact:e.posterContact,lang:t}}const de=794,qt=1123,Vt=30,V={fontSize:"var(--c-micro)",letterSpacing:".08em",color:"var(--c-faint)"},Kt=[["posterNotice","Notice at the top"],["posterJumTitle","Friday prayer, name"],["posterJumWho","Who it is for"],["posterJumSummer","Summer time"],["posterJumWinter","Winter time"],["posterLocation","Where you pray"],["posterAppLead","App, small heading"],["posterAppBody","App, text"],["posterQrCaption","Text under the QR"],["posterContact","Line under the bar"]],Qt=e=>e.replace(/^./,a=>a.toUpperCase());function Xt({result:e,settings:a,onSettings:t}){const s=D.useMemo(()=>oe(e),[e]),n=new Date,l=`${n.getUTCFullYear()}-${String(n.getUTCMonth()+1).padStart(2,"0")}`,[i,m]=D.useState(()=>{var M;return s.some(k=>k.key===l)?l:((M=s[0])==null?void 0:M.key)||"all"});D.useEffect(()=>{var M;i!=="all"&&!s.some(k=>k.key===i)&&m(((M=s[0])==null?void 0:M.key)||"all")},[s,i]);const d=D.useMemo(()=>Jt(a,{month:i}),[a,i]),p=D.useMemo(()=>Gt(e,d),[e,d]),y=d.type==="periods"?1:i==="all"?s.length:1,c=D.useRef(null),f=D.useRef(null),[g,u]=D.use
148State(1),[b,x]=D.useState(0);D.useEffect(()=>{const M=c.current;if(!M)return;const k=()=>{x(M.clientWidth),u(Math.min(1,M.clientWidth/de))};k();const C=new ResizeObserver(k);return C.observe(M),()=>C.disconnect()},[]);const j=()=>{var k;const M=(k=f.current)==null?void 0:k.contentWindow;M&&(M.focus(),M.print())},A=y*qt+(y-1)*Vt+24;return o.jsxs("div",{className:"space-y-3",children:[o.jsxs("div",{className:"grid gap-3 sm:grid-cols-4",children:[o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:V,children:"Poster type"}),o.jsxs("select",{value:a.posterType||"month",onChange:M=>t({posterType:M.target.value}),className:"rounded-[4px] px-3",style:P,children:[o.jsx("option",{value:"month",children:"Month sheet, day by day"}),o.jsx("option",{value:"periods",children:"Overview, fixed times per period"})]})]}),o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:V,children:"Month"}),o.jsxs("select",{value:i,onChange:M=>m(M.target.value),disabled:d.type==="periods",className:"rounded-[4px] px-3",style:P,children:[o.jsx("option",{value:"all",children:"All months"}),s.map(M=>o.jsxs("option",{value:M.key,children:[Qt(q[M.m])," ",M.y]},M.key))]})]}),o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:V,children:"Heading"}),o.jsx("input",{value:a.posterTitle??"",onChange:M=>t({posterTitle:M.target.value}),className:"rounded-[4px] px-3",style:P})]}),o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:V,children:"Side margin (mm)"}),o.jsx("input",{type:"number",min:6,max:25,step:.2,value:a.posterMarginMm??11.6,onChange:M=>t({posterMarginMm:M.target.value===""?"":Number(M.target.value)}),className:"rounded-[4px] px-3",style:P})]})]}),o.jsx("p",{className:"font-serif",style:{fontSize:"var(--c-fine)",color:"var(--c-faint)"},children:"The heading gets the month and year added. 11.6 mm is the drawn margin; smaller means a bigger table, and most office printers cannot print the outermost 5 mm."}),o.jsxs(Fe,{title:"Text on the poster",children:[o.jsx("div",{className:"grid gap-4 sm:grid-cols-2",children:Kt.map(([M,k])=>o.jsxs("label",{className:`flex flex-col gap-1.5 ${["posterNotice","posterAppBody","posterContact","posterLocation"].includes(M)?"sm:col-span-2":""}`,children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:V,children:k}),o.jsx("input",{value:a[M]??"",onChange:C=>t({[M]:C.target.value}),className:"rounded-[4px] px-3",style:P})]},M))}),o.jsx("p",{className:"font-serif mt-3",style:{fontSize:"var(--c-fine)",color:"var(--c-faint)"},children:"Leave a field empty to drop it from the poster. Wrap words in **two asterisks** to set them bold. The poster is in Norwegian because the students reading it on the door are."})]}),o.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[o.jsx(H,{tone:"primary",onClick:j,children:"Print / Save as PDF"}),o.jsxs("span",{className:"font-serif",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:["Saves as â",pe(e,d),".pdfâ. A4, one sheet per month."]})]}),o.jsx("div",{ref:c,className:"w-full overflow-hidden rounded-[6px]",style:{background:"var(--c-sunk)",border:"1px solid var(--c-line)",height:A*g},children:o.jsx("iframe",{ref:f,title:pe(e,d),srcDoc:p,style:{width:de,height:A,border:0,transform:`scale(${g})`,transformOrigin:"0 0",display:"block",background:"transparent",marginLeft:Math.max(0,(b-de*g)/2)}})})]})}const te={fontSize:"var(--c-micro)",letterSpacing:".08em",color:"var(--c-faint)"},Zt=e=>e.replace(/^./,a=>a.toUpperCase());function ea({result:e,settings:a,onSettings:t}){const s=D.useMemo(()=>oe(e),[e]),n=new Date,l=`${n.getUTCFullYear()}-${String(n.getUTCMonth()+1).padStart(2,"0")}`,[i,m]=D.useState(()=>{var f;return s.some(g=>g.key===l)?l:((f=s[0])==null?void 0:f.key)||"all"});D.useEffect(()=>{var f;i!=="all"&&!s.some(g=>g.key===i)&&m(((f=s[0])==null?void 0:f.key)||"all")},[s,i]);const[d,p]=D.useState(!1),y=D.useMemo(()=>Ft(e,{month:i,greeting:a.bookingGreeting,signoff:a.bookingSignoff}),[e,i,a.bookingGreeting,a.bookingSignoff]),c=async()=>{try{await navigator.clipboard.writeText(y),p(!0),setTimeout(()=>p(!1),1600)}catch{}};return o.jsxs("div",{className:"space-y-3",children:[o.jsxs("div",{className:"grid gap-3 sm:grid-cols-3",children:[o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:te,children:"Month"}),o.jsxs("select",{value:i,onChange:f=>m(f.target.value),className:"rounded-[4px] px-3",style:P,children:[o.jsx("option",{value:"all",children:"All months"}),s.map(f=>o.jsxs("option",{value:f.key,children:[Zt(q[f.m])," ",f.y]},f.key))]})]}),o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:te,children:"Greeting"}),o.jsx("input",{value:a.bookingGreeting??"",onChange:f=>t({bookingGreeting:f.target.value}),className:"rounded-[4px] px-3",style:P})]}),o.jsxs("label",{className:"flex flex-col gap-1.5",children:[o.jsx("span",{className:"font-display font-semibold uppercase",style:te,children:"Sign-off"}),o.jsx("textarea",{rows:2,value:a.bookingSignoff??"",onChange:f=>t({bookingSignoff:f.target.value}),className:"rounded-[4px] px-3 py-2 font-serif",style:P})]})]}),o.jsxs("div",{className:"flex items-center gap-3",children:[o.jsx(H,{tone:"primary",onClick:c,children:d?"Copied":"Copy the message"}),o.jsx("span",{className:"font-serif",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:"Paste it straight into the e-mail to UiO. The times are the room slots, separate from the jamaah."})]}),o.jsx("pre",{className:"rounded-[6px] p-3 overflow-auto tnum",style:{fontSize:"12.5px",lineHeight:1.55,background:"var(--c-sunk)",border:"1px solid var(--c-line)",maxHeight:480,whiteSpace:"pre"},children:y}),o.jsx("div",{className:"overflow-x-auto rounded-[6px]",style:{border:"1px solid var(--c-line)"},children:o.jsxs("table",{className:"w-full font-serif",style:{fontSize:"var(--c-label)",whiteSpace:"nowrap"},children:[o.jsx("thead",{children:o.jsx("tr",{style:{color:"var(--c-faint)"},children:["Prayer","From","To","Weekdays","Book from","Book to","Min","Jamaah","Weeks"].map(f=>o.jsx("th",{className:"text-left px-3 py-2 font-display font-semibold uppercase",style:te,children:f},f))})}),o.jsx("tbody",{children:e.bookings.map((f,g)=>o.jsxs("tr",{style:{borderTop:"1px solid var(--c-line-soft)"},children:[o.jsx("td",{className:"px-3 py-1.5",children:f.prayer}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:L(f.from)}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:L(f.to)}),o.jsx("td",{className:"px-3 py-1.5",children:we(f.dows,be)}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:w(f.start)}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:w(f.end)}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:f.end-f.start}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:o.jsx("b",{children:w(f.time)}
148)}),o.jsx("td",{className:"px-3 py-1.5 tnum",children:f.weeks||""})]},g))})]})})]})}const ta={fontSize:"var(--c-micro)",letterSpacing:".08em",color:"var(--c-faint)"};function K({jam:e,base:a}){if(e==null)return o.jsx("td",{className:"px-3 py-1.5 tnum",style:{color:"var(--c-faint)"},children:"â"});const t=a==null?null:e-a;return o.jsxs("td",{className:"px-3 py-1.5 tnum",children:[w(e),t!=null&&o.jsxs("span",{style:{color:"var(--c-faint)"},children:[" +",t]})]})}function aa({result:e}){return o.jsx("div",{className:"overflow-auto rounded-[6px]",style:{border:"1px solid var(--c-line)",maxHeight:560},children:o.jsxs("table",{className:"w-full font-serif",style:{fontSize:"var(--c-label)",whiteSpace:"nowrap"},children:[o.jsx("thead",{children:o.jsx("tr",{style:{color:"var(--c-faint)",position:"sticky",top:0,background:"var(--c-panel)"},children:["Date","Day","Fajr","Dhuhr","Asr","Maghrib","Isha"].map(a=>o.jsx("th",{className:"text-left px-3 py-2 font-display font-semibold uppercase",style:ta,children:a},a))})}),o.jsx("tbody",{children:e.dayPlans.map(a=>{const t=be[a.date.getUTCDay()];return a.closed?o.jsxs("tr",{style:{borderTop:"1px solid var(--c-line-soft)",color:"var(--c-faint)",fontStyle:"italic"},children:[o.jsx("td",{className:"px-3 py-1.5 tnum",children:L(a.date)}),o.jsx("td",{className:"px-3 py-1.5",children:t}),o.jsx("td",{className:"px-3 py-1.5",colSpan:5,children:a.closedName?a.closedName.en:"closed"})]},L(a.date)):o.jsxs("tr",{style:{borderTop:"1px solid var(--c-line-soft)"},children:[o.jsx("td",{className:"px-3 py-1.5 tnum",children:L(a.date)}),o.jsx("td",{className:"px-3 py-1.5",children:t}),o.jsx(K,{jam:a.fajr,base:a.row.fajr}),a.jumuah&&a.dhuhr==null?o.jsx("td",{className:"px-3 py-1.5",style:{fontStyle:"italic"},children:e.settings.jumuahLabel}):o.jsx(K,{jam:a.dhuhr,base:a.row.dhuhr}),o.jsx(K,{jam:a.asr,base:a.asrBase}),o.jsx(K,{jam:a.maghrib,base:a.row.maghrib}),o.jsx(K,{jam:a.isha,base:a.row.isha})]},L(a.date))})})]})})}const na=[{id:"poster",label:"Poster"},{id:"mail",label:"Booking e-mail"},{id:"week",label:"Weekly plan"},{id:"days",label:"Daily times"},{id:"checks",label:"Checks"},{id:"file",label:"File"}],ce=(e,a)=>{let t=0,s=null;return e.periods.forEach(n=>{const l=n[a]?n[a].time:null;l!=null&&l!==s&&t++,s=l}),t},Ee={error:"danger",warn:"warn",info:"neutral"};function sa({result:e}){const a={error:0,warn:1,info:2},t=[...e.issues].sort((s,n)=>a[s.level]-a[n.level]);return o.jsxs("div",{className:"space-y-2",children:[o.jsxs("p",{className:"font-serif",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:["All ",e.checked," generated times were checked against the file: after the adhan, before the next prayer."]}
148),t.length===0&&o.jsx(ge,{children:"Nothing to report."}),t.map((s,n)=>o.jsx("div",{className:"rounded-[6px] px-3 py-2 font-serif",style:{fontSize:"var(--c-label)",background:`var(--c-${Ee[s.level]}-soft, var(--c-sunk))`,color:s.level==="info"?"var(--c-text)":`var(--c-${Ee[s.level]})`,border:"1px solid var(--c-line-soft)"},children:s.en||s.no},n))]})}const ra={date:"Date",fajr:"Fajr",sunrise:"Sunrise",dhuhr:"Dhuhr",asrShafi:"Asr Shafi (1Ã)",asrHanafi:"Asr Hanafi (2Ã)",maghrib:"Maghrib",isha:"Isha"};function oa({source:e,result:a}){return o.jsxs("div",{children:[o.jsxs("table",{className:"w-full font-serif",style:{fontSize:"var(--c-label)"},children:[o.jsx("thead",{children:o.jsxs("tr",{style:{color:"var(--c-faint)"},children:[o.jsx("th",{className:"text-left py-1",children:"Field"}),o.jsx("th",{className:"text-left py-1",children:"Column in the file"})]})}),o.jsx("tbody",{children:Object.entries(ra).map(([t,s])=>o.jsxs("tr",{style:{borderTop:"1px solid var(--c-line-soft)"},children:[o.jsx("td",{className:"py-1.5 pr-4",children:s}),o.jsx("td",{className:"py-1.5 tnum",children:e.usedHeader[t]||o.jsx("span",{style:{color:"var(--c-faint)"},children:"not found"})})]},t))})]}),o.jsxs("p",{className:"font-serif mt-3",style:{fontSize:"var(--c-label)",color:"var(--c-muted)"},children:["Delimiter: ",o.jsx("code",{children:e.delim===" "?"TAB":e.delim}),". Asr basis in use:"," ",a.settings.asrBasis==="hanafi"?"Hanafi (2Ã)":"Shafi (1Ã)","."]})]})}function ia({result:e,source:a,settings:t,onSettings:s}){const[n,l]=D.useState("poster"),i=e.issues.filter(c=>c.level==="warn").length,m=e.issues.filter(c=>c.level==="error").length,d=re(e),p=e.dayPlans.filter(c=>!c.closed).length,y=e.dayPlans.length===0;return o.jsxs("div",{className:"space-y-4",children:[o.jsxs("div",{className:"grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-2",children:[o.jsx(G,{n:p,label:"open days"}),o.jsx(G,{n:e.closedInRange,label:"days off"}),o.jsx(G,{n:e.bookings.length,label:"bookings"}),o.jsx(G,{n:`${ce(e,"dhuhr")}/${ce(e,"asr")}/${ce(e,"isha")}`,label:"changes D/A/I"}),o.jsx(G,{n:i,label:"warnings",tone:i?"warn":"neutral"}),o.jsx(G,{n:m,label:"errors",tone:m?"danger":"neutral"})]}),y?o.jsx(ge,{children:"No days in this range. Check From date and To date under General, and the Checks view for the reason."}):o.jsxs(o.Fragment,{children:[o.jsxs("div",{className:"flex flex-wrap gap-2",children:[o.jsxs(H,{onClick:()=>ee(`Jamaat-tider_${d}.csv`,Ot(e)),children:["Jamaat-tider_",d,".csv"]}),o.jsxs(H,{onClick:()=>ee(`Rombooking_${d}.csv`,Lt(e)),children:["Rombooking_",d,".csv"]}),o.jsxs(H,{onClick:()=>ee(`iBonn_${d}.csv`,Bt(e),{bom:!1}),children:["iBonn_",d,".csv"]}),o.jsxs(H,{onClick:()=>ee(`Ukeoversikt_${d}.txt`,Ae(e)),children:["Ukeoversikt_",d,".txt"]})]}),o.jsxs("p",{className:"font-serif",style:{fontSize:"var(--c-fine)",color:"var(--c-faint)"},children:["iBønn reads only the offsets in this file and adds them to its own prayer times."," ",{clock:o.jsx(o.Fragment,{children:"Asr counts from Standard (1Ã) in summer time and Hanafi (2Ã) in winter time, which is what iBønn has done for MSS whatever its admin panel says."}),shafi:o.jsx(o.Fragment,{children:"Asr counts from Standard (1Ã) all year, so if iBønn uses Hanafi in winter, as it has, the winter Asr jamaah lands late."}),hanafi:o.jsx(o.Fragment,{children:"Asr counts from Hanafi (2Ã) all year, so if iBønn uses Standard in summer, as it has, the summer Asr jamaah lands up to an hour early."})}[e.settings.ibonnAsrBasis]," ","Change it under Output files."]}),o.jsx(Je,{options:na,value:n,onChange:l,label:"View"}),n==="poster"&&o.jsx(Xt,{result:e,settings:t,onSettings:s}),n==="mail"&&o.jsx(ea,{result:e,settings:t,onSettings:s}),n==="week"&&o.jsx("pre",{className:"rounded-[6px] p-3 overflow-auto tnum",style:{fontSize:"12.5px",lineHeight:1.55,background:"var(--c-sunk)",border:"1px solid var(--c-line)",maxHeight:560},children:Ae(e)}),n==="days"&&o.jsx(aa,{result:e}),n==="checks"&&o.jsx(sa,{result:e}),n==="file"&&o.jsx(oa,{source:a,result:e})]})]})}const la={rangeFrom:"",rangeTo:"",closedMonths:[7],closedWeekdays:[0],autoNorwegianHolidays:!1,closedDatesText:"",earliestAllowed:"07:00",latestAllowed:"22:00",latestDayPrayer:"19:30",roundTo:5,slotLeadMin:5,slotLengthMin:30,slotPhaseMin:0,stability:"preferred",fajrEnabled:!0,fajrFixed:"08:10",fajrMinSunrise:"08:30",dhuhrEnabled:!0,dhuhrPreferred:"11:05, 12:05, 13:05, 14:05, 15:05, 12:15, 12:25",dhuhrGapToAsrMin:15,dhuhrMaxWaitMin:90,freeAfter:"16:00",noDhuhrWeekdays:[5],jumuahEnabled:!1,jumuahTime:"13:00",jumuahLabel:"Jummuah",asrEnabled:!0,asrBasis:"hanafi",asrStability:"earliest-free",asrPreferred:"09:05, 10:05, 11:05, 12:05, 13:05, 14:05, 15:05",asrGapToMaghribMin:20,asrMaxWaitMin:90,asrStepMin:15,maghribEnabled:!0,maghribOffsetMin:3,ish
148aEnabled:!0,ishaRoundTo:15,ishaMaxWaitMin:30,ibonnDateFormat:"dd-MM",ibonnAsrBasis:"clock"},ha={bookingGreeting:"Hei",bookingSignoff:`Mvh, 149Muslimsk Studentsamfunn`},da={posterType:"month",posterMarginMm:11.6,posterTitle:"Bønnetider",posterNotice:"**NB!** Tidene under er nÃ¥r vi ber i jamaah, ikke nÃ¥r bønnetiden gÃ¥r inn.",posterJumTitle:"Jummuah",posterJumWho:"menn & kvinner",posterJumSummer:"kl. 13:30â14:00",posterJumWinter:"kl. 12:40â13:10",posterLocation:"Vi ber i Frederikke Gymsal",posterAppLead:"FÃ¥ tidene pÃ¥ mobilen",posterAppBody:"Bønnetidene finnes ogsÃ¥ i appen **iBønn** â velg «Muslimsk Studentsamfunn»",posterQrCaption:"ibønn.no",posterContact:"Følg oss pÃ¥ Instagram/Facebook **@muslimskstudent**"},fe={...la,...ha,...da},ca=e=>{const a=We(e.source_text);return{name:e.source_name,text:e.source_text,...a,year:e.year,saved:!0}};function Sa(){Re("Prayer times","The month's jamaah times, the poster and the room bookings.",{noindex:!0});const[e,a]=D.useState([]),[t,s]=D.useState(!0),[n,l]=D.useState(null),[i,m]=D.useState(null),[d,p]=D.useState(fe),[y,c]=D.useState(!1),[f,g]=D.useState(!1),[u,b]=D.useState(null),x=D.useCallback(async S=>{l(null);try{const E=await Ve(S);m(ca(E)),p({...fe,...E.settings||{}}),c(!1)}catch(E){l(E.message)}},[]);D.useEffect(()=>{let S=!1;return(async()=>{try{const E=await Ke();if(S)return;a(E),E.length&&await x(E[0].year)}catch(E){S||l(E.message)}finally{S||s(!1)}})(),()=>{S=!0}},[x]);const j=S=>{m(S),c(!0),b(null)},A=S=>{p(E=>({...E,...S})),c(!0)},M=()=>{p(fe),c(!0)},k=async()=>{if(i){g(!0),b(null);try{const S=await Qe({year:i.year,sourceName:i.name,sourceText:i.text,settings:d});m(E=>({...E,saved:!0,name:S.source_name})),c(!1),a(E=>{const r=E.filter(h=>h.year!==S.year);return[{year:S.year,source_name:S.source_name,updated_at:S.updated_at},...r].sort((h,v)=>v.year-h.year)})}catch(S){b(S.message)}finally{g(!1)}}},C=D.useMemo(()=>{if(!i)return null;const S=Ct(i.rows,d);return S.issues=i.issues.concat(S.issues),S},[i,d]);return o.jsx(ze,{maxWidth:1100,title:"Prayer times",subtitle:"The year's file in, the poster and the room bookings out",children:o.jsxs("div",{className:"space-y-4",children:[t?o.jsx(qe,{label:"Looking for a saved yearâ¦"}):o.jsx(pt,{years:e,source:i,saving:f,dirty:y,onFile:j,onPick:x,onSave:k}),n&&o.jsxs(me,{children:["Could not read the saved years (",n,"). Drop this yearâs file to work without them."]}),u&&o.jsx(me,{children:u}),i&&o.jsxs(o.Fragment,{children:[o.jsx(kt,{settings:d,onChange:A,onReset:M,year:i.year}),C&&o.jsx(ia,{result:C,source:i,settings:d,onSettings:A})]}),!t&&!i&&o.jsx(ge,{children:"No year yet. Drop the file from Islamsk RÃ¥d Norge above and the tables appear."})]})})}export{Sa as default};
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.