|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>π« Herbstferien 2026 β Ferienkurse Planner</title> |
|
<style> |
|
:root { |
|
--ale: #4A90D9; |
|
--seba: #E67E22; |
|
--both: #27AE60; |
|
--bg: #f5f5f5; |
|
--card: #fff; |
|
--shadow: 0 2px 8px rgba(0,0,0,0.08); |
|
} |
|
* { box-sizing: border-box; margin: 0; padding: 0; } |
|
body { |
|
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; |
|
background: var(--bg); color: #333; padding: 16px; |
|
max-width: 1400px; margin: 0 auto; |
|
} |
|
h1 { font-size: 1.5em; margin-bottom: 4px; } |
|
.subtitle { color: #666; margin-bottom: 12px; font-size: 0.9em; } |
|
.stats-bar { |
|
display: flex; gap: 16px; flex-wrap: wrap; |
|
background: var(--card); border-radius: 12px; padding: 12px 20px; |
|
box-shadow: var(--shadow); margin-bottom: 12px; align-items: center; |
|
} |
|
.stat { text-align: center; min-width: 80px; } |
|
.stat .num { font-size: 1.8em; font-weight: 700; } |
|
.stat .label { font-size: 0.7em; color: #888; text-transform: uppercase; } |
|
.stat.ale .num { color: var(--ale); } |
|
.stat.seba .num { color: var(--seba); } |
|
.stat.free .num { color: var(--both); } |
|
.legend { display: flex; gap: 10px; margin-left: auto; font-size: 0.8em; align-items: center; } |
|
.legend-dot { width: 12px; height: 12px; border-radius: 50%; display: inline-block; margin-right: 3px; vertical-align: middle; } |
|
.deadline-banner { |
|
background: #fff3e0; border: 2px solid #ff9800; border-radius: 8px; |
|
padding: 10px 16px; margin-bottom: 12px; font-size: 0.85em; |
|
} |
|
.deadline-banner strong { color: #e65100; } |
|
.week-tabs { display: flex; gap: 8px; margin-bottom: 12px; } |
|
.week-tab { |
|
padding: 8px 20px; border-radius: 8px; cursor: pointer; |
|
background: var(--card); border: 2px solid #ddd; font-weight: 600; font-size: 0.9em; |
|
transition: all 0.2s; user-select: none; |
|
} |
|
.week-tab.active { border-color: var(--both); background: #e8f5e9; } |
|
.week-tab:hover { border-color: #999; } |
|
.main-grid { display: grid; grid-template-columns: 280px 1fr; gap: 12px; } |
|
@media (max-width: 900px) { .main-grid { grid-template-columns: 1fr; } } |
|
.activities-panel { |
|
background: var(--card); border-radius: 12px; padding: 12px; |
|
box-shadow: var(--shadow); max-height: 75vh; overflow-y: auto; |
|
} |
|
.activities-panel h3 { margin-bottom: 8px; font-size: 0.95em; } |
|
.section-label { |
|
font-size: 0.75em; font-weight: 700; color: #888; |
|
text-transform: uppercase; margin: 10px 0 4px; letter-spacing: 0.5px; |
|
border-bottom: 1px solid #eee; padding-bottom: 3px; |
|
} |
|
.activity-card { |
|
border: 2px solid #eee; border-radius: 8px; padding: 8px 10px; |
|
margin-bottom: 6px; cursor: pointer; transition: all 0.15s; |
|
position: relative; user-select: none; |
|
} |
|
.activity-card:hover { border-color: #bbb; transform: translateX(2px); } |
|
.activity-card.active.ale-only { border-color: var(--ale); background: #e8f0fa; } |
|
.activity-card.active.seba-only { border-color: var(--seba); background: #fdf0e4; } |
|
.activity-card.active.both-kids { border-color: var(--both); background: #e8f5e9; } |
|
.activity-card .name { font-weight: 700; font-size: 0.85em; } |
|
.activity-card .meta { font-size: 0.7em; color: #888; margin-top: 2px; } |
|
.badge { |
|
display: inline-block; padding: 1px 5px; border-radius: 3px; |
|
font-size: 0.65em; font-weight: 600; color: #fff; margin-right: 3px; |
|
} |
|
.badge.ale { background: var(--ale); } |
|
.badge.seba { background: var(--seba); } |
|
.badge.both { background: var(--both); } |
|
.badge.avail-green { background: #27ae60; } |
|
.badge.avail-yellow { background: #f39c12; } |
|
.badge.avail-red { background: #e74c3c; } |
|
.activity-card .link { |
|
position: absolute; top: 6px; right: 8px; font-size: 0.75em; |
|
color: #4A90D9; text-decoration: none; |
|
} |
|
.activity-card .link:hover { text-decoration: underline; } |
|
.calendar-panel { |
|
background: var(--card); border-radius: 12px; padding: 12px; |
|
box-shadow: var(--shadow); overflow-x: auto; |
|
} |
|
.cal-grid { |
|
display: grid; grid-template-columns: 50px repeat(5, 1fr); |
|
gap: 1px; min-width: 500px; |
|
} |
|
.cal-header { |
|
text-align: center; font-weight: 700; font-size: 0.8em; |
|
padding: 6px 2px; background: #f8f8f8; border-radius: 4px; |
|
} |
|
.cal-time { |
|
font-size: 0.65em; color: #aaa; text-align: right; padding-right: 4px; |
|
height: 24px; display: flex; align-items: center; justify-content: flex-end; |
|
} |
|
.cal-cell { height: 24px; position: relative; border-bottom: 1px solid #f8f8f8; } |
|
.cal-block { |
|
position: absolute; left: 1px; right: 1px; border-radius: 3px; |
|
font-size: 0.55em; color: #fff; padding: 1px 3px; |
|
overflow: hidden; white-space: nowrap; text-overflow: ellipsis; |
|
z-index: 2; cursor: pointer; font-weight: 600; |
|
display: flex; align-items: center; |
|
} |
|
.cal-block.ale { background: var(--ale); } |
|
.cal-block.seba { background: var(--seba); } |
|
.cal-block.both { background: var(--both); } |
|
.cal-block:hover { opacity: 0.85; filter: brightness(1.1); } |
|
.free-row { |
|
display: grid; grid-template-columns: 50px repeat(5, 1fr); |
|
gap: 1px; margin-top: 8px; padding-top: 8px; border-top: 2px dashed #ddd; |
|
min-width: 500px; |
|
} |
|
.free-cell { |
|
text-align: center; font-size: 0.75em; padding: 5px; |
|
border-radius: 4px; font-weight: 700; |
|
} |
|
.free-cell.good { background: #e8f5e9; color: #27ae60; } |
|
.free-cell.ok { background: #fff8e1; color: #f57f17; } |
|
.free-cell.bad { background: #fce4ec; color: #c62828; } |
|
.conflict-warn { |
|
background: #fce4ec; border: 1px solid #e57373; border-radius: 6px; |
|
padding: 6px 12px; margin-bottom: 8px; font-size: 0.8em; color: #c62828; |
|
display: none; |
|
} |
|
.conflict-warn.show { display: block; } |
|
</style> |
|
</head> |
|
<body> |
|
<h1>π« Herbstferien 2026 β Ferienkurse Planner</h1> |
|
<p class="subtitle">π TΓΆdistrasse 27, 8002 ZΓΌrich | π§ Ale (2018) π¦ Seba (2020) | Click activities to toggle on/off</p> |
|
<div class="deadline-banner"> |
|
β οΈ <strong>Week 1 deadline: 29 Sep 2026</strong> (2 weeks!) | Week 2 deadline: 6 Oct 2026 | |
|
<a href="https://www.stadt-zuerich.ch/sport-portal/angebot/ferienkurse" target="_blank">π Stadt ZΓΌrich Portal</a> |
|
</div> |
|
<div class="stats-bar"> |
|
<div class="stat ale"><div class="num" id="stat-ale">0h</div><div class="label">π§ Ale covered</div></div> |
|
<div class="stat seba"><div class="num" id="stat-seba">0h</div><div class="label">π¦ Seba covered</div></div> |
|
<div class="stat free"><div class="num" id="stat-free">0h</div><div class="label">β Both out (2 wks)</div></div> |
|
<div class="legend"> |
|
<span><span class="legend-dot" style="background:var(--ale)"></span>Ale</span> |
|
<span><span class="legend-dot" style="background:var(--seba)"></span>Seba</span> |
|
<span><span class="legend-dot" style="background:var(--both)"></span>Both</span> |
|
</div> |
|
</div> |
|
<div class="conflict-warn" id="conflict-warn">β οΈ Schedule conflict detected!</div> |
|
<div class="week-tabs"> |
|
<div class="week-tab active" onclick="showWeek(1)">π
Week 1 β Oct 5β9</div> |
|
<div class="week-tab" onclick="showWeek(2)">π
Week 2 β Oct 12β16</div> |
|
</div> |
|
<div class="main-grid"> |
|
<div class="activities-panel" id="activities-panel"></div> |
|
<div class="calendar-panel"> |
|
<div class="cal-grid" id="cal-grid"></div> |
|
<div class="free-row" id="free-row"></div> |
|
</div> |
|
</div> |
|
<script> |
|
const BASE_URL='https://www.stadt-zuerich.ch/sport-portal/angebot/ferienkurse'; |
|
const COURSES=[ |
|
{id:'FRO11',name:'Robotics π€ (AM)',code:'FRO 11',week:1,days:[0,1,2,3,4],start:8.5,end:12,kid:'seba',loc:'Tekmania',dist:'500m π’',avail:'green',availText:'Many spots',age:'2019β2021'}, |
|
{id:'FRO12',name:'Robotics π€ (PM)',code:'FRO 12',week:1,days:[0,1,2,3,4],start:13,end:16.5,kid:'seba',loc:'Tekmania',dist:'500m π’',avail:'green',availText:'Many spots',age:'2019β2021'}, |
|
{id:'AKCL11',name:'Acrobatics & Clowning π€Έ',code:'AKCL 11',week:1,days:[0,1,2,3,4],start:10,end:15,kid:'both',loc:'Gabler',dist:'600m π’',avail:'yellow',availText:'Waitlist',age:'2017β2020'}, |
|
{id:'MICA11',name:'Mini Basketball π',code:'MICA 11',week:1,days:[0,1,2,3,4],start:9.5,end:15.5,kid:'both',loc:'Falletsche',dist:'4km π ',avail:'green',availText:'Many spots',age:'2013β2020'}, |
|
{id:'TEUE11',name:'Tennis Uetliberg πΎ',code:'TEUE 11',week:1,days:[0,1,2,3,4],start:9.75,end:16.5,kid:'both',loc:'TC Uetliberg',dist:'5km π΄',avail:'yellow',availText:'Waitlist',age:'2014β2020'}, |
|
{id:'BASC11',name:'Basketball π',code:'BASC 11',week:1,days:[0,1,2,3,4],start:9,end:16,kid:'ale',loc:'RebhΓΌgel',dist:'3km π ',avail:'green',availText:'Many spots',age:'2010β2019'}, |
|
{id:'CACA11',name:'Capoeira π₯',code:'CACA 11',week:1,days:[0,1,2,3,4],start:9,end:16,kid:'ale',loc:'Entlisberg',dist:'2.5km π ',avail:'green',availText:'Many spots',age:'2014β2019'}, |
|
{id:'FDB11',name:'Printing & Crafting π¨',code:'FDB 11',week:1,days:[0,1,2,3,4],start:9,end:15,kid:'ale',loc:'Rote Fabrik',dist:'2km π‘',avail:'yellow',availText:'Few spots',age:'2016β2019'}, |
|
{id:'SUP11',name:'SUP & Kayak π',code:'SUP 11',week:1,days:[0,1,2,3,4],start:8.5,end:11.5,kid:'ale',loc:'Mythenquai',dist:'900m π’',avail:'green',availText:'Many spots',age:'2015β2019'}, |
|
{id:'TACA11',name:'Dance Camp π',code:'TACA 11',week:1,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'TANZ-FABRIK',dist:'1km π‘',avail:'green',availText:'Many spots',age:'2015β2019'}, |
|
{id:'TEBE11',name:'Tennis Belvoir πΎ',code:'TEBE 11',week:1,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'TC Belvoir',dist:'800m π’',avail:'yellow',availText:'Waitlist',age:'2014β2018'}, |
|
{id:'RECA11',name:'Riding Camp π΄',code:'RECA 11',week:1,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'Kolbenhof',dist:'4.5km π΄',avail:'yellow',availText:'Waitlist',age:'2015β2018'}, |
|
{id:'FSC12',name:'SchΓΆflis π (Tue)',code:'FSC 12',week:1,days:[1],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'yellow',availText:'Waitlist',age:'2014β2020'}, |
|
{id:'FEN11',name:'Nature Heroes π¦ (Thu)',code:'FEN 11',week:1,days:[3],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'yellow',availText:'Few spots',age:'2014β2020'}, |
|
{id:'FWH11',name:'Dog Walking πβπ¦Ί (Mon)',code:'FWH 11',week:1,days:[0],start:13,end:17,kid:'ale',loc:'AlbisgΓΌtli',dist:'3.5km π ',avail:'yellow',availText:'Few spots',age:'2014β2018'}, |
|
{id:'FZH11',name:'Dog Expert π (Tue)',code:'FZH 11',week:1,days:[1],start:13,end:17,kid:'ale',loc:'AlbisgΓΌtli',dist:'3.5km π ',avail:'yellow',availText:'Waitlist',age:'2014β2018'}, |
|
{id:'FCO21',name:'Coding & Art π»π¨',code:'FCO 21',week:2,days:[0,1,2,3,4],start:9.5,end:16,kid:'both',loc:'Coding a Story',dist:'200m π’',avail:'yellow',availText:'Waitlist',age:'2014β2021'}, |
|
{id:'TEUE21',name:'Tennis Uetliberg πΎ',code:'TEUE 21',week:2,days:[0,1,2,3,4],start:9.75,end:16.5,kid:'both',loc:'TC Uetliberg',dist:'5km π΄',avail:'yellow',availText:'Waitlist',age:'2014β2020'}, |
|
{id:'TACA21',name:'Dance Camp π',code:'TACA 21',week:2,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'TANZ-FABRIK',dist:'1km π‘',avail:'green',availText:'Many spots',age:'2015β2019'}, |
|
{id:'TEBE21',name:'Tennis Belvoir πΎ',code:'TEBE 21',week:2,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'TC Belvoir',dist:'800m π’',avail:'yellow',availText:'Few spots',age:'2014β2018'}, |
|
{id:'BASC21',name:'Basketball π',code:'BASC 21',week:2,days:[0,1,2,3,4],start:9,end:16,kid:'ale',loc:'RebhΓΌgel',dist:'3km π ',avail:'green',availText:'Many spots',age:'2010β2019'}, |
|
{id:'GRDA21',name:'Creative Camp π€',code:'GRDA 21',week:2,days:[0,1,2,3,4],start:9,end:16,kid:'ale',loc:'GZ Heuried',dist:'1.5km π‘',avail:'green',availText:'Many spots',age:'2011β2018'}, |
|
{id:'VOCA21',name:'Vaulting Camp π΄',code:'VOCA 21',week:2,days:[0,1,2,3,4],start:10,end:16,kid:'ale',loc:'Kolbenhof',dist:'4.5km π΄',avail:'yellow',availText:'Waitlist',age:'2015β2018'}, |
|
{id:'BUD21',name:'Budo π₯',code:'BUD 21',week:2,days:[0,1,2,3,4],start:9,end:10.5,kid:'ale',loc:'Budokan',dist:'1.2km π‘',avail:'green',availText:'Many spots',age:'2012β2019'}, |
|
{id:'FAH21',name:'No Fear of Dogs πΆ (Tue)',code:'FAH 21',week:2,days:[1],start:13,end:17,kid:'both',loc:'AlbisgΓΌtli',dist:'3.5km π ',avail:'green',availText:'Many spots',age:'2016β2020'}, |
|
{id:'FTA21',name:'Animal Heroes π¦Έ (Wed)',code:'FTA 21',week:2,days:[2],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'green',availText:'Many spots',age:'2014β2020'}, |
|
{id:'FNS21',name:'SchΓΆflis π (Tue)',code:'FNS 21',week:2,days:[1],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'yellow',availText:'Waitlist',age:'2014β2020'}, |
|
{id:'FSC21',name:'SchΓΆflis π (Thu)',code:'FSC 21',week:2,days:[3],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'yellow',availText:'Waitlist',age:'2014β2020'}, |
|
{id:'FSC22',name:'SchΓΆflis π (Fri)',code:'FSC 22',week:2,days:[4],start:10,end:15,kid:'both',loc:'Mittelleimbach',dist:'5km π΄',avail:'green',availText:'Many spots',age:'2014β2020'}, |
|
{id:'FZH21',name:'Dog Expert π (Mon)',code:'FZH 21',week:2,days:[0],start:13,end:17,kid:'ale',loc:'AlbisgΓΌtli',dist:'3.5km π ',avail:'yellow',availText:'Waitlist',age:'2013β2018'}, |
|
{id:'FWH21',name:'Dog Walking πβπ¦Ί (Fri)',code:'FWH 21',week:2,days:[4],start:13,end:17,kid:'ale',loc:'AlbisgΓΌtli',dist:'3.5km π ',avail:'yellow',availText:'Waitlist',age:'2014β2018'}, |
|
]; |
|
const DAYS=['Mon','Tue','Wed','Thu','Fri']; |
|
const DATES={1:['Oct 5','Oct 6','Oct 7','Oct 8','Oct 9'],2:['Oct 12','Oct 13','Oct 14','Oct 15','Oct 16']}; |
|
const T0=8,T1=17; |
|
let curWeek=1,active=new Set(['FRO11','FRO12','CACA11','TACA21','FTA21','FSC22']); |
|
function showWeek(w){curWeek=w;document.querySelectorAll('.week-tab').forEach((t,i)=>t.classList.toggle('active',i===w-1));render();} |
|
function toggle(id){active.has(id)?active.delete(id):active.add(id);render();} |
|
function fmtT(t){const h=Math.floor(t),m=Math.round((t-h)*60);return h+':'+String(m).padStart(2,'0');} |
|
function render(){renderActs();renderCal();renderStats();} |
|
function renderActs(){ |
|
const p=document.getElementById('activities-panel'); |
|
const wc=COURSES.filter(c=>c.week===curWeek); |
|
const full=wc.filter(c=>c.days.length===5),single=wc.filter(c=>c.days.length<5); |
|
let h=`<h3>Week ${curWeek} Activities</h3>`; |
|
const sections=[['π« Both kids','both'],['π§ Ale only','ale'],['π¦ Seba only','seba']]; |
|
for(const[label,kid]of sections){ |
|
const items=[...full,...single].filter(c=>c.kid===kid); |
|
if(!items.length)continue; |
|
h+=`<div class="section-label">${label}</div>`; |
|
items.forEach(c=>{ |
|
const on=active.has(c.id); |
|
const dur=c.end-c.start,dh=Math.floor(dur),dm=Math.round((dur-dh)*60); |
|
const ds=dm>0?dh+'h'+dm+'m':dh+'h'; |
|
const ts=fmtT(c.start)+'β'+fmtT(c.end); |
|
const dayStr=c.days.length===5?'MonβFri':c.days.map(d=>DAYS[d]).join(', '); |
|
const kc=c.kid==='ale'?'ale-only':c.kid==='seba'?'seba-only':'both-kids'; |
|
h+=`<div class="activity-card ${on?'active':''} ${kc}" onclick="toggle('${c.id}')"> |
|
<a class="link" href="${BASE_URL}?q=${encodeURIComponent(c.code)}" target="_blank" onclick="event.stopPropagation()">π</a> |
|
<div class="name">${on?'β
':'β¬'} ${c.name}</div> |
|
<div class="meta"> |
|
<span class="badge ${c.kid}">${c.kid==='both'?'π« Both':c.kid==='ale'?'π§ Ale':'π¦ Seba'}</span> |
|
<span class="badge avail-${c.avail}">${c.availText}</span> |
|
${ds} Β· ${ts} Β· ${dayStr} |
|
</div> |
|
<div class="meta">π ${c.loc} (${c.dist}) Β· Ages ${c.age}</div> |
|
</div>`; |
|
}); |
|
} |
|
p.innerHTML=h; |
|
} |
|
function renderCal(){ |
|
const g=document.getElementById('cal-grid'); |
|
const slots=(T1-T0)*2,dates=DATES[curWeek]; |
|
let h='<div class="cal-header"></div>'; |
|
for(let d=0;d<5;d++)h+=`<div class="cal-header">${DAYS[d]}<br><span style="font-weight:400;font-size:0.75em">${dates[d]}</span></div>`; |
|
for(let s=0;s<slots;s++){ |
|
const t=T0+s*0.5; |
|
h+=s%2===0?`<div class="cal-time">${fmtT(t)}</div>`:`<div class="cal-time" style="color:#ddd">:30</div>`; |
|
for(let d=0;d<5;d++)h+=`<div class="cal-cell" data-d="${d}" data-s="${s}"></div>`; |
|
} |
|
g.innerHTML=h; |
|
const ac=COURSES.filter(c=>c.week===curWeek&&active.has(c.id)); |
|
// Check conflicts per kid per day |
|
let hasConflict=false; |
|
ac.forEach(c=>{ |
|
c.days.forEach(d=>{ |
|
const ss=Math.round((c.start-T0)*2),se=Math.round((c.end-T0)*2); |
|
const height=(se-ss)*25-1; |
|
const cells=g.querySelectorAll(`[data-d="${d}"][data-s="${ss}"]`); |
|
if(!cells.length)return; |
|
const cell=cells[0]; |
|
const existing=cell.querySelectorAll('.cal-block'); |
|
const blk=document.createElement('div'); |
|
blk.className=`cal-block ${c.kid==='both'?'both':c.kid}`; |
|
blk.style.height=height+'px';blk.style.top='0'; |
|
if(existing.length>0){ |
|
// Check if same kid or overlapping |
|
blk.style.left=c.kid==='seba'||c.kid==='both'?'50%':'1px'; |
|
blk.style.width='48%'; |
|
if(existing[0].style.width!=='48%'){existing[0].style.width='48%';} |
|
} |
|
const shortName=c.name.replace(/[^\w\s&]/gu,'').trim().split(' ').slice(0,2).join(' '); |
|
blk.textContent=shortName; |
|
blk.title=`${c.name}\n${fmtT(c.start)}β${fmtT(c.end)}\n${c.loc} (${c.dist})`; |
|
cell.appendChild(blk); |
|
}); |
|
}); |
|
// Free hours |
|
const fr=document.getElementById('free-row'); |
|
let fh='<div class="free-cell" style="font-size:0.65em;color:#888">β Both<br>out</div>'; |
|
for(let d=0;d<5;d++){ |
|
const dc=ac.filter(c=>c.days.includes(d)); |
|
const aleS=new Set(),sebaS=new Set(); |
|
dc.forEach(c=>{for(let t=c.start;t<c.end;t+=0.5){const s=Math.round(t*2);if(c.kid==='ale'||c.kid==='both')aleS.add(s);if(c.kid==='seba'||c.kid==='both')sebaS.add(s);}}); |
|
let bo=0;for(const s of aleS)if(sebaS.has(s))bo+=0.5; |
|
const cls=bo>=5?'good':bo>=3?'ok':'bad'; |
|
fh+=`<div class="free-cell ${cls}">${bo}h</div>`; |
|
} |
|
fr.innerHTML=fh; |
|
} |
|
function renderStats(){ |
|
let at=0,st=0,bt=0; |
|
for(let w=1;w<=2;w++){ |
|
const ac=COURSES.filter(c=>c.week===w&&active.has(c.id)); |
|
for(let d=0;d<5;d++){ |
|
const dc=ac.filter(c=>c.days.includes(d)); |
|
const aleS=new Set(),sebaS=new Set(); |
|
dc.forEach(c=>{for(let t=c.start;t<c.end;t+=0.5){const s=Math.round(t*2);if(c.kid==='ale'||c.kid==='both')aleS.add(s);if(c.kid==='seba'||c.kid==='both')sebaS.add(s);}}); |
|
at+=aleS.size*0.5;st+=sebaS.size*0.5; |
|
for(const s of aleS)if(sebaS.has(s))bt+=0.5; |
|
} |
|
} |
|
document.getElementById('stat-ale').textContent=at+'h'; |
|
document.getElementById('stat-seba').textContent=st+'h'; |
|
document.getElementById('stat-free').textContent=bt+'h'; |
|
} |
|
render(); |
|
</script> |
|
</body> |
|
</html> |