{"id":8517,"date":"2026-10-05T00:47:34","date_gmt":"2026-10-04T21:47:34","guid":{"rendered":"https:\/\/englishfever.com\/?page_id=8517"},"modified":"2026-10-11T09:39:39","modified_gmt":"2026-10-11T06:39:39","slug":"schedule","status":"publish","type":"page","link":"https:\/\/englishfever.com\/en\/schedule\/","title":{"rendered":"Schedule"},"content":{"rendered":"<div id=\"ef-schedule-connection\" hidden data-endpoint=\"https:\/\/englishfever.com\/en\/wp-json\/englishfever-schedule\/v1\/plan\" data-nonce=\"\" data-can-edit=\"0\" data-can-bulk=\"0\" data-user-label=\"\" data-login-url=\"https:\/\/englishfever.com\/wp-login.php?redirect_to=https%3A%2F%2Fenglishfever.com%2Fen%2Fschedule%2F\"><\/div>\n\n\n\n<!-- WordPress: paste this entire file into a Custom HTML block. Requires permission to run JavaScript. -->\n<div class=\"tc-planner\" data-teacher-calendar data-no-dynamic-translation>\n<style>\n.tc-planner{--ink:#203a43;--muted:#62777e;--line:#dbe6e7;--gold:#e3af32;--aqua:#46cabc;--pink:#dd49a3;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,\"Segoe UI\",sans-serif;color:var(--ink);max-width:1280px;margin:112px auto 20px;padding:32px;background:radial-gradient(ellipse at 0 0,#fff8df,transparent 40%),radial-gradient(ellipse at 100% 5%,#e3faf3,transparent 45%),#f5f8f7;border:1px solid var(--line);border-radius:28px;box-shadow:0 18px 60px #203a4310;line-height:1.5;box-sizing:border-box}\n.tc-planner *{box-sizing:border-box}.tc-planner button,.tc-planner input,.tc-planner select{font:inherit}.tc-planner button{cursor:pointer}.tc-planner h2{font-size:clamp(28px,4vw,44px);letter-spacing:-1.5px;line-height:1.1;margin:8px 0 14px;color:var(--ink)}.tc-planner p{margin:0}.tc-planner .tc-eyebrow{font-size:11px;letter-spacing:2px;font-weight:800;text-transform:uppercase;color:#528278}.tc-planner .tc-intro{max-width:730px;color:var(--muted);font-size:14px}.tc-planner .tc-stats{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin:26px 0 16px}.tc-planner .tc-stat{padding:20px;border:1px solid #ffffff;border-radius:20px;background:#ffffffa6;box-shadow:0 6px 22px #203a4306;position:relative;overflow:hidden}.tc-planner .tc-stat::before{content:\"\";position:absolute;top:0;left:0;right:0;height:4px;background:var(--accent)}.tc-planner .tc-stat strong{font-size:15px}.tc-planner .tc-number{font-size:36px;font-weight:750;letter-spacing:-1px;line-height:1.25;margin-top:8px}.tc-planner .tc-number span{font-size:13px;font-weight:500;letter-spacing:0;color:var(--muted)}.tc-planner .tc-detail{font-size:12px;color:var(--muted)}.tc-planner .tc-meter{height:5px;background:#e8eeee;border-radius:10px;margin-top:14px;overflow:hidden}.tc-planner .tc-meter i{display:block;height:100%;background:var(--accent);transition:width .2s}.tc-planner .tc-health{display:flex;gap:10px;justify-content:space-between;flex-wrap:wrap;font-size:12px;color:var(--muted);margin:12px 0 24px}.tc-planner .tc-toolbar{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:20px 0 12px}.tc-planner .tc-btn{border:1px solid #d1dfde;border-radius:10px;padding:8px 12px;background:white;color:var(--ink);font-size:12px;font-weight:600}.tc-planner .tc-btn:hover{background:#eef7f3}.tc-planner .tc-btn:disabled{opacity:.4;cursor:default}.tc-planner .tc-primary{background:#254b46;color:white;border-color:#254b46}.tc-planner .tc-instructions{font-size:12px;color:var(--muted);padding:12px 16px;border:1px dashed #c7dcd7;border-radius:12px;background:#ffffff80}.tc-planner .tc-weeks{display:grid;gap:24px;margin-top:24px}.tc-planner .tc-week{scroll-margin-top:160px;border:1px solid var(--line);border-radius:18px;background:#ffffffb5;overflow:hidden}.tc-planner .tc-weektitle{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:15px 20px;border-bottom:1px solid var(--line)}.tc-planner .tc-weektitle strong{font-size:14px}.tc-planner .tc-weektitle span{font-size:12px;color:var(--muted)}.tc-planner .tc-days{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:0}.tc-planner .tc-day{padding:14px 10px;border-right:1px solid #e7eeee;min-width:0}.tc-planner .tc-day:last-child{border:0}.tc-planner .tc-dayhead{display:flex;align-items:baseline;justify-content:space-between;margin:0 4px 12px;gap:4px}.tc-planner .tc-dayhead b{font-size:12px}.tc-planner .tc-dayhead span{font-size:11px;color:var(--muted)}.tc-planner .tc-stone{width:100%;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;border-radius:17px;height:68px;border:1px solid #ffffffb3;box-shadow:inset 0 2px 3px #ffffffee,inset 0 -5px 7px #00000013,0 4px 7px #203a4318;overflow:hidden;color:#333;touch-action:pan-y;transition:transform .16s,box-shadow .16s;background:var(--stone);margin:0}.tc-planner .tc-stone::before{content:\"\";position:absolute;top:3px;left:8%;width:84%;height:42%;border-radius:50%;background:linear-gradient(#ffffffb8,#ffffff10);pointer-events:none}.tc-planner .tc-stone:hover{transform:translateY(-2px);box-shadow:inset 0 2px 3px white,inset 0 -5px 7px #00000013,0 7px 12px #203a4324}.tc-planner .tc-stone b{font-size:14px;z-index:1}.tc-planner .tc-stone small{font-size:10px;z-index:1;opacity:.8}.tc-planner .tc-inga{--stone:linear-gradient(145deg,#fff0aa,#e8b93f 55%,#c99017);color:#533b08}.tc-planner .tc-santa{--stone:linear-gradient(145deg,#bff7e7,#60d5c5 55%,#27aa9b);color:#134b44}.tc-planner .tc-viktorija{--stone:linear-gradient(145deg,#ffd0ed,#ef78bc 55%,#cf3994);color:#652146}.tc-planner .tc-gap{height:26px;display:flex;align-items:center;justify-content:center;font-size:9px;color:#81918f;white-space:nowrap}.tc-planner .tc-gap.tc-lunch{height:34px}.tc-planner .tc-finish{font-size:10px;color:#7b8f8b;text-align:center;margin-top:9px}.tc-planner .tc-over{outline:3px solid #254b46;outline-offset:2px}.tc-planner .tc-status{min-height:24px;font-size:12px;color:#315f51;margin:12px 0}.tc-planner .tc-foot{font-size:11px;color:var(--muted);margin-top:24px}.tc-planner dialog{border:1px solid #dbe6e7;border-radius:20px;padding:24px;width:min(420px,90vw);color:var(--ink);box-shadow:0 20px 80px #203a4333}.tc-planner dialog::backdrop{background:#143d3a66;backdrop-filter:blur(4px)}.tc-planner dialog h3{margin:0 0 8px}.tc-planner dialog label{display:block;font-size:13px;margin:16px 0 5px}.tc-planner dialog select{width:100%;padding:10px;border:1px solid #ccdcd8;border-radius:8px;background:white}.tc-planner .tc-modalactions{display:flex;gap:8px;justify-content:flex-end;margin-top:22px}.tc-planner button:focus-visible{outline:3px solid #163f52;outline-offset:3px}\n.tc-planner .tc-compact{display:none}.tc-planner .tc-sessiontime span+span::before{content:'\u2013'}\n@media(max-width:700px){.tc-planner{padding:10px;border-radius:18px}.tc-planner .tc-stats{gap:6px}.tc-planner .tc-stat{padding:10px}.tc-planner .tc-number{font-size:26px}.tc-planner .tc-number span{display:block;font-size:10px}.tc-planner .tc-stat strong{font-size:12px}.tc-planner .tc-days{grid-template-columns:repeat(5,minmax(0,1fr))}.tc-planner .tc-day{border-right:1px solid #e7eeee;border-bottom:0;padding:10px 3px}.tc-planner .tc-dayhead{display:flex;flex-direction:column;align-items:center;gap:2px;margin:0 0 10px}.tc-planner .tc-dayhead b{font-size:11px}.tc-planner .tc-dayhead span{font-size:9px}.tc-planner .tc-full{display:none}.tc-planner .tc-compact{display:inline}.tc-planner .tc-stone{height:66px;border-radius:12px;padding:4px 1px;min-width:0}.tc-planner .tc-stone b{font-size:clamp(9px,2.4vw,12px);letter-spacing:-.3px;white-space:nowrap}.tc-planner .tc-stone small{font-size:9px;line-height:1.3}.tc-planner .tc-sessiontime span{display:block}.tc-planner .tc-sessiontime span+span::before{content:''}.tc-planner .tc-gap{height:24px;font-size:8px}.tc-planner .tc-gap.tc-lunch{height:30px}.tc-planner .tc-finish{font-size:8px;white-space:nowrap}.tc-planner .tc-weektitle{padding:12px 10px}.tc-planner .tc-weektitle strong{font-size:13px}.tc-planner .tc-weektitle span{font-size:10px}.tc-planner .tc-week{scroll-margin-top:90px}.tc-planner .tc-btn{padding:8px 10px}}\n@media print{.tc-planner{background:white;box-shadow:none;padding:0;border:0;max-width:none;margin:0;font-size:10px;print-color-adjust:exact;-webkit-print-color-adjust:exact}.tc-planner .tc-toolbar,.tc-planner .tc-instructions,.tc-planner .tc-status,.tc-planner dialog{display:none}.tc-planner .tc-week{break-inside:avoid;margin:0}.tc-planner .tc-weeks{gap:12px}.tc-planner .tc-days{grid-template-columns:repeat(5,1fr)}.tc-planner .tc-day{padding:7px;border-bottom:0}.tc-planner .tc-stone{height:42px}.tc-planner .tc-gap{height:16px}.tc-planner .tc-gap.tc-lunch{height:20px}.tc-planner .tc-stats{margin:15px 0}.tc-planner h2{font-size:28px}.tc-planner .tc-weektitle{padding:8px 12px}}\n.tc-dayoff{background:linear-gradient(150deg,#eef3f4,#dde7e9);border-radius:16px;border:1px dashed #a9bdc3;padding:28px 8px;text-align:center;color:#49636c;min-height:260px;display:flex;flex-direction:column;justify-content:center;gap:8px}.tc-dayoff strong{font-size:18px}.tc-dayoff small{font-size:12px}@media(max-width:600px){.tc-dayoff{padding:16px 3px;min-height:230px}.tc-dayoff strong{font-size:13px}.tc-dayoff small{font-size:10px}}\n<\/style>\n<div class=\"tc-eyebrow\">Eight weeks \u00b7 three teachers \u00b7 one shared plan<\/div>\n<h2>A little balance.<br>A brighter working week.<\/h2>\n<p class=\"tc-intro\">12 October \u2013 4 December 2026 \u00b7 144 sessions \u00b7 216 teaching hours.<br>Plan full days where possible, with room for a shared morning or afternoon.<\/p>\n<div class=\"tc-stats\"><\/div>\n<div class=\"tc-health\"><\/div>\n<div class=\"tc-instructions\">Drag one stone onto another to <b>swap sessions<\/b>. Click or tap a stone to change its teacher, half day, or whole day. All three teachers can be assigned to any weekday.<\/div>\n<div class=\"tc-toolbar\">\n<button class=\"tc-btn tc-primary\" data-action=\"current-week\">Current week<\/button>\n<button class=\"tc-btn\" data-action=\"undo\" disabled>\u21b6 Undo<\/button>\n<button class=\"tc-btn\" data-action=\"export\">Export plan<\/button>\n<button class=\"tc-btn\" data-action=\"import\">Import plan<\/button>\n<button class=\"tc-btn\" data-action=\"csv\">Download CSV<\/button>\n<button class=\"tc-btn\" data-action=\"print\">Print \/ PDF<\/button>\n<button class=\"tc-btn\" data-action=\"reset\">Reset starting plan<\/button>\n<input type=\"file\" accept=\".json,application\/json\" class=\"tc-import\" hidden>\n<\/div>\n<div class=\"tc-status\" role=\"status\" aria-live=\"polite\"><\/div>\n<div class=\"tc-weeks\"><\/div>\n<p class=\"tc-foot\">11 and 18 November are days off and excluded from session totals. Each stone is one 90-minute session. Monday\u2013Thursday: two 10-minute breaks and a 50-minute lunch. Friday: one 10-minute break and a 50-minute lunch, ending at 14:30. Edits are saved to WordPress and checked every 8 seconds. Only the authorised teacher accounts can edit. Export a plan for a backup.<\/p>\n<dialog class=\"tc-editor\"><h3>Change assignment<\/h3><p class=\"tc-editdescription tc-detail\"><\/p><label>Teacher<select class=\"tc-teacher\"><option value=\"Inga\">Inga \u00b7 Golden<\/option><option value=\"Santa\">Santa \u00b7 Aquamarine<\/option><option value=\"Viktorija\">Viktorija \u00b7 Fuchsia<\/option><\/select><\/label><label>Apply to<select class=\"tc-scope\"><option value=\"session\">This session<\/option><option value=\"half\">This half day<\/option><option value=\"day\">The whole day<\/option><\/select><\/label><p class=\"tc-detail\" style=\"margin-top:12px\">Monday\u2013Thursday halves: sessions 1\u20132 \/ 3\u20134. Friday halves: sessions 1\u20132 \/ session 3.<\/p><div class=\"tc-modalactions\"><button class=\"tc-btn\" data-action=\"cancel\">Cancel<\/button><button class=\"tc-btn tc-primary\" data-action=\"apply\">Apply change<\/button><\/div><\/dialog>\n<script>\n(() => {\n  'use strict';\n\n  const root = document.currentScript?.closest('[data-teacher-calendar]') || document.querySelector('[data-teacher-calendar]');\n  if (!document.querySelector('meta[name=\"viewport\"]')) {\n    const meta = document.createElement('meta');\n    meta.name = 'viewport';\n    meta.content = 'width=device-width, initial-scale=1';\n    document.head.appendChild(meta);\n  }\n  const $ = s => root.querySelector(s),\n    names = ['Inga', 'Santa', 'Viktorija'],\n    days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'];\n  const key = 'teacher-calendar-2026-10-12-v1',\n    start = new Date(2026, 9, 12),\n    slots = [],\n    history = [];\n  const daysOff = new Set(['2026-11-11','2026-11-18']); function isoDate(w,d) { const dt = date(w,d); return `${dt.getFullYear()}-${String(dt.getMonth()+1).padStart(2,'0')}-${String(dt.getDate()).padStart(2,'0')}`; } function isDayOff(w,d) { return daysOff.has(isoDate(w,d)); } const totalSessions = 144; const times = ['09:00\u201310:30', '10:40\u201312:10', '13:00\u201314:30', '14:40\u201316:10'];\n  for (let w = 0; w < 8; w++) for (let d = 0; d < 5; d++) for (let s = 0; s < (d === 4 ? 3 : 4); s++) slots.push({\n    w,\n    d,\n    s\n  });\n  function initial() {\n    return slots.map(({\n      w,\n      d,\n      s\n    }) => {\n      if (d === 0) return 'Inga';\n      if (d === 3) {\n        if (w === 0) return 'Inga';\n        const ingaHalf = w % 2 === 1 ? 0 : 1;\n        if (Math.floor(s \/ 2) === ingaHalf) return 'Inga';\n        return w <= 2 ? 'Santa' : 'Viktorija';\n      }\n      if (d === 1) return w % 2 === 0 ? 'Santa' : 'Viktorija';\n      if (d === 2) return w % 2 === 0 ? 'Viktorija' : 'Santa';\n      return w < 5 ? 'Santa' : 'Viktorija';\n    });\n  }\n  let plan = initial(),\n    drag = null,\n    edit = null,\n    saveAvailable = true;\n  function valid(a) {\n    return (Array.isArray(a) ? a.length === slots.length : false) ? a.every(n => names.includes(n)) : false;\n  }\n  const connection = document.getElementById('ef-schedule-connection');\n  const canEdit = connection?.dataset.canEdit === '1';\n  const canBulk = connection?.dataset.canBulk === '1';\n  let revision = -1, busy = false, ready = false, openedAtCurrentWeek = false;\n  function currentWeek(now = new Date()) {\n    const parts = new Intl.DateTimeFormat('en-GB',{timeZone:'Europe\/Riga',year:'numeric',month:'numeric',day:'numeric'}).formatToParts(now);\n    const part = type => Number(parts.find(p=>p.type===type).value);\n    const today = Date.UTC(part('year'),part('month')-1,part('day'));\n    return Math.max(0,Math.min(7,Math.floor((today-Date.UTC(2026,9,12))\/604800000)));\n  }\n  function jumpToCurrentWeek() {\n    const week = root.querySelectorAll('.tc-week')[currentWeek()];\n    if (week) week.scrollIntoView({behavior:'instant',block:'start'});\n  }\n  const banner = document.createElement('p');\n  banner.className = 'tc-instructions';\n  banner.style.marginTop = '16px';\n  if (canEdit) banner.textContent = 'Shared schedule \u00b7 Signed in as ' + connection.dataset.userLabel + ' \u00b7 Your edits save for everyone.';\n  else {\n    banner.textContent = 'Shared schedule \u00b7 View only. ';\n    const login = document.createElement('a');\n    login.textContent = 'Teachers: sign in to edit';\n    login.href = connection?.dataset.loginUrl || '\/wp-login.php';\n    banner.appendChild(login);\n  }\n  $('.tc-intro').after(banner);\n  if (!canBulk) ['import','reset'].forEach(action=>{const el=$('[data-action=\"'+action+'\"]'); if (el) el.hidden=true;});\n  function editing() { return canEdit ? ready ? !busy : false : false; }\n  function applyState(data) {\n    if (!valid(data.assignments) || !Number.isInteger(data.revision)) throw Error('Invalid server response');\n    plan = data.assignments.slice(); revision = data.revision; ready = true;\n    render();\n    if (!openedAtCurrentWeek) {\n      openedAtCurrentWeek = true;\n      requestAnimationFrame(()=>requestAnimationFrame(jumpToCurrentWeek));\n    }\n  }\n  function savedMessage(data) {\n    return data.updated_by ? 'Saved for everyone \u00b7 Last edit by ' + data.updated_by + ' at ' + new Date(data.updated_at).toLocaleString('en-GB',{timeZone:'Europe\/Riga',day:'numeric',month:'short',hour:'2-digit',minute:'2-digit'}) + ' (Riga).' : 'Shared plan loaded. Changes save for all three teachers.';\n  }\n  async function request(method, body) {\n    if (!connection) throw Error('Shared connection unavailable');\n    const controller = new AbortController();\n    const timeout = setTimeout(()=>controller.abort(),15000);\n    try {\n      const headers = {'Content-Type':'application\/json'};\n      if (canEdit) headers['X-WP-Nonce'] = connection.dataset.nonce;\n      const response = await fetch(connection.dataset.endpoint,{method,headers,credentials:'same-origin',cache:'no-store',signal:controller.signal,body:body?JSON.stringify(body):undefined});\n      const nonce = response.headers.get('X-WP-Nonce');\n      if (nonce) connection.dataset.nonce = nonce;\n      const data = await response.json();\n      return {response,data};\n    } finally {clearTimeout(timeout);}\n  }\n  async function refresh() {\n    if (busy || document.hidden) return;\n    try {\n      const {response,data} = await request('GET');\n      if (!response.ok) throw Error();\n      if (data.revision !== revision) {\n        history.length = 0;\n        if ($('.tc-editor').open) $('.tc-editor').close();\n        applyState(data); say(savedMessage(data));\n      }\n    } catch(e) {say(ready ? 'Connection lost. Edits require a successful server save. Reconnecting automatically\u2026' : 'Cannot load shared schedule. Reconnecting automatically\u2026');}\n  }\n  function date(w, d = 0) {\n    let dt = new Date(start);\n    dt.setDate(dt.getDate() + w * 7 + d);\n    return dt;\n  }\n  const fmt = dt => dt.toLocaleDateString('en-GB', {\n    day: 'numeric',\n    month: 'short'\n  });\n  function say(message) {\n    $('.tc-status').textContent = message;\n  }\n  async function commit(next, message, undo = false) {\n    if (!editing() || !valid(next)) return;\n    const changes = next.map((teacher,index)=>({teacher,index})).filter(c=>!isDayOff(slots[c.index].w,slots[c.index].d) && c.teacher !== plan[c.index]);\n    if (!changes.length) {say('The assignments are already the same.');return;}\n    const before = plan.slice();\n    busy = true; render(); say('Saving shared schedule\u2026');\n    try {\n      const {response,data} = await request('POST',{expected_revision:revision,changes});\n      if (response.status === 409) {\n        history.length=0; applyState(data);\n        say('Another teacher changed the schedule. Latest edits loaded; please repeat your change.');\n        return;\n      }\n      if (!response.ok) throw Error(response.status===403 ? 'Your sign-in expired or this account cannot edit. Sign in again, then reload the page.' : 'Could not save. Please try the change again.');\n      if (undo) history.pop(); else history.push(before);\n      if(history.length>100) history.shift();\n      applyState(data); say(message + ' ' + savedMessage(data));\n    } catch(e) {say('Change was not confirmed saved. ' + (e.message || 'Reconnect and try again.'));}\n    finally {busy=false;render();}\n  }\n  function stats() {\n    let counts = names.map(n => plan.filter((x,i) => x === n && !isDayOff(slots[i].w,slots[i].d)).length),\n      full = [0, 0, 0],\n      split = 0,\n      uneven = 0;\n    for (let w = 0; w < 8; w++) for (let d = 0; d < 5; d++) {\n      if (isDayOff(w,d)) continue; let a = slots.map((x, i) => (x.w === w ? x.d === d : false) ? plan[i] : null).filter(Boolean);\n      if (new Set(a).size === 1) full[names.indexOf(a[0])]++;else {\n        split++;\n        if (d === 4 ? a[0] !== a[1] : a[0] !== a[1] || a[2] !== a[3]) uneven++;\n      }\n    }\n    $('.tc-stats').innerHTML = names.map((n, i) => `<div class=\"tc-stat\" style=\"--accent:${['var(--gold)', 'var(--aqua)', 'var(--pink)'][i]}\"><strong>${n}<\/strong><div class=\"tc-number\">${counts[i]} <span>sessions<\/span><\/div><div class=\"tc-detail\">${counts[i] * 1.5} hours \u00b7 ${full[i]} full days<\/div><div class=\"tc-meter\"><i style=\"width:${counts[i] \/ totalSessions * 100}%\"><\/i><\/div><\/div>`).join('');\n    let spread = Math.max(...counts) - Math.min(...counts);\n    $('.tc-health').innerHTML = `<span><b>${spread <= 1 ? 'Beautifully balanced' : spread <= 3 ? 'Nearly balanced' : 'Workload differs'}<\/b> \u00b7 ${spread} session${spread === 1 ? '' : 's'} between highest and lowest<\/span><span>${split} split days${uneven ? ' \u00b7 ' + uneven + ' outside preferred half-day pattern' : ''} \u00b7 Target \u2248 48 each<\/span>`;\n  }\n  function render() {\n    stats();\n    $('.tc-weeks').innerHTML = Array.from({\n      length: 8\n    }, (_, w) => `<section class=\"tc-week\"><div class=\"tc-weektitle\"><strong>Week ${String(w + 1).padStart(2, '0')}<\/strong><span>${fmt(date(w))} \u2013 ${fmt(date(w, 4))}<\/span><\/div><div class=\"tc-days\">${days.map((day, d) => `<div class=\"tc-day\"><div class=\"tc-dayhead\"><b><span class=\"tc-full\">${day}<\/span><span class=\"tc-compact\">${day.slice(0,3)}<\/span><\/b><span>${fmt(date(w, d))}<\/span><\/div>${isDayOff(w,d) ? '<div class=\"tc-dayoff\"><strong>Day off<\/strong><small>No sessions scheduled<br>Excluded from totals<\/small><\/div>' : ''}${slots.map((x, i) => {\n      if (x.w !== w || x.d !== d || isDayOff(w,d)) return '';\n      let after = x.s === 0 ? '<div class=\"tc-gap\" title=\"10:30\u201310:40 \u00b7 break\"><span class=\"tc-full\">10:30\u201310:40 \u00b7 break<\/span><span class=\"tc-compact\">Break<\/span><\/div>' : x.s === 1 ? '<div class=\"tc-gap tc-lunch\" title=\"12:10\u201313:00 \u00b7 lunch\"><span class=\"tc-full\">12:10\u201313:00 \u00b7 lunch<\/span><span class=\"tc-compact\">Lunch<\/span><\/div>' : (x.s === 2 ? d !== 4 : false) ? '<div class=\"tc-gap\" title=\"14:30\u201314:40 \u00b7 break\"><span class=\"tc-full\">14:30\u201314:40 \u00b7 break<\/span><span class=\"tc-compact\">Break<\/span><\/div>' : '';\n      return `<button type=\"button\" draggable=\"${editing()}\" ${editing()?'':'disabled'} data-slot=\"${i}\" class=\"tc-stone tc-${plan[i].toLowerCase()}\" aria-label=\"${day} ${fmt(date(w, d))}, ${times[x.s]}, ${plan[i]}. Click to change assignment.\"><b>${plan[i]}<\/b><small class=\"tc-sessiontime\">${times[x.s].split('\u2013').map(t=>'<span>'+t+'<\/span>').join('')}<\/small><\/button>${after}`;\n    }).join('')}<div class=\"tc-finish\">${isDayOff(w,d) ? 'No teaching today' : 'Finish ' + (d === 4 ? '14:30' : '16:10')}<\/div><\/div>`).join('')}<\/div><\/section>`).join('');\n    $('[data-action=\"undo\"]').disabled = !editing() || !history.length;\n    ['reset','import','apply'].forEach(action=>$('[data-action=\"'+action+'\"]').disabled=!editing());\n  }\n  root.addEventListener('dragstart', e => {\n    const el = e.target.closest('[data-slot]');\n    if (!el || !editing()) {e.preventDefault();return;}\n    drag = Number(el.dataset.slot);\n    e.dataTransfer.effectAllowed = 'move';\n    e.dataTransfer.setData('text\/plain', String(drag));\n  });\n  root.addEventListener('dragover', e => {\n    const el = e.target.closest('[data-slot]');\n    if (el ? drag !== null : false) {\n      e.preventDefault();\n      e.dataTransfer.dropEffect = 'move';\n      el.classList.add('tc-over');\n    }\n  });\n  root.addEventListener('dragleave', e => {\n    const el = e.target.closest('[data-slot]');\n    if (el ? !el.contains(e.relatedTarget) : false) el.classList.remove('tc-over');\n  });\n  root.addEventListener('dragend', () => {\n    drag = null;\n    root.querySelectorAll('.tc-over').forEach(x => x.classList.remove('tc-over'));\n  });\n  root.addEventListener('drop', e => {\n    const el = e.target.closest('[data-slot]');\n    if (!el || drag === null || !editing()) return;\n    e.preventDefault();\n    let i = Number(el.dataset.slot),\n      j = drag;\n    drag = null;\n    let next = plan.slice();\n    [next[i], next[j]] = [next[j], next[i]];\n    commit(next, 'Sessions swapped.');\n    root.querySelectorAll('.tc-over').forEach(x => x.classList.remove('tc-over'));\n  });\n  function download(contents, file, type) {\n    let blob = new Blob([contents], {\n        type\n      }),\n      url = URL.createObjectURL(blob),\n      a = document.createElement('a');\n    a.href = url;\n    a.download = file;\n    document.body.appendChild(a);\n    a.click();\n    a.remove();\n    setTimeout(() => URL.revokeObjectURL(url), 1000);\n  }\n  root.addEventListener('click', e => {\n    let block = e.target.closest('[data-slot]');\n    if (block) {\n      if (!editing()) return;\n      edit = Number(block.dataset.slot);\n      const x = slots[edit];\n      $('.tc-editdescription').textContent = `${days[x.d]}, ${fmt(date(x.w, x.d))} \u00b7 ${times[x.s]}`;\n      $('.tc-teacher').value = plan[edit];\n      $('.tc-teacher option[value=\"Inga\"]').disabled = false;\n      $('.tc-scope').value = 'session';\n      $('.tc-editor').showModal();\n      return;\n    }\n    let action = e.target.closest('[data-action]')?.dataset.action;\n    if (!action) return;\n    if (action === 'current-week') jumpToCurrentWeek();\n    if (action === 'cancel') $('.tc-editor').close();\n    if (action === 'apply') {\n      let next = plan.slice(),\n        x = slots[edit],\n        scope = $('.tc-scope').value,\n        n = $('.tc-teacher').value;\n      slots.forEach((slot, i) => {\n        if (i === edit || ((slot.w === x.w ? slot.d === x.d : false) ? scope === 'day' || (scope === 'half' ? Math.floor(slot.s \/ 2) === Math.floor(x.s \/ 2) : false) : false)) next[i] = n;\n      });\n      $('.tc-editor').close();\n      commit(next, 'Assignment updated.');\n    }\n    if (action === 'undo' ? history.length : false) {\n      commit(history[history.length-1].slice(), 'Last change undone.', true);\n    }\n    if (action === 'reset' ? confirm('Restore the starting schedule for all three teachers? You can undo this until another teacher edits.') : false) commit(initial(), 'Starting schedule restored.');\n    if (action === 'export') {\n      download(JSON.stringify({\n        version: 1,\n        start: '2026-10-12',\n        assignments: plan\n      }, null, 2), 'teacher-plan-2026-10-12.json', 'application\/json');\n      say('Shared plan exported as a backup.');\n    }\n    if (action === 'import') $('.tc-import').click();\n    if (action === 'csv') {\n      let rows = ['Date,Day,Week,Session,Start,End,Teacher'];\n      slots.forEach((x, i) => {\n        if (isDayOff(x.w,x.d)) return;\n        let dt = date(x.w, x.d),\n          iso = `${dt.getFullYear()}-${String(dt.getMonth() + 1).padStart(2, '0')}-${String(dt.getDate()).padStart(2, '0')}`;\n        rows.push([iso, days[x.d], x.w + 1, x.s + 1, ...times[x.s].split('\u2013'), plan[i]].join(','));\n      });\n      download(rows.join('\\r\\n'), 'teacher-calendar.csv', 'text\/csv;charset=utf-8');\n      say('CSV downloaded.');\n    }\n    if (action === 'print') window.print();\n  });\n  $('.tc-import').addEventListener('change', async e => {\n    let file = e.target.files[0];\n    if (!file) return;\n    try {\n      if (file.size > 100000) throw Error();\n      let data = JSON.parse(await file.text());\n      if (data.version !== 1 || data.start !== '2026-10-12' || !valid(data.assignments)) throw Error();\n      commit(data.assignments.slice(), 'Plan imported.');\n    } catch (err) {\n      say('Could not import: choose a valid exported plan for 12 October 2026. No assignments changed.');\n    }\n    e.target.value = '';\n  });\n  render();\n  say('Loading shared schedule\u2026');\n  refresh();\n  setInterval(refresh,8000);\n  document.addEventListener('visibilitychange',()=>{if(!document.hidden)refresh();});\n  window.addEventListener('online',refresh);\n})();\n<\/script>\n<\/div>\n\n\n\n\n","protected":false},"excerpt":{"rendered":"<p>Eight weeks \u00b7 three teachers \u00b7 one shared plan A little balance.A brighter working week. 12 October \u2013<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"_tutorstarter_page_metadata":{"sidebar_select":"no-sidebar","footer_select":"","page_title_toggle":true,"header_toggle":false,"header_trans_toggle":false,"footer_toggle":false},"footnotes":"","_members_access_role":[],"_members_access_error":""},"class_list":["post-8517","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/pages\/8517","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/comments?post=8517"}],"version-history":[{"count":11,"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/pages\/8517\/revisions"}],"predecessor-version":[{"id":9049,"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/pages\/8517\/revisions\/9049"}],"wp:attachment":[{"href":"https:\/\/englishfever.com\/en\/wp-json\/wp\/v2\/media?parent=8517"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}