const { useState, useRef } = React;

/* ---------- constants & seed data ---------- */

const ROLE_OPTIONS = ['Project Manager', 'Developer', 'Architect'];
const VISIBLE_WEEKS = 12;
const HALF = 6;
const REF_MONDAY = new Date(Date.UTC(2026, 0, 5));
const TODAY_DATE = new Date(Date.UTC(2026, 7, 10));

function mondayOf(d) {
  const dt = new Date(d);
  const day = (dt.getUTCDay() + 6) % 7;
  dt.setUTCDate(dt.getUTCDate() - day);
  dt.setUTCHours(0, 0, 0, 0);
  return dt;
}
function absWeek(d) { return Math.round((mondayOf(d) - REF_MONDAY) / (7 * 86400000)); }
function weekDateFromAbs(idx) { return new Date(REF_MONDAY.getTime() + idx * 7 * 86400000); }
function weekLabel(d) { return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); }

const TODAY_ABS_WEEK = absWeek(TODAY_DATE);
const TODAY_ISO = TODAY_DATE.toISOString().slice(0, 10);

const INITIAL_PROJECTS = [
  { id: 'portal', name: 'Client Portal', active: true },
  { id: 'mobile', name: 'Mobile App', active: true },
  { id: 'erp', name: 'ERP Migration', active: true },
];
const INITIAL_RESOURCES = [
  { id: 'ana', name: 'Ana Ferreira', role: 'Project Manager', partnerName: '', initials: 'AF', active: true },
  { id: 'rui', name: 'Rui Santos', role: 'Developer', partnerName: '', initials: 'RS', active: true },
  { id: 'marta', name: 'Marta Lopes', role: 'Architect', partnerName: 'Northwind Consulting', initials: 'ML', active: true },
  { id: 'pedro', name: 'Pedro Costa', role: 'Developer', partnerName: '', initials: 'PC', active: true },
  { id: 'sofia', name: 'Sofia Ramos', role: 'Developer', partnerName: 'Northwind Consulting', initials: 'SR', active: true },
];
const INITIAL_ALLOCATIONS = [
  { id: 'a1', resourceId: 'ana', projectId: 'portal', pct: 40, start: TODAY_ABS_WEEK - 6, span: 6 },
  { id: 'a2', resourceId: 'ana', projectId: 'mobile', pct: 30, start: TODAY_ABS_WEEK - 1, span: 4 },
  { id: 'a3', resourceId: 'ana', projectId: 'erp', pct: 20, start: TODAY_ABS_WEEK + 4, span: 5 },
  { id: 'a4', resourceId: 'rui', projectId: 'portal', pct: 60, start: TODAY_ABS_WEEK - 6, span: 14 },
  { id: 'a5', resourceId: 'rui', projectId: 'mobile', pct: 50, start: TODAY_ABS_WEEK - 3, span: 10 },
  { id: 'a6', resourceId: 'marta', projectId: 'erp', pct: 70, start: TODAY_ABS_WEEK - 6, span: 16 },
  { id: 'a7', resourceId: 'marta', projectId: 'portal', pct: 20, start: TODAY_ABS_WEEK - 6, span: 6 },
  { id: 'a8', resourceId: 'pedro', projectId: 'mobile', pct: 30, start: TODAY_ABS_WEEK, span: 10 },
  { id: 'a9', resourceId: 'sofia', projectId: 'portal', pct: 20, start: TODAY_ABS_WEEK - 6, span: 6 },
  { id: 'a10', resourceId: 'sofia', projectId: 'erp', pct: 10, start: TODAY_ABS_WEEK + 3, span: 6 },
];
const INITIAL_TASKS = [
  { id: 1, resourceId: 'ana', projectId: 'erp', title: 'ERP Migration kickoff', priority: 'Medium', status: 'Completed', startDate: '2026-08-09', endDate: '2026-08-11' },
  { id: 2, resourceId: 'ana', projectId: null, title: 'Approve quarterly budget', priority: 'High', status: 'New', startDate: '2026-08-10', endDate: '2026-08-12' },
  { id: 3, resourceId: 'ana', projectId: null, title: 'Weekly progress report', priority: 'Medium', status: 'On Going', startDate: '2026-08-12', endDate: '2026-08-14' },
  { id: 4, resourceId: 'ana', projectId: 'mobile', title: 'Review Mobile App proposal', priority: 'High', status: 'Blocked', startDate: '2026-08-05', endDate: '2026-08-08' },
  { id: 5, resourceId: 'rui', projectId: 'portal', title: 'Implement authentication', priority: 'High', status: 'Completed', startDate: '2026-08-08', endDate: '2026-08-11' },
  { id: 6, resourceId: 'rui', projectId: 'portal', title: 'Fix checkout bug', priority: 'Medium', status: 'On Going', startDate: '2026-08-12', endDate: '2026-08-13' },
  { id: 7, resourceId: 'rui', projectId: 'mobile', title: 'Sprint 12 code review', priority: 'Low', status: 'Blocked', startDate: '2026-08-07', endDate: '2026-08-09' },
  { id: 8, resourceId: 'marta', projectId: 'erp', title: 'ERP architecture design', priority: 'High', status: 'Completed', startDate: '2026-08-08', endDate: '2026-08-10' },
  { id: 9, resourceId: 'marta', projectId: 'erp', title: 'Data model review', priority: 'Medium', status: 'New', startDate: '2026-08-13', endDate: '2026-08-14' },
  { id: 10, resourceId: 'marta', projectId: 'portal', title: 'Architecture sync meeting', priority: 'Low', status: 'Parked', startDate: '2026-08-11', endDate: '2026-08-12' },
  { id: 11, resourceId: 'pedro', projectId: 'mobile', title: 'Set up test environment', priority: 'Medium', status: 'Completed', startDate: '2026-08-10', endDate: '2026-08-11' },
  { id: 12, resourceId: 'pedro', projectId: 'mobile', title: 'Migrate login component', priority: 'Medium', status: 'New', startDate: '2026-08-14', endDate: '2026-08-15' },
  { id: 13, resourceId: 'sofia', projectId: 'erp', title: 'QA test report', priority: 'Medium', status: 'On Going', startDate: '2026-08-12', endDate: '2026-08-13' },
  { id: 14, resourceId: 'sofia', projectId: 'portal', title: 'Alignment meeting', priority: 'Low', status: 'Blocked', startDate: '2026-08-08', endDate: '2026-08-09' },
];

const PROFILE_STYLE = {
  'Project Manager': { tintBg: 'var(--color-accent-100)', tintText: 'var(--color-accent-800)', border: 'var(--color-accent-700)' },
  'Developer': { tintBg: 'var(--color-accent-100)', tintText: 'var(--color-accent-700)', border: 'var(--color-accent-400)' },
  'Architect': { tintBg: 'var(--color-neutral-200)', tintText: 'var(--color-neutral-800)', border: 'var(--color-neutral-600)' },
};
const PRIORITY_COLOR = { Low: 'var(--color-neutral-500)', Medium: 'oklch(70% 0.15 80)', High: 'oklch(58% 0.19 27)' };
const STATUS_STYLE = {
  'New': 'font-size:11px;padding:2px 8px;background:var(--color-neutral-200);color:var(--color-neutral-800)',
  'On Going': 'font-size:11px;padding:2px 8px;background:var(--color-accent-100);color:var(--color-accent-800)',
  'Blocked': 'font-size:11px;padding:2px 8px;border:1px solid oklch(58% 0.19 27);color:oklch(58% 0.19 27)',
  'Parked': 'font-size:11px;padding:2px 8px;border:1px solid oklch(70% 0.15 80);color:oklch(70% 0.15 80)',
  'Completed': 'font-size:11px;padding:2px 8px;background:var(--color-neutral-100);color:color-mix(in srgb, var(--color-text) 55%, transparent)',
};
const DANGER = 'oklch(58% 0.19 27)';

function avatarStyle(role) {
  const p = PROFILE_STYLE[role] || PROFILE_STYLE.Developer;
  return `width:32px;height:32px;flex:none;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:600;background:${p.tintBg};color:${p.tintText};border:1px solid ${p.border}`;
}

/** Turns a `"prop:value;prop2:value2"` CSS string into a React style object. */
function sx(css) {
  if (!css) return undefined;
  const out = {};
  for (const decl of css.split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const prop = decl.slice(0, i).trim();
    if (!prop) continue;
    const key = prop.startsWith('--') ? prop : prop.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
    out[key] = decl.slice(i + 1).trim();
  }
  return out;
}

/* ---------- app ---------- */

function App() {
  const [state, setState] = useState(() => ({
    screen: 'matrix',
    filterProject: 'all',
    filterRole: 'all',
    editingId: null,
    editValues: null,
    newAlloc: null,
    addResource: null,
    collapsed: {},
    historyProjectKey: null,
    historyProjectName: '',
    backofficeTab: 'projects',
    newProjectNameBo: '',
    selectedPersonId: 'ana',
    statusFilter: 'all',
    weekOffset: 0,
    projects: INITIAL_PROJECTS.map((p) => ({ ...p })),
    resources: INITIAL_RESOURCES.map((r) => ({ ...r })),
    allocations: INITIAL_ALLOCATIONS.map((a) => ({ ...a })),
    tasks: INITIAL_TASKS.map((t) => ({ ...t })),
  }));

  const trackRefs = useRef({});
  const seqRef = useRef(1000);
  const nextId = (prefix) => prefix + seqRef.current++;

  const update = (patch) => setState((s) => ({ ...s, ...(typeof patch === 'function' ? patch(s) : patch) }));

  /* navigation */
  const goMatrix = () => update({ screen: 'matrix' });
  const goActivities = () => update({ screen: 'activities' });
  const goBackoffice = () => update({ screen: 'backoffice' });
  const setBoTabProjects = () => update({ backofficeTab: 'projects' });
  const setBoTabResources = () => update({ backofficeTab: 'resources' });
  const stopProp = (e) => e.stopPropagation();

  /* back office — projects */
  const setNewProjectNameBo = (e) => update({ newProjectNameBo: e.target.value });
  const addProjectBo = () => {
    const name = state.newProjectNameBo.trim();
    if (!name) return;
    const id = nextId('p');
    update((s) => ({ projects: [...s.projects, { id, name, active: true }], newProjectNameBo: '' }));
  };
  const renameProject = (id, name) => update((s) => ({ projects: s.projects.map((p) => (p.id === id ? { ...p, name } : p)) }));
  const toggleProjectActive = (id) => update((s) => ({ projects: s.projects.map((p) => (p.id === id ? { ...p, active: !p.active } : p)) }));
  const deleteProject = (id) => update((s) => ({
    projects: s.projects.filter((p) => p.id !== id),
    allocations: s.allocations.filter((a) => a.projectId !== id),
    tasks: s.tasks.map((t) => (t.projectId === id ? { ...t, projectId: null } : t)),
  }));
  const addUserToProject = (projectId, resourceId) => {
    if (!resourceId) return;
    update((s) => {
      if (s.allocations.some((a) => a.projectId === projectId && a.resourceId === resourceId)) return {};
      return { allocations: [...s.allocations, { id: nextId('a'), resourceId, projectId, pct: 20, start: TODAY_ABS_WEEK, span: 4 }] };
    });
  };
  const removeAllocationById = (id) => update((s) => ({ allocations: s.allocations.filter((a) => a.id !== id) }));

  /* back office — resources */
  const updateResourceField = (id, field, value) => update((s) => ({ resources: s.resources.map((r) => (r.id === id ? { ...r, [field]: value } : r)) }));
  const toggleResourceActive = (id) => update((s) => ({ resources: s.resources.map((r) => (r.id === id ? { ...r, active: !r.active } : r)) }));
  const deleteResource = (id) => update((s) => ({
    resources: s.resources.filter((r) => r.id !== id),
    allocations: s.allocations.filter((a) => a.resourceId !== id),
    tasks: s.tasks.filter((t) => t.resourceId !== id),
    selectedPersonId: s.selectedPersonId === id ? (s.resources.find((r) => r.id !== id) || {}).id : s.selectedPersonId,
  }));

  /* allocation matrix */
  const onFilterProject = (e) => update({ filterProject: e.target.value });
  const onFilterRole = (e) => update({ filterRole: e.target.value });
  const goToday = () => update({ weekOffset: 0 });
  const windowStartAbs = (offset) => TODAY_ABS_WEEK - HALF + offset;
  const prevMonth = () => update((s) => {
    const curStart = weekDateFromAbs(windowStartAbs(s.weekOffset));
    const d = new Date(curStart);
    d.setUTCMonth(d.getUTCMonth() - 1);
    const newAbs = absWeek(mondayOf(d));
    return { weekOffset: newAbs - (TODAY_ABS_WEEK - HALF) };
  });
  const nextMonth = () => update((s) => {
    const curStart = weekDateFromAbs(windowStartAbs(s.weekOffset));
    const d = new Date(curStart);
    d.setUTCMonth(d.getUTCMonth() + 1);
    const newAbs = absWeek(mondayOf(d));
    return { weekOffset: newAbs - (TODAY_ABS_WEEK - HALF) };
  });

  const openEdit = (resourceId) => {
    const values = {};
    state.allocations.filter((a) => a.resourceId === resourceId).forEach((a) => { values[a.id] = a.pct; });
    update({ editingId: resourceId, editValues: values });
  };
  const closeEdit = () => update({ editingId: null, editValues: null });
  const setSlider = (allocId, value) => update((s) => ({ editValues: { ...s.editValues, [allocId]: Number(value) } }));
  const saveEdit = () => update((s) => ({
    allocations: s.allocations.map((a) => (s.editValues[a.id] != null ? { ...a, pct: s.editValues[a.id] } : a)),
    editingId: null, editValues: null,
  }));

  const onBlockMouseDown = (allocId) => (e) => {
    e.preventDefault();
    const track = trackRefs.current[allocId];
    if (!track) return;
    const colWidth = track.offsetWidth / VISIBLE_WEEKS;
    const startX = e.clientX;
    const alloc = state.allocations.find((a) => a.id === allocId);
    const startPos = alloc.start;
    const onMove = (ev) => {
      const newStart = startPos + Math.round((ev.clientX - startX) / colWidth);
      setState((s) => ({ ...s, allocations: s.allocations.map((a) => (a.id === allocId ? { ...a, start: newStart } : a)) }));
    };
    const onUp = () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
  };
  const onResizeMouseDown = (allocId, edge) => (e) => {
    e.stopPropagation();
    e.preventDefault();
    const track = trackRefs.current[allocId];
    if (!track) return;
    const colWidth = track.offsetWidth / VISIBLE_WEEKS;
    const startX = e.clientX;
    const alloc = state.allocations.find((a) => a.id === allocId);
    const origStart = alloc.start, origSpan = alloc.span;
    const onMove = (ev) => {
      const deltaCols = Math.round((ev.clientX - startX) / colWidth);
      setState((s) => ({
        ...s,
        allocations: s.allocations.map((a) => {
          if (a.id !== allocId) return a;
          if (edge === 'left') {
            const newStart = Math.min(origStart + origSpan - 1, origStart + deltaCols);
            return { ...a, start: newStart, span: origStart + origSpan - newStart };
          }
          return { ...a, span: Math.max(1, origSpan + deltaCols) };
        }),
      }));
    };
    const onUp = () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); };
    window.addEventListener('mousemove', onMove);
    window.addEventListener('mouseup', onUp);
  };

  /* new allocation wizard */
  const openNewAlloc = (preset) => update({
    newAlloc: {
      step: 'project', projectQuery: '', projectId: null,
      resourceQuery: '', resourceId: preset ? preset.resourceId : null,
      presetResource: !!(preset && preset.resourceId),
      showCreateResourceForm: false, newResourceName: '', newResourceRole: 'Developer',
      pct: 50, start: TODAY_ABS_WEEK, end: TODAY_ABS_WEEK + 3,
    },
  });
  const closeNewAlloc = () => update({ newAlloc: null });
  const setProjectQuery = (e) => update((s) => ({ newAlloc: { ...s.newAlloc, projectQuery: e.target.value } }));
  const pickProject = (projectId) => update((s) => ({ newAlloc: { ...s.newAlloc, projectId, step: s.newAlloc.presetResource ? 'details' : 'resource' } }));
  const createProject = () => {
    const name = state.newAlloc.projectQuery.trim();
    if (!name) return;
    const id = nextId('p');
    update((s) => ({
      projects: [...s.projects, { id, name, active: true }],
      newAlloc: { ...s.newAlloc, projectId: id, step: s.newAlloc.presetResource ? 'details' : 'resource' },
    }));
  };
  const setResourceQuery = (e) => update((s) => ({ newAlloc: { ...s.newAlloc, resourceQuery: e.target.value } }));
  const pickResource = (resourceId) => update((s) => ({ newAlloc: { ...s.newAlloc, resourceId, step: 'details' } }));
  const toggleCreateResourceForm = () => update((s) => ({ newAlloc: { ...s.newAlloc, showCreateResourceForm: !s.newAlloc.showCreateResourceForm } }));
  const setNewResourceName = (e) => update((s) => ({ newAlloc: { ...s.newAlloc, newResourceName: e.target.value } }));
  const setNewResourceRole = (e) => update((s) => ({ newAlloc: { ...s.newAlloc, newResourceRole: e.target.value } }));
  const createResourceInWizard = () => {
    const w = state.newAlloc;
    const name = w.newResourceName.trim();
    if (!name) return;
    const id = nextId('r');
    const initials = name.split(' ').map((x) => x[0]).slice(0, 2).join('').toUpperCase();
    update((s) => ({
      resources: [...s.resources, { id, name, role: w.newResourceRole, initials, active: true }],
      newAlloc: { ...s.newAlloc, resourceId: id, step: 'details' },
    }));
  };
  const backToProjectStep = () => update((s) => ({ newAlloc: { ...s.newAlloc, step: 'project' } }));
  const backFromDetails = () => update((s) => ({ newAlloc: { ...s.newAlloc, step: s.newAlloc.presetResource ? 'project' : 'resource' } }));
  const setAllocPct = (e) => update((s) => ({ newAlloc: { ...s.newAlloc, pct: Number(e.target.value) } }));
  const setAllocStart = (e) => update((s) => {
    const start = Number(e.target.value);
    const end = Math.max(start, s.newAlloc.end);
    return { newAlloc: { ...s.newAlloc, start, end } };
  });
  const setAllocEnd = (e) => update((s) => {
    const end = Math.max(Number(e.target.value), s.newAlloc.start);
    return { newAlloc: { ...s.newAlloc, end } };
  });
  const saveNewAlloc = () => {
    const w = state.newAlloc;
    if (!w.projectId || !w.resourceId) return;
    const allocId = nextId('a');
    const project = state.projects.find((p) => p.id === w.projectId);
    const dateIso = weekDateFromAbs(w.start).toISOString().slice(0, 10);
    update((s) => ({
      allocations: [...s.allocations, { id: allocId, resourceId: w.resourceId, projectId: w.projectId, pct: w.pct, start: w.start, span: w.end - w.start + 1 }],
      tasks: [...s.tasks, { id: nextId('t'), resourceId: w.resourceId, projectId: w.projectId, title: project.name + ' kickoff', priority: 'Medium', status: 'New', startDate: dateIso, endDate: dateIso }],
      newAlloc: null,
    }));
  };

  /* add resource dialog */
  const openAddResource = () => update({ addResource: { name: '', role: 'Developer', partnerName: '', projectChecks: {}, newProjectName: '' } });
  const closeAddResource = () => update({ addResource: null });
  const setAddResName = (e) => update((s) => ({ addResource: { ...s.addResource, name: e.target.value } }));
  const setAddResRole = (e) => update((s) => ({ addResource: { ...s.addResource, role: e.target.value } }));
  const setAddResPartner = (e) => update((s) => ({ addResource: { ...s.addResource, partnerName: e.target.value } }));
  const toggleAddResProject = (projectId) => update((s) => ({ addResource: { ...s.addResource, projectChecks: { ...s.addResource.projectChecks, [projectId]: !s.addResource.projectChecks[projectId] } } }));
  const setAddResNewProjectName = (e) => update((s) => ({ addResource: { ...s.addResource, newProjectName: e.target.value } }));
  const addNewProjectInAddResource = () => {
    const name = state.addResource.newProjectName.trim();
    if (!name) return;
    const id = nextId('p');
    update((s) => ({
      projects: [...s.projects, { id, name, active: true }],
      addResource: { ...s.addResource, projectChecks: { ...s.addResource.projectChecks, [id]: true }, newProjectName: '' },
    }));
  };
  const saveAddResource = () => {
    const a = state.addResource;
    const name = a.name.trim();
    if (!name) return;
    const id = nextId('r');
    const initials = name.split(' ').map((x) => x[0]).slice(0, 2).join('').toUpperCase();
    const checkedIds = Object.keys(a.projectChecks).filter((k) => a.projectChecks[k]);
    const newAllocs = checkedIds.map((pid) => ({ id: nextId('a'), resourceId: id, projectId: pid, pct: 20, start: TODAY_ABS_WEEK, span: 4 }));
    update((s) => ({
      resources: [...s.resources, { id, name, role: a.role, partnerName: a.partnerName.trim(), initials, active: true }],
      allocations: [...s.allocations, ...newAllocs],
      addResource: null,
    }));
  };

  /* activities */
  const selectPerson = (id) => update({ selectedPersonId: id });
  const setStatusFilter = (f) => update({ statusFilter: f });
  const toggleGroupCollapse = (key) => update((s) => ({ collapsed: { ...s.collapsed, [key]: !s.collapsed[key] } }));
  const collapseAllGroups = () => update((s) => {
    const collapsed = { none: true };
    s.projects.forEach((p) => { collapsed[p.id] = true; });
    return { collapsed };
  });
  const expandAllGroups = () => update({ collapsed: {} });
  const updateTask = (id, field, value) => update((s) => ({ tasks: s.tasks.map((t) => (t.id === id ? { ...t, [field]: value } : t)) }));
  const setTaskStatus = (id, status) => update((s) => ({
    tasks: s.tasks.map((t) => (t.id === id ? { ...t, status, completedAt: status === 'Completed' ? TODAY_ISO : t.completedAt } : t)),
  }));
  const openHistory = (key, name) => update({ historyProjectKey: key, historyProjectName: name });
  const closeHistory = () => update({ historyProjectKey: null, historyProjectName: '' });

  const mapTask = (t) => {
    const late = t.status !== 'Completed' && t.endDate < TODAY_ISO;
    return {
      id: t.id,
      title: t.title,
      priorityLabel: t.priority,
      priorityValue: t.priority,
      priorityDotStyle: `width:7px;height:7px;border-radius:50%;background:${PRIORITY_COLOR[t.priority]};display:inline-block;margin-right:5px`,
      statusValue: t.status,
      statusBadgeStyle: STATUS_STYLE[t.status] || STATUS_STYLE.New,
      startDateValue: t.startDate,
      endDateValue: t.endDate,
      dateRange: (t.startDate ? t.startDate.slice(5) : '—') + ' – ' + (t.endDate ? t.endDate.slice(5) : '—'),
      lateStyle: late ? `color:${DANGER};font-weight:600` : '',
      onPriorityChange: (e) => updateTask(t.id, 'priority', e.target.value),
      onStatusChange: (e) => setTaskStatus(t.id, e.target.value),
      onStartDateChange: (e) => updateTask(t.id, 'startDate', e.target.value),
      onEndDateChange: (e) => updateTask(t.id, 'endDate', e.target.value),
    };
  };

  /* ---------- derived render data ---------- */

  const windowStart = windowStartAbs(state.weekOffset);
  const weeks = [];
  for (let i = 0; i < VISIBLE_WEEKS; i++) {
    const abs = windowStart + i;
    const d = weekDateFromAbs(abs);
    const isToday = abs === TODAY_ABS_WEEK;
    weeks.push({
      abs, label: weekLabel(d),
      style: `flex:1;text-align:center;font-size:10px;color:${isToday ? 'var(--color-accent-700)' : 'color-mix(in srgb, var(--color-text) 55%, transparent)'};font-weight:${isToday ? '700' : '400'};padding-bottom:8px;border-bottom:2px solid ${isToday ? 'var(--color-accent-700)' : 'var(--color-divider)'}`,
    });
  }
  const startYear = weekDateFromAbs(windowStart).getUTCFullYear();
  const endYear = weekDateFromAbs(windowStart + VISIBLE_WEEKS - 1).getUTCFullYear();
  const yearLabel = startYear === endYear ? String(startYear) : `${startYear}–${endYear}`;

  const roleFiltered = state.resources.filter((r) => r.active !== false && (state.filterRole === 'all' || r.role === state.filterRole));
  const matrixRows = [];
  roleFiltered.forEach((r) => {
    const allocs = state.allocations.filter((a) => a.resourceId === r.id);
    const total = allocs.reduce((sum, a) => sum + a.pct, 0);
    const overbooked = total > 100;
    const visibleAllocs = allocs.filter((a) => state.filterProject === 'all' || a.projectId === state.filterProject);
    if (allocs.length > 0 && visibleAllocs.length === 0) return;
    matrixRows.push({
      key: 'h-' + r.id, isHeader: true, isProject: false, isAdd: false,
      name: r.name, role: r.role, initials: r.initials, avatarStyle: avatarStyle(r.role),
      showAlert: overbooked, totalLabel: total + '%',
      onClick: () => openEdit(r.id),
    });
    visibleAllocs.forEach((a) => {
      const project = state.projects.find((p) => p.id === a.projectId);
      matrixRows.push({
        key: a.id, isHeader: false, isProject: true, isAdd: false,
        projectName: project ? project.name : '—',
        trackStyle: `flex:1;position:relative;height:26px;overflow:hidden;background-color:var(--color-neutral-100);background-image:linear-gradient(to right, var(--color-divider) 1px, transparent 1px);background-size:calc(100%/${VISIBLE_WEEKS}) 100%`,
        setTrackRef: (el) => { trackRefs.current[a.id] = el; },
        blockStyle: `position:absolute;top:2px;bottom:2px;left:${((a.start - windowStart) / VISIBLE_WEEKS) * 100}%;width:${(a.span / VISIBLE_WEEKS) * 100}%;background:${overbooked ? DANGER : 'var(--color-accent-600)'};color:var(--color-bg);font-size:11px;display:flex;align-items:center;justify-content:center;cursor:grab;user-select:none`,
        pctLabel: a.pct + '%',
        onMouseDown: onBlockMouseDown(a.id),
        onResizeLeft: onResizeMouseDown(a.id, 'left'),
        onResizeRight: onResizeMouseDown(a.id, 'right'),
        onDoubleClick: () => openEdit(r.id),
      });
    });
    matrixRows.push({ key: 'add-' + r.id, isHeader: false, isProject: false, isAdd: true, addProjectClick: () => openNewAlloc({ resourceId: r.id }) });
  });

  const dialogOpen = state.editingId !== null;
  let editingResource = null;
  if (dialogOpen) {
    const r = state.resources.find((x) => x.id === state.editingId);
    const allocs = state.allocations.filter((a) => a.resourceId === state.editingId);
    const total = allocs.reduce((sum, a) => sum + (state.editValues[a.id] != null ? state.editValues[a.id] : a.pct), 0);
    editingResource = {
      name: r.name, role: r.role, initials: r.initials, avatarStyle: avatarStyle(r.role),
      sliders: allocs.map((a) => {
        const project = state.projects.find((p) => p.id === a.projectId);
        const val = state.editValues[a.id] != null ? state.editValues[a.id] : a.pct;
        return { id: a.id, name: project ? project.name : '—', value: val, valueLabel: val + '%', onChange: (e) => setSlider(a.id, e.target.value) };
      }),
      totalLabel: total + '%',
      totalRowStyle: `display:flex;justify-content:space-between;padding-top:var(--space-3);border-top:1px solid var(--color-divider);font-size:14px;color:${total > 100 ? DANGER : 'inherit'}`,
    };
  }

  const weekOptions = [];
  for (let i = -12; i <= 12; i++) weekOptions.push({ value: TODAY_ABS_WEEK + i, label: weekLabel(weekDateFromAbs(TODAY_ABS_WEEK + i)) });

  let projectMatches = [], showCreateProjectOption = false, resourceMatches = [];
  let wizardResourceName = '', wizardProjectName = '';
  if (state.newAlloc) {
    const w = state.newAlloc;
    const q = w.projectQuery.trim().toLowerCase();
    projectMatches = state.projects.filter((p) => p.active !== false && (!q || p.name.toLowerCase().includes(q))).map((p) => ({ id: p.id, name: p.name }));
    showCreateProjectOption = q.length > 0 && !state.projects.some((p) => p.name.toLowerCase() === q);
    const rq = w.resourceQuery.trim().toLowerCase();
    resourceMatches = state.resources.filter((r) => r.active !== false && (!rq || r.name.toLowerCase().includes(rq))).map((r) => ({ id: r.id, name: r.name, role: r.role }));
    if (w.resourceId) { const rr = state.resources.find((r) => r.id === w.resourceId); wizardResourceName = rr ? rr.name : ''; }
    if (w.projectId) { const pp = state.projects.find((p) => p.id === w.projectId); wizardProjectName = pp ? pp.name : ''; }
  }

  let addResProjectOptions = [];
  if (state.addResource) {
    addResProjectOptions = state.projects.map((p) => ({ id: p.id, name: p.name, checked: !!state.addResource.projectChecks[p.id], onToggle: () => toggleAddResProject(p.id) }));
  }

  const people = state.resources.filter((r) => r.active !== false).map((r) => {
    const late = state.tasks.some((t) => t.resourceId === r.id && t.status !== 'Completed' && t.endDate < TODAY_ISO);
    const selected = r.id === state.selectedPersonId;
    return {
      id: r.id, name: r.name, role: r.role, initials: r.initials, avatarStyle: avatarStyle(r.role),
      hasLate: late, onClick: () => selectPerson(r.id),
      rowStyle: `display:flex;align-items:center;gap:8px;padding:8px 6px;cursor:pointer;background:${selected ? 'var(--color-accent-100)' : 'transparent'}`,
    };
  });
  const selectedPerson = people.find((p) => p.id === state.selectedPersonId) || people[0] || { avatarStyle: '', initials: '', name: '', role: '' };

  const statusFilters = [
    { key: 'all', label: 'All' }, { key: 'New', label: 'New' }, { key: 'On Going', label: 'On Going' },
    { key: 'Blocked', label: 'Blocked' }, { key: 'Parked', label: 'Parked' },
  ].map((f) => ({
    key: f.key, label: f.label, onClick: () => setStatusFilter(f.key),
    style: `font-size:12px;padding:5px 12px;border:1px solid var(--color-divider);cursor:pointer;background:${state.statusFilter === f.key ? 'var(--color-accent)' : 'transparent'};color:${state.statusFilter === f.key ? 'var(--color-bg)' : 'inherit'}`,
  }));

  const passesFilter = (t) => state.statusFilter === 'all' || t.status === state.statusFilter;
  const personTasksAll = state.tasks.filter((t) => t.resourceId === state.selectedPersonId);
  const groupDefs = [...state.projects, { id: null, name: 'No project' }];
  const groups = groupDefs.map((p) => {
    const key = p.id || 'none';
    const all = personTasksAll.filter((t) => (p.id === null ? !t.projectId : t.projectId === p.id));
    const active = all.filter((t) => t.status !== 'Completed' && passesFilter(t)).map(mapTask);
    const history = all.filter((t) => t.status === 'Completed').map(mapTask);
    const collapsed = !!state.collapsed[key];
    return {
      key, name: p.name, active, history, count: active.length, hasHistory: history.length > 0, historyCount: history.length,
      expanded: !collapsed, chevronRotate: collapsed ? 'rotate(0deg)' : 'rotate(90deg)',
      onToggle: () => toggleGroupCollapse(key), onOpenHistory: () => openHistory(key, p.name), hasContent: all.length > 0,
    };
  }).filter((g) => g.hasContent);
  const historyTasks = state.historyProjectKey ? (groups.find((g) => g.key === state.historyProjectKey) || { history: [] }).history : [];

  const boProjects = state.projects.map((p) => {
    const assignedAllocs = state.allocations.filter((a) => a.projectId === p.id);
    const assigned = assignedAllocs.map((a) => {
      const r = state.resources.find((x) => x.id === a.resourceId);
      return { allocId: a.id, name: r ? r.name : '—', onRemove: () => removeAllocationById(a.id) };
    });
    const assignedIds = assignedAllocs.map((a) => a.resourceId);
    const availableUsers = state.resources.filter((r) => r.active !== false && !assignedIds.includes(r.id));
    return {
      id: p.id, name: p.name,
      statusLabel: p.active !== false ? 'Active' : 'Disabled',
      statusStyle: `font-size:11px;padding:2px 8px;background:${p.active !== false ? 'var(--color-accent-100)' : 'var(--color-neutral-200)'};color:${p.active !== false ? 'var(--color-accent-800)' : 'var(--color-neutral-700)'}`,
      toggleLabel: p.active !== false ? 'Disable' : 'Enable',
      onToggleActive: () => toggleProjectActive(p.id),
      onRename: (e) => renameProject(p.id, e.target.value),
      onDelete: () => deleteProject(p.id),
      assignedUsers: assigned,
      availableUsers,
      onAddUserSelect: (e) => addUserToProject(p.id, e.target.value),
    };
  });
  const boResources = state.resources.map((r) => ({
    id: r.id, name: r.name, roleValue: r.role, partnerName: r.partnerName || '',
    statusLabel: r.active !== false ? 'Active' : 'Disabled',
    statusStyle: `font-size:11px;padding:2px 8px;background:${r.active !== false ? 'var(--color-accent-100)' : 'var(--color-neutral-200)'};color:${r.active !== false ? 'var(--color-accent-800)' : 'var(--color-neutral-700)'}`,
    toggleLabel: r.active !== false ? 'Disable' : 'Enable',
    onToggleActive: () => toggleResourceActive(r.id),
    onRename: (e) => updateResourceField(r.id, 'name', e.target.value),
    onPartnerChange: (e) => updateResourceField(r.id, 'partnerName', e.target.value),
    onRoleChange: (e) => updateResourceField(r.id, 'role', e.target.value),
    onDelete: () => deleteResource(r.id),
  }));

  const navBtnStyle = (active) =>
    `text-align:left;padding:8px 10px;font-family:var(--font-body);font-size:13.5px;border:none;cursor:pointer;background:${active ? 'var(--color-accent-100)' : 'transparent'};color:${active ? 'var(--color-accent-800)' : 'inherit'};font-weight:${active ? '500' : '400'}`;

  /* ---------- render ---------- */

  return (
    <div style={sx('display:flex;min-height:100vh;background:var(--color-bg);color:var(--color-text);font-family:var(--font-body)')}>
      <aside style={sx('width:230px;flex:none;background:var(--color-surface);border-right:1px solid var(--color-divider);padding:var(--space-6) var(--space-4);display:flex;flex-direction:column;gap:var(--space-8)')}>
        <div style={sx('font-family:var(--font-heading);font-weight:600;font-size:21px;letter-spacing:-.02em')}>Briefing</div>
        <nav style={sx('display:flex;flex-direction:column;gap:var(--space-8)')}>
          <div>
            <div style={sx('font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 55%, transparent);margin-bottom:var(--space-2)')}>Module 1 — Allocation</div>
            <div style={sx('display:flex;flex-direction:column;gap:1px')}>
              <button style={sx(navBtnStyle(state.screen === 'matrix'))} onClick={goMatrix}>Allocation Matrix</button>
            </div>
          </div>
          <div>
            <div style={sx('font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 55%, transparent);margin-bottom:var(--space-2)')}>Module 2 — Activity Management</div>
            <div style={sx('display:flex;flex-direction:column;gap:1px')}>
              <button style={sx(navBtnStyle(state.screen === 'activities'))} onClick={goActivities}>Activities</button>
            </div>
          </div>
          <div>
            <div style={sx('font-size:10px;letter-spacing:.09em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 55%, transparent);margin-bottom:var(--space-2)')}>Back Office</div>
            <div style={sx('display:flex;flex-direction:column;gap:1px')}>
              <button style={sx(navBtnStyle(state.screen === 'backoffice'))} onClick={goBackoffice}>Projects & Users</button>
            </div>
          </div>
        </nav>
      </aside>

      <main style={sx('flex:1;min-width:0;padding:var(--space-8) var(--space-8) var(--space-8)')}>

        {state.screen === 'matrix' && (
          <div>
            <div style={sx('display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4);margin-bottom:var(--space-6);flex-wrap:wrap')}>
              <div>
                <h1 style={{ marginBottom: 2 }}>Allocation Matrix</h1>
                <p className="text-muted" style={{ margin: 0, fontSize: 13 }}>Each resource's projects over time — drag a block to move it, drag its edges to resize, double-click to edit</p>
              </div>
              <button className="btn btn-primary" onClick={() => openNewAlloc(null)}>+ New allocation</button>
            </div>

            <div style={sx('display:flex;align-items:center;gap:var(--space-4);margin-bottom:var(--space-4);flex-wrap:wrap')}>
              <div className="field" style={{ width: 190 }}>
                <label>Project</label>
                <select className="input" value={state.filterProject} onChange={onFilterProject}>
                  <option value="all">All projects</option>
                  {state.projects.filter((p) => p.active !== false).map((p) => <option key={p.id} value={p.id}>{p.name}</option>)}
                </select>
              </div>
              <div className="field" style={{ width: 190 }}>
                <label>Role</label>
                <select className="input" value={state.filterRole} onChange={onFilterRole}>
                  <option value="all">All roles</option>
                  {ROLE_OPTIONS.map((ro) => <option key={ro} value={ro}>{ro}</option>)}
                </select>
              </div>
            </div>

            <div className="blueprint" style={{ padding: 'var(--space-4)' }}>
              <i className="corner tl"></i><i className="corner tr"></i><i className="corner bl"></i><i className="corner br"></i>

              <div style={sx('display:flex;align-items:center;gap:8px;margin-bottom:12px;justify-content:flex-end')}>
                <button className="btn btn-secondary" onClick={goToday}>Today</button>
                <button className="btn btn-secondary" style={{ padding: '6px 10px' }} onClick={prevMonth}>‹ Previous Month</button>
                <span style={{ fontSize: 13, fontWeight: 500 }}>{yearLabel}</span>
                <button className="btn btn-secondary" style={{ padding: '6px 10px' }} onClick={nextMonth}>Next Month ›</button>
              </div>

              <div style={sx('display:flex;gap:10px;padding-left:42px')}>
                <div style={{ width: 150, flex: 'none' }}></div>
                <div style={{ flex: 1, display: 'flex' }}>
                  {weeks.map((wk) => <div key={wk.abs} style={sx(wk.style)}>{wk.label}</div>)}
                </div>
              </div>

              {matrixRows.map((row) => {
                if (row.isHeader) {
                  return (
                    <div key={row.key} style={sx('display:flex;align-items:center;gap:10px;padding:14px 0 6px;border-top:1px solid var(--color-divider);cursor:pointer')} onClick={row.onClick}>
                      <div style={sx(row.avatarStyle)}>{row.initials}</div>
                      <div style={{ minWidth: 0 }}>
                        <div style={{ fontSize: 13.5, fontWeight: 500, whiteSpace: 'nowrap' }}>{row.name}</div>
                        <div style={sx('font-size:11px;color:color-mix(in srgb, var(--color-text) 55%, transparent);white-space:nowrap')}>{row.role}</div>
                      </div>
                      {row.showAlert && <span style={sx('font-size:10px;padding:2px 7px;border:1px solid oklch(58% 0.19 27);color:oklch(58% 0.19 27)')}>Overbooked</span>}
                      <span style={sx('margin-left:auto;font-size:12px;color:color-mix(in srgb, var(--color-text) 60%, transparent)')}>Total: {row.totalLabel}</span>
                    </div>
                  );
                }
                if (row.isProject) {
                  return (
                    <div key={row.key} style={sx('display:flex;align-items:center;gap:10px;padding:3px 0 3px 42px')}>
                      <div style={sx('width:150px;flex:none;font-size:12.5px;color:color-mix(in srgb, var(--color-text) 75%, transparent)')}>{row.projectName}</div>
                      <div style={sx(row.trackStyle)} ref={row.setTrackRef}>
                        <div style={sx(row.blockStyle)} onMouseDown={row.onMouseDown} onDoubleClick={row.onDoubleClick}>
                          <div style={{ position: 'absolute', left: 0, top: 0, bottom: 0, width: 8, cursor: 'ew-resize' }} onMouseDown={row.onResizeLeft}></div>
                          {row.pctLabel}
                          <div style={{ position: 'absolute', right: 0, top: 0, bottom: 0, width: 8, cursor: 'ew-resize' }} onMouseDown={row.onResizeRight}></div>
                        </div>
                      </div>
                    </div>
                  );
                }
                return (
                  <div key={row.key} style={sx('padding:4px 0 10px 42px')}>
                    <span style={sx('font-size:12px;color:var(--color-accent-700);cursor:pointer')} onClick={row.addProjectClick}>+ Add project</span>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {state.screen === 'activities' && (
          <div style={sx('display:flex;gap:var(--space-6);align-items:flex-start')}>
            <div className="card" style={{ width: 220, flex: 'none', padding: 'var(--space-2)' }}>
              <div style={sx('display:flex;align-items:center;justify-content:space-between;padding:6px 6px 4px')}>
                <span style={sx('font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 55%, transparent)')}>People</span>
                <span style={sx('font-size:11px;color:var(--color-accent-700);cursor:pointer')} onClick={openAddResource}>+ Add</span>
              </div>
              {people.map((pp) => (
                <div key={pp.id} style={sx(pp.rowStyle)} onClick={pp.onClick}>
                  <div style={sx(pp.avatarStyle)}>{pp.initials}</div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={sx('font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis')}>{pp.name}</div>
                    <div style={sx('font-size:11px;color:color-mix(in srgb, var(--color-text) 55%, transparent);white-space:nowrap')}>{pp.role}</div>
                  </div>
                  {pp.hasLate && <span style={sx('width:7px;height:7px;border-radius:50%;background:oklch(58% 0.19 27);flex:none')}></span>}
                </div>
              ))}
            </div>

            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ marginBottom: 'var(--space-5)' }}>
                <h1 style={{ marginBottom: 2 }}>Activity Management</h1>
                <p className="text-muted" style={{ margin: 0, fontSize: 13 }}>Current week · Aug 10–16, 2026</p>
              </div>

              {state.historyProjectKey ? (
                <React.Fragment>
                  <div style={{ marginBottom: 'var(--space-4)' }}>
                    <span style={sx('font-size:13px;color:var(--color-accent-700);cursor:pointer')} onClick={closeHistory}>← Back</span>
                    <h2 style={sx('margin:10px 0 4px;color:var(--color-accent-700);font-weight:700;font-size:19px')}>History — {state.historyProjectName}</h2>
                  </div>
                  <div style={sx('display:grid;grid-template-columns:30% repeat(4,1fr);gap:10px;padding:4px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 45%, transparent)')}>
                    <span>Task</span><span>Priority</span><span>Status</span><span>CLOSED ON</span>
                  </div>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                    {historyTasks.map((t) => (
                      <div key={t.id} style={sx('display:grid;grid-template-columns:30% repeat(4,1fr);gap:10px;align-items:center;padding:8px 4px;border-bottom:1px solid color-mix(in srgb, var(--color-text) 8%, transparent)')}>
                        <div style={sx('font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis')}>{t.title}</div>
                        <span style={{ fontSize: 12, whiteSpace: 'nowrap' }}><i style={sx(t.priorityDotStyle)}></i>{t.priorityLabel}</span>
                        <span style={sx(t.statusBadgeStyle)}>Completed</span>
                        <span style={sx('font-size:12px;color:color-mix(in srgb, var(--color-text) 55%, transparent);white-space:nowrap')}>{t.dateRange}</span>
                      </div>
                    ))}
                  </div>
                </React.Fragment>
              ) : (
                <React.Fragment>
                  <div style={sx('display:flex;align-items:center;gap:8px;margin-bottom:var(--space-4);flex-wrap:wrap')}>
                    <div style={sx(selectedPerson.avatarStyle)}>{selectedPerson.initials}</div>
                    <div style={{ flex: 'none', whiteSpace: 'nowrap', marginRight: 'auto' }}>
                      <div style={{ fontSize: 14, fontWeight: 500 }}>{selectedPerson.name}</div>
                      <div style={sx('font-size:11px;color:color-mix(in srgb, var(--color-text) 55%, transparent)')}>{selectedPerson.role}</div>
                    </div>
                    <span style={sx('font-size:12px;color:var(--color-accent-700);cursor:pointer')} onClick={expandAllGroups}>Expand all</span>
                    <span style={sx('font-size:12px;color:var(--color-accent-700);cursor:pointer')} onClick={collapseAllGroups}>Collapse all</span>
                    <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                      {statusFilters.map((sf) => <span key={sf.key} style={sx(sf.style)} onClick={sf.onClick}>{sf.label}</span>)}
                    </div>
                  </div>

                  {groups.map((g) => (
                    <div key={g.key} style={sx('margin-bottom:var(--space-4);border-bottom:1px solid var(--color-divider);padding-bottom:8px')}>
                      <div style={sx('display:flex;align-items:center;gap:10px;padding:6px 0')}>
                        <span style={sx(`font-size:11px;display:inline-block;transform:${g.chevronRotate};transition:transform .15s;cursor:pointer`)} onClick={g.onToggle}>▸</span>
                        <span style={sx('color:var(--color-accent-700);font-weight:700;font-size:15px;flex:1;cursor:pointer')} onClick={g.onToggle}>{g.name}</span>
                        <span style={sx('font-size:11px;color:color-mix(in srgb, var(--color-text) 50%, transparent)')}>{g.count} active</span>
                        {g.hasHistory && <span style={sx('font-size:12px;color:var(--color-accent-700);cursor:pointer')} onClick={g.onOpenHistory}>History ({g.historyCount})</span>}
                        <button className="btn btn-secondary" style={{ padding: '3px 10px', fontSize: 11 }}>+ Add task</button>
                      </div>
                      {g.expanded && (
                        <React.Fragment>
                          <div style={sx('display:grid;grid-template-columns:30% repeat(4,1fr);gap:10px;padding:4px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 45%, transparent)')}>
                            <span></span><span>Priority</span><span>Status</span><span>Start Date</span><span>End Date</span>
                          </div>
                          <div style={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
                            {g.active.map((t) => (
                              <div key={t.id} style={sx('display:grid;grid-template-columns:30% repeat(4,1fr);gap:10px;align-items:center;padding:8px 4px;border-bottom:1px solid color-mix(in srgb, var(--color-text) 8%, transparent)')}>
                                <div style={sx('font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis')}>{t.title}</div>
                                <select className="input" style={{ width: '100%', fontSize: 12, padding: '3px 6px', minHeight: 28 }} value={t.priorityValue} onChange={t.onPriorityChange}>
                                  <option value="Low">Low</option>
                                  <option value="Medium">Medium</option>
                                  <option value="High">High</option>
                                </select>
                                <select className="input" style={{ width: '100%', fontSize: 12, padding: '3px 6px', minHeight: 28 }} value={t.statusValue} onChange={t.onStatusChange}>
                                  <option value="New">New</option>
                                  <option value="On Going">On Going</option>
                                  <option value="Blocked">Blocked</option>
                                  <option value="Parked">Parked</option>
                                  <option value="Completed">Completed</option>
                                </select>
                                <input type="date" className="input" style={{ width: '100%', fontSize: 12, padding: '3px 6px', minHeight: 28 }} value={t.startDateValue} onChange={t.onStartDateChange} />
                                <input type="date" className="input" style={{ width: '100%', fontSize: 12, padding: '3px 6px', minHeight: 28 }} value={t.endDateValue} onChange={t.onEndDateChange} />
                              </div>
                            ))}
                          </div>
                        </React.Fragment>
                      )}
                    </div>
                  ))}
                </React.Fragment>
              )}
            </div>
          </div>
        )}

        {state.screen === 'backoffice' && (
          <div>
            <h1 style={{ marginBottom: 2 }}>Back Office</h1>
            <p className="text-muted" style={{ margin: '0 0 var(--space-4) 0', fontSize: 13 }}>Manage projects, users and their assignments</p>

            <div className="seg" style={{ marginBottom: 'var(--space-5)' }}>
              <label className="seg-opt"><input type="radio" name="botab" checked={state.backofficeTab === 'projects'} onChange={setBoTabProjects} />Projects</label>
              <label className="seg-opt"><input type="radio" name="botab" checked={state.backofficeTab === 'resources'} onChange={setBoTabResources} />Resources</label>
            </div>

            {state.backofficeTab === 'projects' && (
              <React.Fragment>
                <div style={{ display: 'flex', gap: 8, marginBottom: 'var(--space-5)' }}>
                  <input className="input" placeholder="New project name" style={{ width: 280 }} value={state.newProjectNameBo} onChange={setNewProjectNameBo} />
                  <button className="btn btn-primary" onClick={addProjectBo}>+ Add project</button>
                </div>
                {boProjects.map((p) => (
                  <div key={p.id} className="blueprint" style={{ padding: 'var(--space-3)', marginBottom: 14 }}>
                    <i className="corner tl"></i><i className="corner tr"></i><i className="corner bl"></i><i className="corner br"></i>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                      <input className="input" style={{ flex: 1, minWidth: 160, fontWeight: 500 }} value={p.name} onChange={p.onRename} />
                      <span style={sx(p.statusStyle)}>{p.statusLabel}</span>
                      <button className="btn btn-secondary" onClick={p.onToggleActive}>{p.toggleLabel}</button>
                      <button className="btn btn-secondary" onClick={p.onDelete}>Delete</button>
                    </div>
                    <div style={{ marginTop: 12 }}>
                      <div style={sx('font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:color-mix(in srgb, var(--color-text) 55%, transparent);margin-bottom:6px')}>Assigned resources</div>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 8 }}>
                        {p.assignedUsers.map((u) => (
                          <span key={u.allocId} className="tag tag-neutral" style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>{u.name}<span onClick={u.onRemove} style={{ cursor: 'pointer', fontWeight: 700 }}>×</span></span>
                        ))}
                      </div>
                      <select className="input" style={{ width: 220 }} value="" onChange={p.onAddUserSelect}>
                        <option value="">+ Add a resource…</option>
                        {p.availableUsers.map((au) => <option key={au.id} value={au.id}>{au.name}</option>)}
                      </select>
                    </div>
                  </div>
                ))}
              </React.Fragment>
            )}

            {state.backofficeTab === 'resources' && (
              <React.Fragment>
                <div style={{ marginBottom: 'var(--space-5)' }}>
                  <button className="btn btn-primary" onClick={openAddResource}>+ Add resource</button>
                </div>
                {boResources.map((u) => (
                  <div key={u.id} className="blueprint" style={{ padding: 'var(--space-3)', marginBottom: 12 }}>
                    <i className="corner tl"></i><i className="corner tr"></i><i className="corner bl"></i><i className="corner br"></i>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                      <input className="input" style={{ flex: 1, minWidth: 150, fontWeight: 500 }} value={u.name} onChange={u.onRename} />
                      <select className="input" style={{ width: 160 }} value={u.roleValue} onChange={u.onRoleChange}>
                        {ROLE_OPTIONS.map((ro) => <option key={ro} value={ro}>{ro}</option>)}
                      </select>
                      <input className="input" placeholder="Partner name" style={{ width: 190 }} value={u.partnerName} onChange={u.onPartnerChange} />
                      <span style={sx(u.statusStyle)}>{u.statusLabel}</span>
                      <button className="btn btn-secondary" onClick={u.onToggleActive}>{u.toggleLabel}</button>
                      <button className="btn btn-secondary" onClick={u.onDelete}>Delete</button>
                    </div>
                  </div>
                ))}
              </React.Fragment>
            )}
          </div>
        )}

      </main>

      {dialogOpen && editingResource && (
        <div className="dialog-backdrop" onClick={closeEdit}>
          <div className="dialog" onClick={stopProp}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={sx(editingResource.avatarStyle)}>{editingResource.initials}</div>
              <div>
                <div className="dialog-title">{editingResource.name}</div>
                <div style={sx('font-size:12px;color:color-mix(in srgb, var(--color-text) 55%, transparent)')}>{editingResource.role}</div>
              </div>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)', marginTop: 'var(--space-2)' }}>
              {editingResource.sliders.map((s) => (
                <div key={s.id}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}>
                    <span>{s.name}</span>
                    <span style={{ fontWeight: 500 }}>{s.valueLabel}</span>
                  </div>
                  <input type="range" min="0" max="100" step="5" value={s.value} onChange={s.onChange} style={{ width: '100%', accentColor: 'var(--color-accent)' }} />
                </div>
              ))}
            </div>
            <div style={sx(editingResource.totalRowStyle)}>
              <span>Total allocated</span>
              <span style={{ fontWeight: 600 }}>{editingResource.totalLabel}</span>
            </div>
            <div className="dialog-actions">
              <button className="btn btn-secondary" onClick={closeEdit}>Cancel</button>
              <button className="btn btn-primary" onClick={saveEdit}>Save</button>
            </div>
          </div>
        </div>
      )}

      {state.newAlloc && (
        <div className="dialog-backdrop" onClick={closeNewAlloc}>
          <div className="dialog" onClick={stopProp} style={{ width: 'min(480px,100%)' }}>
            <div className="dialog-title">New allocation</div>

            {state.newAlloc.step === 'project' && (
              <React.Fragment>
                <div className="field"><label>Search or create a project</label>
                  <input className="input" placeholder="Type to search…" value={state.newAlloc.projectQuery} onChange={setProjectQuery} />
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 1, maxHeight: 220, overflow: 'auto' }}>
                  {projectMatches.map((p) => (
                    <div key={p.id} style={sx('padding:8px 10px;cursor:pointer;border-bottom:1px solid var(--color-divider)')} onClick={() => pickProject(p.id)}>{p.name}</div>
                  ))}
                  {showCreateProjectOption && (
                    <div style={sx('padding:8px 10px;cursor:pointer;color:var(--color-accent-700)')} onClick={createProject}>+ Create project "{state.newAlloc.projectQuery}"</div>
                  )}
                </div>
                <div className="dialog-actions"><button className="btn btn-secondary" onClick={closeNewAlloc}>Cancel</button></div>
              </React.Fragment>
            )}

            {state.newAlloc.step === 'resource' && (
              <React.Fragment>
                <div className="field"><label>Search or create a resource</label>
                  <input className="input" placeholder="Type to search…" value={state.newAlloc.resourceQuery} onChange={setResourceQuery} />
                </div>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 1, maxHeight: 180, overflow: 'auto' }}>
                  {resourceMatches.map((r) => (
                    <div key={r.id} style={sx('padding:8px 10px;cursor:pointer;border-bottom:1px solid var(--color-divider)')} onClick={() => pickResource(r.id)}>{r.name} · {r.role}</div>
                  ))}
                </div>
                <div style={{ marginTop: 8 }}>
                  <span style={sx('color:var(--color-accent-700);cursor:pointer;font-size:13px')} onClick={toggleCreateResourceForm}>+ Create new resource</span>
                  {state.newAlloc.showCreateResourceForm && (
                    <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
                      <input className="input" placeholder="Name" value={state.newAlloc.newResourceName} onChange={setNewResourceName} />
                      <select className="input" style={{ width: 150 }} value={state.newAlloc.newResourceRole} onChange={setNewResourceRole}>
                        {ROLE_OPTIONS.map((ro) => <option key={ro} value={ro}>{ro}</option>)}
                      </select>
                      <button className="btn btn-primary" onClick={createResourceInWizard}>Add</button>
                    </div>
                  )}
                </div>
                <div className="dialog-actions">
                  <button className="btn btn-secondary" onClick={backToProjectStep}>Back</button>
                  <button className="btn btn-secondary" onClick={closeNewAlloc}>Cancel</button>
                </div>
              </React.Fragment>
            )}

            {state.newAlloc.step === 'details' && (
              <React.Fragment>
                <div style={sx('font-size:13px;color:color-mix(in srgb, var(--color-text) 60%, transparent);margin-bottom:8px')}>{wizardResourceName} → {wizardProjectName}</div>
                <div style={{ marginBottom: 12 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}><span>Allocation</span><span style={{ fontWeight: 500 }}>{state.newAlloc.pct}%</span></div>
                  <input type="range" min="0" max="100" step="5" value={state.newAlloc.pct} onChange={setAllocPct} style={{ width: '100%', accentColor: 'var(--color-accent)' }} />
                </div>
                <div style={{ display: 'flex', gap: 10 }}>
                  <div className="field" style={{ flex: 1 }}><label>Start week</label>
                    <select className="input" value={state.newAlloc.start} onChange={setAllocStart}>
                      {weekOptions.map((mo) => <option key={mo.value} value={mo.value}>{mo.label}</option>)}
                    </select>
                  </div>
                  <div className="field" style={{ flex: 1 }}><label>End week</label>
                    <select className="input" value={state.newAlloc.end} onChange={setAllocEnd}>
                      {weekOptions.map((mo) => <option key={mo.value} value={mo.value}>{mo.label}</option>)}
                    </select>
                  </div>
                </div>
                <div className="dialog-actions">
                  <button className="btn btn-secondary" onClick={backFromDetails}>Back</button>
                  <button className="btn btn-secondary" onClick={closeNewAlloc}>Cancel</button>
                  <button className="btn btn-primary" onClick={saveNewAlloc}>Save</button>
                </div>
              </React.Fragment>
            )}
          </div>
        </div>
      )}

      {state.addResource && (
        <div className="dialog-backdrop" onClick={closeAddResource}>
          <div className="dialog" onClick={stopProp}>
            <div className="dialog-title">Add resource</div>
            <div className="field"><label>Name</label><input className="input" value={state.addResource.name} onChange={setAddResName} /></div>
            <div className="field"><label>Role</label>
              <select className="input" value={state.addResource.role} onChange={setAddResRole}>
                {ROLE_OPTIONS.map((ro) => <option key={ro} value={ro}>{ro}</option>)}
              </select>
            </div>
            <div className="field"><label>Partner name (optional)</label><input className="input" value={state.addResource.partnerName} onChange={setAddResPartner} /></div>
            <div className="field"><label>Assign to projects</label>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
                {addResProjectOptions.map((po) => (
                  <label key={po.id} style={{ display: 'flex', alignItems: 'center', gap: 8, fontSize: 13, cursor: 'pointer' }}>
                    <input type="checkbox" checked={po.checked} onChange={po.onToggle} style={{ width: 15, height: 15, accentColor: 'var(--color-accent)' }} />
                    {po.name}
                  </label>
                ))}
              </div>
              <div style={{ display: 'flex', gap: 8, marginTop: 8 }}>
                <input className="input" placeholder="New project name" value={state.addResource.newProjectName} onChange={setAddResNewProjectName} />
                <button className="btn btn-secondary" onClick={addNewProjectInAddResource}>+ Add</button>
              </div>
            </div>
            <div className="dialog-actions">
              <button className="btn btn-secondary" onClick={closeAddResource}>Cancel</button>
              <button className="btn btn-primary" onClick={saveAddResource}>Save</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
