const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/chart-DBFzEEJS.js","assets/dates-n-jl3C-v.js","assets/pdf-B_QgZFLu.js","assets/index-CKr-jwvi.js","assets/index-DZaZnuRK.css","assets/pdf-26wlXapU.js","assets/rolldown-runtime-hePW80VL.js"])))=>i.map(i=>d[i]);
import{n as e}from"./rolldown-runtime-hePW80VL.js";import{t}from"./index-CKr-jwvi.js";import{C as n,S as r,a as i,c as a,d as o,f as s,i as c,l,m as u,n as d,o as f,r as p,s as m,t as h,v as g}from"./ui-CuDKrJrQ.js";import{a as _,c as v,i as y,l as b,n as x,o as S,r as C,s as w,t as T}from"./dates-n-jl3C-v.js";function E(e){if(!(e instanceof Date)||!Number.isFinite(e.getTime()))throw Error(`Invalid timeline date.`);let t=`${String(e.getFullYear()).padStart(4,`0`)}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`;if(!C(t))throw Error(`The timeline date is outside the supported range.`);return t}function D(e){return e.map(e=>({id:e.id,name:i(e.title.length>90?`${e.title.slice(0,87)}…`:e.title),start:e.start,end:e.end,progress:Number(e.progressPercent),dependencies:e.predecessors.join(`,`)}))}var O={tasks:100,fileBytes:256e3},k=e=>n().regex(/^\d{1,9}(?:\.\d{1,4})?$/,`Use a positive number with up to four decimal places.`).refine(t=>Number(t)<=e,`Use ${e.toLocaleString(`en-CA`)} or less.`),A=n().refine(C,`Use a real date in YYYY-MM-DD format.`),j=n().regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/,`Use a valid task ID.`),M=r({id:j,phase:n().trim().min(1).max(80),title:n().trim().min(1).max(160),start:A,end:A,hours:k(1e5),rate:k(1e6),progressPercent:k(100),predecessors:u(j).max(O.tasks)}),N=r({schemaVersion:g(1),kind:g(`project-plan`),title:n().trim().min(1).max(160),description:n().max(4e3),currency:s([`CAD`,`USD`,`EUR`,`GBP`,`AUD`]),referenceDate:A,contingencyPercent:k(100),tasks:u(M).min(1,`Add at least one task.`).max(O.tasks)});function P(e){let t=[],n=F(e);if(n)return{ok:!1,errors:[{path:``,message:n}],warnings:t};let r=N.safeParse(e);if(!r.success)return{ok:!1,errors:r.error.issues.map(e=>({path:e.path.join(`.`),message:e.message})),warnings:t};let i=r.data,a=[],o=new Map;i.tasks.forEach((e,t)=>{o.has(e.id)&&a.push({path:`tasks.${t}.id`,message:`Each task needs a unique ID.`}),o.set(e.id,e),e.end<e.start&&a.push({path:`tasks.${t}.end`,message:`The end date must be on or after the start date.`}),new Set(e.predecessors).size!==e.predecessors.length&&a.push({path:`tasks.${t}.predecessors`,message:`A predecessor can only be listed once.`})}),i.tasks.forEach((e,n)=>{e.predecessors.forEach(r=>{let i=o.get(r);r===e.id?a.push({path:`tasks.${n}.predecessors`,message:`A task cannot depend on itself.`}):i?e.start<y(i.end)&&t.push({path:`tasks.${n}.start`,message:`“${e.title}” starts before the next working day after “${i.title}” finishes. Dates have not been moved.`}):a.push({path:`tasks.${n}.predecessors`,message:`A predecessor task is missing. Choose an existing task.`})})});let s=new Set,c=new Set,l=e=>{if(c.has(e))return!1;if(s.has(e))return!0;c.add(e);for(let t of o.get(e)?.predecessors??[])if(!l(t))return!1;return c.delete(e),s.add(e),!0};return i.tasks.some(e=>!l(e.id))&&a.push({path:`tasks`,message:`These dependencies form a loop. Remove a predecessor to break the cycle.`}),a.length?{ok:!1,errors:a,warnings:t}:{ok:!0,value:i,warnings:t}}function F(e){let t=new Set,n=0,r=(e,i)=>{if(++n>6e3||i>8)return`This plan is too complex to import.`;if(typeof e==`string`&&e.length>8e3)return`A field in this plan is too long.`;if(!e||typeof e!=`object`)return null;if(t.has(e))return`This plan contains a circular object.`;if(t.add(e),!Array.isArray(e)&&Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)return`This plan contains an unsupported object.`;for(let[t,n]of Object.entries(e)){if([`__proto__`,`prototype`,`constructor`].includes(t))return`This plan contains an unsafe property.`;let e=r(n,i+1);if(e)return e}return t.delete(e),null};return r(e,0)}function I(e){if(!P(e).ok)throw Error(`Correct the plan before calculating its budget.`);let t=Object.create(null),n=new S(0);for(let r of e.tasks)t[r.id]=v(r.hours,r.rate),n=n.plus(r.hours);let r=b(Object.values(t)),i=w(r,e.contingencyPercent),a=e.tasks.map(e=>e.start).sort()[0],o=e.tasks.map(e=>e.end).sort().at(-1);return{totalHours:n.toString(),baseCost:r,contingency:i,totalCost:b([r,i]),taskCosts:t,start:a,end:o,calendarDays:x(a,o),workingDays:_(a,o)}}function L(e,t=!1){return`"${(!t&&/^[\s\u0000-\u001f]*[=+@-]|^[\t\r\n]/.test(e)?`'${e}`:e).replaceAll(`"`,`""`)}"`}function R(e){let t=I(e),n=[[`Task ID`,`Phase`,`Task`,`Start (inclusive)`,`End (inclusive)`,`Hours`,`Hourly rate`,`Task cost`,`Currency`,`Progress (%)`,`Predecessor IDs`].map(e=>L(e)).join(`,`)];for(let r of e.tasks)n.push([L(r.id),L(r.phase),L(r.title),L(r.start),L(r.end),L(r.hours,!0),L(r.rate,!0),L(t.taskCosts[r.id],!0),L(e.currency),L(r.progressPercent,!0),L(r.predecessors.join(`; `))].join(`,`));return`\uFEFF${n.join(`\r
`)}\r\n`}function z(){return`task-${globalThis.crypto.randomUUID()}`}function B(e,t,n,r){let i=[`Discovery`,`Design`,`Development`,`Integration`,`Testing`,`Launch`],a=[`Agree on goals and scope`,`Design the main screens and experience`,`Build the main features`,`Connect the required systems`,`Test with the team and fix issues`,`Prepare the launch and handover`],o=`2026-09-07`;return{schemaVersion:1,kind:`project-plan`,title:e,description:t,currency:`CAD`,referenceDate:`2026-09-07`,contingencyPercent:`15`,tasks:i.map((e,t)=>{let i=T(o,t===2?18:t===5?2:4),s={id:`task-${t+1}`,phase:e,title:a[t],start:o,end:i,hours:String(n[t]),rate:r,progressPercent:`0`,predecessors:t?[`task-${t}`]:[]};return o=y(i),s})}}var V={"customer-portal":B(`Customer portal`,`An illustrative plan for a secure customer portal with account access, requests and updates. Replace the sample hours, rates and dates with your own.`,[24,40,160,40,48,16],`100`),"internal-application":B(`Internal business application`,`An illustrative plan for an internal application that replaces spreadsheet handoffs. Sample rates are not Essential Designs prices.`,[32,48,200,64,64,24],`100`),"legacy-modernization":B(`Legacy software modernization`,`An illustrative plan for improving an existing system, connecting data and moving users safely. Investigate migration requirements before setting your own estimate.`,[48,40,240,96,80,32],`100`)},H=e({mount:()=>K}),U=e=>structuredClone(e),W=(e,t)=>new Intl.NumberFormat(`en-CA`,{style:`currency`,currency:t,currencyDisplay:`code`}).format(Number(e)),G=`project-planner`;function K(e){let n=U(V[`customer-portal`]),r=!1,s=!1,u=!0,g=0,_,v=`Week`,b=!window.matchMedia(`(max-width: 767px)`).matches,x=`Start with the sample plan, then replace the illustrative hours, rates and dates with your own.`,S=!1,w=`A4`,T=!1,D=0,k=!1,A=(t,n=!1)=>{x=t,S=n;let r=e.querySelector(`[data-planner-status]`);r&&(r.textContent=x,r.setAttribute(`role`,n?`alert`:`status`),r.classList.toggle(`et-error`,n))},j=()=>{if(!r)return;let e=P(n);if(!e.ok){A(`Correct the highlighted fields before this draft can be saved. Your previous saved draft is unchanged.`,!0);return}try{m(G,e.value)}catch(e){r=!1,A(l(e),!0)}},M=(e,t,n,r=``)=>`<label class="et-planner-field">${e}<input data-project-field="${t}" data-focus="project-${t}" value="${i(n)}" ${r}></label>`,N=(e,t,n,r,a=``)=>`<label><span class="et-planner-cell-label">${n}</span><input aria-label="Task ${t+1} ${n.toLowerCase()}" data-task="${i(e.id)}" data-task-field="${r}" data-focus="${i(e.id)}-${r}" value="${i(e[r])}" ${a}></label>`;function F(){let a=document.activeElement instanceof HTMLElement&&e.contains(document.activeElement)?document.activeElement.dataset.focus:void 0,o=document.activeElement instanceof HTMLButtonElement&&e.contains(document.activeElement)?{...document.activeElement.dataset}:void 0;_?.(),_=void 0;let c=++g,l=P(n),d=l.ok?I(l.value):null,f=l.ok?[]:l.errors,p=l.warnings,m=d?.calendarDays??0,h=m>730,y=m>3650;h&&v===`Day`&&(v=`Week`),y&&v!==`Month`&&(v=`Month`),e.innerHTML=`
      <div class="et-planner" aria-label="Project planner workspace">
        <div class="et-planner-toolbar">
          <label class="et-planner-field">Start from an example<select data-template aria-label="Choose a project example"><option value="">Choose an example…</option>${Object.entries(V).map(([e,t])=>`<option value="${e}">${i(t.title)}</option>`).join(``)}</select></label>
          <button type="button" data-action="import">Import JSON</button>
          <button type="button" data-action="restore">Restore saved draft</button>
          <button type="button" data-action="clear">Clear draft</button>
          <input type="file" data-import accept=".json,application/json" hidden aria-label="Import a saved project plan">
        </div>
        <p class="et-planner-status ${S?`et-error`:``}" data-planner-status role="${S?`alert`:`status`}" aria-live="polite">${i(x)}</p>
        <section class="et-planner-panel" aria-labelledby="et-plan-details">
          <h2 id="et-plan-details">Your project</h2>
          <div class="et-planner-details">
            ${M(`Project name`,`title`,n.title,`maxlength="160" required`)}
            <label class="et-planner-field">Currency<select data-project-field="currency" data-focus="project-currency">${[`CAD`,`USD`,`EUR`,`GBP`,`AUD`].map(e=>`<option ${n.currency===e?`selected`:``}>${e}</option>`).join(``)}</select></label>
            ${M(`Reference date`,`referenceDate`,n.referenceDate,`type="date" min="1900-01-01" max="2199-12-31" required`)}
            ${M(`Extra budget for the unexpected (%)`,`contingencyPercent`,n.contingencyPercent,`type="number" min="0" max="100" step="0.01" inputmode="decimal" required`)}
          </div>
          <label class="et-planner-field et-planner-description">What is the project for?<textarea data-project-field="description" data-focus="project-description" maxlength="4000" rows="2">${i(n.description)}</textarea></label>
          <p class="et-planner-help">The reference date is for your records; changing it does not move tasks. Changing currency changes the label, with no conversion. Sample rates are illustrative, not Essential Designs prices.</p>
        </section>
        <section class="et-planner-summary" aria-label="Estimated project budget" ${d?``:`aria-busy="true"`}>
          <div><span>Total hours</span><strong data-total-hours>${d?i(d.totalHours):`—`}</strong></div>
          <div><span>Base cost</span><strong data-base-cost>${d?i(W(d.baseCost,n.currency)):`—`}</strong></div>
          <div><span>Extra budget (${i(n.contingencyPercent)}%)</span><strong data-contingency>${d?i(W(d.contingency,n.currency)):`—`}</strong></div>
          <div><span>Total estimated cost</span><strong data-total-cost>${d?i(W(d.totalCost,n.currency)):`—`}</strong></div>
          <p>Planning estimate based on your inputs—not a quotation.</p>
        </section>
        <div data-validation>${L(f,`Please correct these fields`,`et-error`)}${L(p,`Schedule conflicts to review`,`et-warning`)}</div>
        <section class="et-planner-panel" aria-labelledby="et-plan-tasks">
          <div class="et-planner-heading"><div><h2 id="et-plan-tasks">Tasks and dates</h2><p class="et-planner-help">Edit tasks here or adjust dates on the timeline. Hours are separate from duration. Dependent tasks will not move automatically.</p></div><button type="button" data-action="add" ${n.tasks.length>=O.tasks?`disabled`:``}>Add task</button></div>
          <div class="et-planner-table-wrap">
            <table class="et-planner-table"><caption class="et-planner-sr">Editable project tasks. Use the previous task selector for finish-to-start dependencies.</caption><thead><tr><th scope="col">Task / phase</th><th scope="col">Start / end</th><th scope="col">Hours / rate</th><th scope="col">Progress / cost</th><th scope="col">Previous tasks</th><th scope="col">Actions</th></tr></thead><tbody>
              ${n.tasks.map((e,t)=>`<tr data-task-row="${i(e.id)}"><td><strong class="et-planner-task-number">Task ${t+1}</strong>${N(e,t,`Task name`,`title`,`maxlength="160" required`)}${N(e,t,`Phase`,`phase`,`maxlength="80" required`)}<small class="et-planner-id">ID: ${i(e.id)}</small></td>
                <td>${N(e,t,`Start date`,`start`,`type="date" min="1900-01-01" max="2199-12-31" required`)}${N(e,t,`End date`,`end`,`type="date" min="1900-01-01" max="2199-12-31" required`)}</td>
                <td>${N(e,t,`Estimated hours`,`hours`,`type="number" min="0" max="100000" step="0.01" inputmode="decimal" required`)}${N(e,t,`Hourly rate`,`rate`,`type="number" min="0" max="1000000" step="0.01" inputmode="decimal" required`)}</td>
                <td>${N(e,t,`Progress (%)`,`progressPercent`,`type="number" min="0" max="100" step="1" required`)}<span class="et-planner-cost">${d?i(W(d.taskCosts[e.id],n.currency)):`Check inputs`}</span></td>
                <td><label><span class="et-planner-cell-label">Previous tasks</span><select aria-label="Task ${t+1} previous tasks" data-task="${i(e.id)}" data-task-field="predecessors" data-focus="${i(e.id)}-predecessors" multiple size="3">${n.tasks.filter(t=>t.id!==e.id).map(t=>`<option value="${i(t.id)}" ${e.predecessors.includes(t.id)?`selected`:``}>${n.tasks.findIndex(e=>e.id===t.id)+1}. ${i(t.title)}</option>`).join(``)}</select></label><small>Choose any tasks that must finish first. Use Ctrl/⌘ to select more than one, or deselect.</small></td>
                <td><div class="et-planner-row-actions"><button type="button" data-action="up" data-id="${i(e.id)}" aria-label="Move task ${t+1} up" ${t===0?`disabled`:``}>↑</button><button type="button" data-action="down" data-id="${i(e.id)}" aria-label="Move task ${t+1} down" ${t===n.tasks.length-1?`disabled`:``}>↓</button><button type="button" data-action="remove" data-id="${i(e.id)}" aria-label="Remove task ${t+1}">Remove</button></div></td></tr>`).join(``)}
            </tbody></table>
          </div>
          <p class="et-planner-help">${n.tasks.length} of ${O.tasks} tasks. Dependencies mean finish-to-start, with no delay added. Working days are Monday–Friday; holidays are not deducted.</p>
        </section>
        <section class="et-planner-panel" aria-labelledby="et-plan-timeline">
          <div class="et-planner-heading"><div><h2 id="et-plan-timeline">Project timeline</h2><p class="et-planner-help" data-duration>${d?`${i(d.start)} to ${i(d.end)}, inclusive · ${d.calendarDays} calendar days · ${d.workingDays} working days`:`Correct the highlighted fields to see the updated timeline.`}</p></div><button type="button" data-action="chart" aria-expanded="${b}" aria-controls="et-planner-chart">${b?`Hide timeline`:`Show timeline`}</button></div>
          <div id="et-planner-chart" ${b?``:`hidden`}>
            <div class="et-planner-views" aria-label="Timeline scale">${[`Day`,`Week`,`Month`].map(e=>`<button type="button" data-action="view" data-view="${e}" aria-pressed="${v===e}" ${e===`Day`&&h||e===`Week`&&y?`disabled`:``}>${e}</button>`).join(``)}</div>
            <p class="et-planner-help">${y?`This long plan uses Month view to keep the timeline responsive.`:h?`Day view is available for plans up to two years long.`:`On desktop, drag or resize a bar to change its dates. Use the task fields for keyboard or mobile editing.`}</p>
            <p data-chart-status class="et-planner-help" role="status">${d?`Loading the timeline…`:`The timeline is paused while there are invalid fields.`}</p>
            <div data-chart class="et-planner-chart"></div>
          </div>
        </section>
        <section class="et-planner-panel" aria-labelledby="et-plan-save"><h2 id="et-plan-save">Save or share your plan</h2><p class="et-planner-help">Download a file to keep or share. The PDF includes full task details and separate timeline pages, so long plans stay readable. Your plan is not sent to Essential Designs.</p>
          <div class="et-planner-exports"><button type="button" data-action="json" ${!d||s?`disabled`:``}>Download JSON</button><button type="button" data-action="csv" ${!d||s?`disabled`:``}>Download CSV</button><label class="et-planner-field">PDF paper size<select data-page-size><option ${w===`A4`?`selected`:``}>A4</option><option ${w===`Letter`?`selected`:``}>Letter</option></select></label><button type="button" data-action="pdf" ${!d||s?`disabled`:``}>${s?`Creating PDF…`:`Download PDF brief`}</button></div>
          <label class="et-planner-remember"><input type="checkbox" data-remember ${r?`checked`:``}> Remember this draft on this device</label><p class="et-planner-help">Off by default. Browser storage is not an encrypted vault; other people using this browser may be able to open the draft. Turning this off removes the saved copy.</p>
        </section>
      </div>`;for(let t of f){let r=t.path.split(`.`),i=r[0]===`tasks`&&r.length>2?`${n.tasks[Number(r[1])]?.id}-${r[2]}`:`project-${r[0]}`;e.querySelectorAll(`[data-focus]`).forEach(e=>{e.dataset.focus===i&&e.setAttribute(`aria-invalid`,`true`)})}a?e.querySelectorAll(`[data-focus]`).forEach(e=>{e.dataset.focus===a&&e.focus({preventScroll:!0})}):o?.action&&([...e.querySelectorAll(`button[data-action]`)].find(e=>e.dataset.action===o.action&&e.dataset.id===o.id&&e.dataset.view===o.view)??e.querySelector(`[data-action="add"]`))?.focus({preventScroll:!0}),d&&b&&t(async()=>{let{mountTimeline:e}=await import(`./chart-DBFzEEJS.js`);return{mountTimeline:e}},__vite__mapDeps([0,1])).then(({mountTimeline:t})=>{u&&c===g&&(_=t(e.querySelector(`[data-chart]`),U(n),{view:v,onReady:()=>{let t=e.querySelector(`[data-chart-status]`);t&&(t.textContent=`Timeline ready. The task list above provides the same dates and values.`)},onError:()=>{let t=e.querySelector(`[data-chart-status]`);t&&(t.textContent=`The timeline could not load. You can still edit every date in the task list and export your plan.`)},onChange:(e,t,r)=>{let i=U(n),a=i.tasks.find(t=>t.id===e);if(!a)return;a.start=t,a.end=r;let o=P(i);if(!o.ok){A(`That timeline change was outside the supported date range.`,!0),F();return}n=o.value,T=!0,A(`Task dates updated. Other tasks have not moved.`),j(),F()}}))}).catch(()=>{if(u&&c===g){let t=e.querySelector(`[data-chart-status]`);t&&(t.textContent=`The timeline could not load. Use the task list to continue.`)}})}function L(e,t,n){return e.length?`<div class="et-planner-issues ${n}" role="${n===`et-error`?`alert`:`status`}"><h3>${t}</h3><ul>${e.slice(0,12).map(e=>`<li>${i(e.path.startsWith(`tasks.`)?`Task ${Number(e.path.split(`.`)[1])+1}: `:``)}${i(e.message)}</li>`).join(``)}</ul>${e.length>12?`<p>And ${e.length-12} more. Correct these fields first.</p>`:``}</div>`:``}async function B(e){let t=e.target;if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement))return;if((t.hasAttribute(`data-project-field`)||t.hasAttribute(`data-task-field`))&&(k=!1),t.hasAttribute(`data-import`)&&t instanceof HTMLInputElement){let e=t.files?.[0];if(!e)return;try{if(e.size>O.fileBytes)throw new a(`This JSON file is too large. Use a plan smaller than 256 KB.`);let t=P(o(await e.text(),O.fileBytes));if(!u)return;if(!t.ok)throw new a(`This plan could not be imported. ${t.errors[0]?.message??`Check its version and fields.`}`);if(!d())return;n=t.value,T=!0,A(`Plan imported. Check the task dates and any schedule warnings.`),j(),F()}catch(e){A(l(e),!0)}finally{t.value=``}return}if(t.hasAttribute(`data-template`)){let e=t.value;e&&d(`Replace this plan with the sample project? Download JSON first if you want to keep your changes.`)?(n=U(V[e]),T=!0,A(`Sample project loaded. Its hours, rates and dates are illustrative.`),j(),F()):t.value=``;return}if(t.hasAttribute(`data-remember`)&&t instanceof HTMLInputElement){r=t.checked;try{if(r){let e=P(n);if(!e.ok)throw new a(`Correct the highlighted fields before saving a draft.`);m(G,e.value),A(`This draft will be saved in this browser as you edit it.`)}else h(G),A(`The saved browser copy was removed. Your current plan is still open.`)}catch(e){r=!1,A(l(e),!0)}F();return}if(t.hasAttribute(`data-page-size`)){w=t.value===`Letter`?`Letter`:`A4`;return}let i=t.dataset.projectField;if(i&&[`title`,`description`,`currency`,`referenceDate`,`contingencyPercent`].includes(i)){n={...n,[i]:t.value},T=!0,A(`Project details updated.`),j(),F();return}let s=t.dataset.task,c=t.dataset.taskField;if(s&&c){let e=n.tasks.find(e=>e.id===s);if(!e)return;c===`predecessors`&&t instanceof HTMLSelectElement?e.predecessors=Array.from(t.selectedOptions).map(e=>e.value):c!==`predecessors`&&(e[c]=t.value),T=!0,A(`Task updated.`),j(),F()}}async function H(i){let a=i.target instanceof Element?i.target.closest(`button[data-action]`):null;if(!a||!e.contains(a)||a.disabled)return;let o=a.dataset.action;if(o===`import`){e.querySelector(`[data-import]`)?.click();return}if(o===`chart`){b=!b,F();return}if(o===`view`){v=a.dataset.view,F();return}if(o===`restore`){try{let e=f(G,P);if(!e){A(`There is no saved plan in this browser. You can import a JSON file instead.`);return}if(!d())return;n=e,T=!0,A(r?`Your saved plan is open. Browser saving remains on.`:`Your saved plan is open. Browser saving remains off unless you choose to enable it.`),F()}catch(e){A(l(e),!0)}return}if(o===`clear`){if(!d(`Clear this plan and its saved browser copy? Download JSON first if you want to keep it.`))return;try{h(G)}catch(e){A(l(e),!0);return}let e=E(new Date);n={schemaVersion:1,kind:`project-plan`,title:`Untitled project`,description:``,currency:n.currency,referenceDate:e,contingencyPercent:`0`,tasks:[{id:z(),phase:`Planning`,title:`First task`,start:e,end:e,hours:`0`,rate:`0`,progressPercent:`0`,predecessors:[]}]},r=!1,T=!1,A(`The plan and saved browser copy have been cleared.`),F();return}if(o===`add`){let t=n.tasks.at(-1),r=t&&C(t.end)&&t.end<`2199-12-24`?y(t.end):n.referenceDate,i=z();n.tasks.push({id:i,phase:`New phase`,title:`New task`,start:C(r)?r:`2026-09-07`,end:C(r)?r:`2026-09-07`,hours:`0`,rate:`0`,progressPercent:`0`,predecessors:[]}),T=!0,A(`Task added. Enter its dates, hours and rate.`),j(),F(),e.querySelector(`[data-focus="${i}-title"]`)?.focus();return}if([`up`,`down`,`remove`].includes(o??``)){let e=n.tasks.findIndex(e=>e.id===a.dataset.id);if(e<0)return;if(o===`remove`){if(!d(`Remove this task and its links from other tasks? Their dates will stay the same.`))return;let t=n.tasks[e].id;n.tasks.splice(e,1),n.tasks.forEach(e=>{e.predecessors=e.predecessors.filter(e=>e!==t)})}else{let t=e+(o===`up`?-1:1);if(t<0||t>=n.tasks.length)return;[n.tasks[e],n.tasks[t]]=[n.tasks[t],n.tasks[e]]}T=!0,A(o===`remove`?`Task removed. Other task dates have not changed.`:`Task order changed. Dates and dependencies are unchanged.`),j(),F();return}if([`json`,`csv`,`pdf`].includes(o??``)){let e=P(n);if(!e.ok){A(`Correct the highlighted fields before downloading.`,!0);return}try{if(o===`json`)c(e.value,`project-plan-v1.json`);else if(o===`csv`)p(R(e.value),`project-tasks.csv`,`text/csv;charset=utf-8`);else{let r=D,i=w,a=JSON.stringify(e.value);s=!0,A(`Creating the PDF brief and timeline pages…`),F();let[{generatePlanPdf:o},{fontBytes:c}]=await Promise.all([t(()=>import(`./pdf-B_QgZFLu.js`),__vite__mapDeps([2,3,4,1,5,6])),t(()=>import(`./pdf-26wlXapU.js`).then(e=>e.r),__vite__mapDeps([5,6,3,4]))]),l=await o(e.value,{fontBytes:await c()},i);if(!u)return;if(r!==D||i!==w||a!==JSON.stringify(n)){A(`Your plan changed while the PDF was being prepared. Your edits are kept. Download the PDF again for the latest version.`);return}p(l,`project-plan.pdf`,`application/pdf`)}A(`${o===`json`?`JSON`:o===`csv`?`CSV`:`PDF`} file created. Your browser handles the download.`),o===`json`&&(T=!1,k=!1)}catch(e){A(l(e),!0)}finally{s=!1,u&&F()}}}let K=e=>{let t=e.target;if(!(t instanceof HTMLInputElement||t instanceof HTMLSelectElement||t instanceof HTMLTextAreaElement))return;let r=t.dataset.projectField;if(r&&[`title`,`description`,`currency`,`referenceDate`,`contingencyPercent`].includes(r))n={...n,[r]:t.value};else if(t.dataset.task&&t.dataset.taskField){let e=n.tasks.find(e=>e.id===t.dataset.task);if(!e)return;let r=t.dataset.taskField;r===`predecessors`&&t instanceof HTMLSelectElement?e.predecessors=Array.from(t.selectedOptions).map(e=>e.value):r!==`predecessors`&&(e[r]=t.value)}else return;D++,k=!0,T=!0},q=e=>{(k||T&&(!r||!P(n).ok))&&(e.preventDefault(),e.returnValue=``)};return e.addEventListener(`input`,K),e.addEventListener(`change`,B),e.addEventListener(`click`,H),window.addEventListener(`beforeunload`,q),F(),()=>{u=!1,g++,_?.(),e.removeEventListener(`input`,K),e.removeEventListener(`change`,B),e.removeEventListener(`click`,H),window.removeEventListener(`beforeunload`,q),e.replaceChildren()}}export{z as a,M as c,R as i,P as l,K as mount,O as n,N as o,I as r,V as s,H as t,D as u};