/* ServiceBridge — Timeline Planning · page sections + 3 timeline layouts */
const { Card, Table, Tag, Statistic, Alert, Icon, Avatar, Button } = window;
const sbStyles = window.sbStyles;

/* ---------- tiny shared bits ---------- */
function Wordmark() {
  return (
    React.createElement('div', { style: sbStyles.wordmark },
      React.createElement('div', { style: sbStyles.glyph },
        React.createElement('svg', { viewBox: '0 0 24 24', width: 18, height: 18, fill: 'none' },
          React.createElement('path', {
            d: 'M12 2c-3.9 0-7 3-7 6.8 0 4.6 5.7 11.4 6.4 12.2.3.4.9.4 1.2 0C13.3 20.2 19 13.4 19 8.8 19 5 15.9 2 12 2Z',
            fill: '#09B0ED'
          }),
          React.createElement('circle', { cx: 12, cy: 8.8, r: 2.6, fill: '#fff' })
        )
      ),
      React.createElement('span', { style: { letterSpacing: '.02em' } },
        React.createElement('b', { style: { fontWeight: 700 } }, 'TITAN'),
        React.createElement('span', { style: { color: '#09B0ED', fontWeight: 700 } }, 'GPS')
      )
    )
  );
}

function StatusTag({ status }) {
  const s = window.STATUS[status];
  return React.createElement(Tag, { color: s.color }, s.label);
}

function OwnerBadge({ owner }) {
  const c = owner === 'Dev' ? '#688DAF' : '#09B0ED';
  return React.createElement('span', { style: sbStyles.owner },
    React.createElement('span', { style: { ...sbStyles.ownerDot, background: c } }),
    owner
  );
}

/* section frame: accent bar + title + caption, optional enclosing container */
function Frame({ title, caption, accent, container, children }) {
  return (
    React.createElement('section', { style: sbStyles.frame },
      React.createElement('div', { style: sbStyles.frameHead },
        React.createElement('div', { style: { ...sbStyles.frameBar, background: accent || '#142E47' } }),
        React.createElement('div', null,
          React.createElement('div', { style: sbStyles.frameTitle }, title),
          React.createElement('div', { style: sbStyles.frameCaption }, caption)
        )
      ),
      container
        ? React.createElement('div', { style: sbStyles.frameContainer }, children)
        : children
    )
  );
}

function PhaseLegend() {
  return (
    React.createElement('div', { style: sbStyles.legend },
      window.PHASES.map((p) =>
        React.createElement('div', { key: p.key, style: sbStyles.legendItem },
          React.createElement('span', { style: { ...sbStyles.swatch, background: p.color } }),
          React.createElement('span', { style: { fontWeight: 500 } }, p.label)
        )
      )
    )
  );
}

/* ---------- HERO ---------- */
function Hero() {
  return (
    React.createElement('header', { style: sbStyles.hero },
      React.createElement('div', { style: sbStyles.heroTop },
        React.createElement(Wordmark, null),
        React.createElement('span', { style: sbStyles.heroLiving },
          React.createElement('span', { style: sbStyles.livingDot }), 'Living tracker · updated weekly')
      ),
      React.createElement('div', { style: sbStyles.heroKicker }, 'Map Refactoring Project'),
      React.createElement('h1', { style: sbStyles.heroTitle }, 'Checklist/Prioritization Of Core UI Elements & Key Functionalities'),
      React.createElement('p', { style: sbStyles.heroSub },
        'Estimated effort and schedule for each design deliverable through the consolidation build — shared between the UX and Dev teams.'),
      React.createElement('div', { style: sbStyles.metaRow },
        [
          ['Owner', 'Jocelyn Gilbertson Kukowski (Product Designer for TitanGPS)'],
          ['Window', React.createElement('span', null,
            React.createElement('div', { style: { fontSize: 13, fontWeight: 700, color: '#56cdf2', marginBottom: 1 } }, '6 Months'),
            React.createElement('div', null, 'Mid May – Mid November')
          )],
          ['Deliverables', String(window.DELIVERABLES.length)],
          ['Status', 'In progress'],
        ].map(([k, v]) =>
          React.createElement('div', { key: k, style: sbStyles.metaItem },
            React.createElement('div', { style: sbStyles.metaLabel }, k),
            React.createElement('div', { style: sbStyles.metaValue }, v)
          )
        )
      )
    )
  );
}

/* ---------- SCOPE & OVERVIEW ---------- */
function Overview() {
  const stats = [
    { value: window.grandTotal(), suffix: ' d', label: 'Total estimated effort' },
    { value: window.designSum(),  suffix: ' d', label: 'Remaining UX design days' },
    { value: window.weeksRemaining(), suffix: ' wk', label: 'Project time remaining' },
  ];
  return (
    React.createElement(Card, { title: 'Project Scope & Overview', style: { marginBottom: 20 } },
      React.createElement('p', { style: { marginTop: 0, color: 'rgba(0,0,0,.65)', maxWidth: 820, lineHeight: 1.6 } },
        'Each deliverable is estimated across four phases — an initial design pass, a revision after dev and UX alignment, a final revision, and the time for the dev team to build it. The schedule below sequences those phases across the project window so both teams can plan capacity and dependencies.'),
      React.createElement('div', { style: sbStyles.statsRow },
        stats.map((s) =>
          React.createElement('div', { key: s.label, style: sbStyles.statBox },
            React.createElement(Statistic, s)
          )
        )
      )
    )
  );
}

/* date/time stamp formatter for sign-offs */
const fmtSignoff = (ms) => new Date(ms).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });
/* short date for phase completions */
const fmtDay = (ms) => new Date(ms).toLocaleString('en-US', { month: 'short', day: 'numeric' });
/* whole calendar days between two timestamps (never negative) */
const daysBetween = (a, b) => Math.max(0, Math.round((b - a) / 86400000));

/* a single sign-off checkbox + timestamp + days-since-previous-step */
function SignOff({ done, ts, prevTs, accent, label, onToggle }) {
  const elapsed = (done && ts && prevTs != null) ? daysBetween(prevTs, ts) : null;
  return React.createElement('div', { style: sbStyles.soCell },
    React.createElement('button', {
      type: 'button', className: 'so-box', onClick: onToggle, 'aria-pressed': !!done,
      title: done ? ('Signed off ' + fmtSignoff(ts) + ' — click to clear') : ('Mark ' + label + ' complete'),
      style: { ...sbStyles.soBox, ...(done ? { background: accent, border: '1.5px solid ' + accent } : null) }
    }, done ? React.createElement(Icon, { name: 'check', style: { color: '#fff', width: 12, height: 12 } }) : null),
    React.createElement('div', { style: sbStyles.soTs },
      done
        ? React.createElement(React.Fragment, null,
            fmtSignoff(ts),
            elapsed != null ? React.createElement('span', { style: { ...sbStyles.phaseElapsed, marginLeft: 4 } }, '+' + elapsed + 'd') : null)
        : React.createElement('span', { style: sbStyles.soEmpty }, '—'))
  );
}

/* a phase checkbox + estimate, plus the actual completion date and the number
   of days elapsed since the previous phase was completed (green +Nd). */
function PhaseCell({ value, done, ts, prevTs, onToggle, label }) {
  const elapsed = (done && ts && prevTs != null) ? daysBetween(prevTs, ts) : null;
  return React.createElement('div', { style: sbStyles.phaseCellWrap },
    React.createElement('div', { style: sbStyles.phaseCell },
      React.createElement('button', {
        type: 'button', className: 'phase-box', onClick: onToggle, 'aria-pressed': !!done,
        title: done ? ('Done ' + fmtDay(ts) + ' — click to clear') : ('Mark done — ' + label),
        style: { ...sbStyles.phaseBox, ...(done ? sbStyles.phaseBoxOn : null) }
      }, done ? React.createElement(Icon, { name: 'check', style: { color: '#fff', width: 10, height: 10 } }) : null),
      React.createElement('span', { style: sbStyles.estCell }, value, React.createElement('span', { style: sbStyles.estUnit }, 'd'))),
    done ? React.createElement('div', { style: sbStyles.phaseActual },
      React.createElement('span', null, fmtDay(ts)),
      elapsed != null ? React.createElement('span', { style: sbStyles.phaseElapsed }, '+' + elapsed + 'd') : null
    ) : null
  );
}

/* ===========================================================
   OPTION A — Estimate table (source of truth + live sign-off)
   =========================================================== */
const SIGNOFF_KEY = 'sb_signoff_v5';
const STATUS_KEY = 'sb_status_v2';
const PHASE_KEY = 'sb_phase_v3';
const LINKS_KEY = 'sb_links_v1';
/* shared links store — a Pages Function backed by KV. Project-wide route,
   so it works no matter which sub-path this demo is served from. */
const LINKS_API = '/api/titan-links';
const SIGNOFF_SEED = {
  /* start fresh — nothing pre-signed */
};

/* shared sign-off store — lifted to App, passed to both the table and the calendar */
function useSignoff() {
  const [store, setStore] = React.useState(() => {
    try { const raw = localStorage.getItem(SIGNOFF_KEY); if (raw) return JSON.parse(raw); } catch (e) {}
    return SIGNOFF_SEED;
  });
  React.useEffect(() => {
    try { localStorage.setItem(SIGNOFF_KEY, JSON.stringify(store)); } catch (e) {}
  }, [store]);
  const getTs = (id, kind) => (store[id] && store[id][kind]) || null;
  const toggle = (id, kind) => setStore((prev) => {
    const cur = prev[id] || {};
    return { ...prev, [id]: { ...cur, [kind]: cur[kind] ? null : Date.now() } };
  });
  /* set a sign-off to a specific date (or null to clear) — used for back-dating prior work */
  const setTs = (id, kind, ms) => setStore((prev) => {
    const cur = prev[id] || {};
    return { ...prev, [id]: { ...cur, [kind]: ms } };
  });

  /* status overrides — e.g. the “Start” action flips a row to In progress */
  const [statuses, setStatuses] = React.useState(() => {
    try { const raw = localStorage.getItem(STATUS_KEY); if (raw) return JSON.parse(raw); } catch (e) {}
    return {};
  });
  React.useEffect(() => {
    try { localStorage.setItem(STATUS_KEY, JSON.stringify(statuses)); } catch (e) {}
  }, [statuses]);
  const getStatus = (id) => statuses[id] || null;
  const setStatus = (id, s) => setStatuses((prev) => ({ ...prev, [id]: s }));

  /* per-phase completion checkboxes (Initial / Rev / Dev build) */
  const [phases, setPhases] = React.useState(() => {
    try { const raw = localStorage.getItem(PHASE_KEY); if (raw) return JSON.parse(raw); } catch (e) {}
    return {};
  });
  React.useEffect(() => {
    try { localStorage.setItem(PHASE_KEY, JSON.stringify(phases)); } catch (e) {}
  }, [phases]);
  const getPhase = (id, k) => !!(phases[id] && phases[id][k]);
  const getPhaseTs = (id, k) => (phases[id] && phases[id][k]) || null;
  const togglePhase = (id, k) => setPhases((prev) => {
    const cur = prev[id] || {};
    return { ...prev, [id]: { ...cur, [k]: cur[k] ? null : Date.now() } };
  });

  /* per-deliverable design links (Figma etc.) — an array of { name, url } per id.
     These are SHARED across every viewer: the document lives in KV behind
     /api/titan-links. localStorage is only an instant-paint cache + offline
     fallback, so the table still works if the API/binding isn't reachable. */
  const [links, setLinks] = React.useState(() => {
    try { const raw = localStorage.getItem(LINKS_KEY); if (raw) return JSON.parse(raw); } catch (e) {}
    return {};
  });

  /* pull the shared links document so everyone sees the same set */
  const loadLinks = React.useCallback(() => {
    fetch(LINKS_API, { headers: { accept: 'application/json' } })
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => {
        if (!data || typeof data !== 'object') return;
        const shared = data.links && typeof data.links === 'object' ? data.links : {};
        setLinks(shared);
        try { localStorage.setItem(LINKS_KEY, JSON.stringify(shared)); } catch (e) {}
      })
      .catch(() => {}); /* no binding / offline → keep the localStorage copy */
  }, []);

  React.useEffect(() => {
    loadLinks();
    /* refresh when the tab regains focus so teammates' additions show up */
    const onFocus = () => loadLinks();
    window.addEventListener('focus', onFocus);
    return () => window.removeEventListener('focus', onFocus);
  }, [loadLinks]);

  /* write the whole links document back: cache locally + push to the shared store */
  const persistLinks = (next) => {
    try { localStorage.setItem(LINKS_KEY, JSON.stringify(next)); } catch (e) {}
    fetch(LINKS_API, {
      method: 'PUT',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ links: next }),
    }).catch(() => {}); /* fire-and-forget; localStorage already holds the copy */
    return next;
  };

  const getLinks = (id) => links[id] || [];
  const addLink = (id, link) => setLinks((prev) => persistLinks({ ...prev, [id]: [...(prev[id] || []), link] }));
  const updateLink = (id, idx, link) => setLinks((prev) => {
    const arr = [...(prev[id] || [])]; arr[idx] = link;
    return persistLinks({ ...prev, [id]: arr });
  });
  const removeLink = (id, idx) => setLinks((prev) => {
    const arr = [...(prev[id] || [])]; arr.splice(idx, 1);
    return persistLinks({ ...prev, [id]: arr });
  });

  return { store, getTs, toggle, setTs, getStatus, setStatus, getPhase, getPhaseTs, togglePhase, getLinks, addLink, updateLink, removeLink };
}

/* per-deliverable design links — named Figma (or any) links, add/edit/remove inline */
function LinksCell({ links, onAdd, onUpdate, onRemove }) {
  const [editing, setEditing] = React.useState(null); /* null | 'new' | index */
  const [name, setName] = React.useState('');
  const [url, setUrl] = React.useState('');

  const normalize = (u) => {
    const t = (u || '').trim();
    if (!t) return '';
    return /^https?:\/\//i.test(t) ? t : 'https://' + t;
  };
  const open = (mode) => {
    if (mode === 'new') { setName(''); setUrl(''); }
    else { setName(links[mode].name); setUrl(links[mode].url); }
    setEditing(mode);
  };
  const save = () => {
    const u = normalize(url);
    if (!u) return;
    const link = { name: (name.trim() || 'Figma link'), url: u };
    if (editing === 'new') onAdd(link); else onUpdate(editing, link);
    setEditing(null);
  };

  if (editing !== null) {
    return React.createElement('div', { style: sbStyles.linkForm },
      React.createElement('input', { style: sbStyles.linkInput, placeholder: 'Link name (e.g. Flows v2)', value: name,
        onChange: (e) => setName(e.target.value), autoFocus: true }),
      React.createElement('input', { style: sbStyles.linkInput, placeholder: 'Paste Figma URL', value: url,
        onChange: (e) => setUrl(e.target.value),
        onKeyDown: (e) => { if (e.key === 'Enter') save(); if (e.key === 'Escape') setEditing(null); } }),
      React.createElement('div', { style: sbStyles.linkFormBtns },
        React.createElement(Button, { size: 'sm', type: 'primary', onClick: save }, 'Save'),
        React.createElement(Button, { size: 'sm', onClick: () => setEditing(null) }, 'Cancel'),
        (editing !== 'new') ? React.createElement('button', { type: 'button', style: sbStyles.linkDel,
          onClick: () => { onRemove(editing); setEditing(null); } }, 'Remove') : null));
  }

  return React.createElement('div', { style: sbStyles.linksWrap },
    links.map((l, i) =>
      React.createElement('div', { key: i, style: sbStyles.linkChip },
        React.createElement('a', { href: l.url, target: '_blank', rel: 'noopener noreferrer', style: sbStyles.linkChipA, title: l.url },
          React.createElement('span', { style: sbStyles.linkChipDot }),
          React.createElement('span', { style: sbStyles.linkChipName }, l.name)),
        React.createElement('button', { type: 'button', style: sbStyles.linkEdit, title: 'Edit link', onClick: () => open(i) },
          React.createElement(Icon, { name: 'edit', style: { width: 11, height: 11 } })))),
    React.createElement('button', { type: 'button', style: sbStyles.linkAdd, onClick: () => open('new') },
      React.createElement(Icon, { name: 'plus', style: { width: 11, height: 11 } }), 'Add link'));
}

function TableView({ getTs, toggle, getStatus, setStatus, getPhase, getPhaseTs, togglePhase, getLinks, addLink, updateLink, removeLink }) {
  const estHead = (p) => React.createElement('span', { style: sbStyles.estHead },
    React.createElement('span', { style: { ...sbStyles.swatchSm, background: p.color } }), p.short);
  const soHead = (label, color) => React.createElement('span', { style: sbStyles.estHead },
    React.createElement('span', { style: { ...sbStyles.swatchSm, background: color, borderRadius: '50%' } }), label);
  const estCell = (v) => React.createElement('span', { style: sbStyles.estCell }, v, React.createElement('span', { style: sbStyles.estUnit }, 'd'));

  const phaseCol = (p, idx) => {
    const prevKey = idx > 0 ? window.PHASES[idx - 1].key : null;
    return { key: p.key, dataIndex: p.key, title: estHead(p), align: 'center', width: 100, render: (v, r) =>
      React.createElement(PhaseCell, { value: v, done: getPhase(r.id, p.key), ts: getPhaseTs(r.id, p.key), prevTs: prevKey ? getPhaseTs(r.id, prevKey) : null, label: p.label, onToggle: () => togglePhase(r.id, p.key) }) };
  };
  const designCol = { key: 'designdone', dataIndex: 'id', title: soHead('Design done', '#09B0ED'), align: 'center', width: 124, render: (_, r) =>
    React.createElement(SignOff, { done: !!getTs(r.id, 'design'), ts: getTs(r.id, 'design'), prevTs: getPhaseTs(r.id, 'revisedB'), accent: '#09B0ED', label: 'design', onToggle: () => toggle(r.id, 'design') }) };
  const devCol = { key: 'devdone', dataIndex: 'id', title: soHead('Dev done', '#142E47'), align: 'center', width: 124, render: (_, r) =>
    React.createElement(SignOff, { done: !!getTs(r.id, 'dev'), ts: getTs(r.id, 'dev'), prevTs: getTs(r.id, 'design'), accent: '#142E47', label: 'dev', onToggle: () => toggle(r.id, 'dev') }) };

  /* who is actively working on it right now, derived from sign-offs:
     design signed off → Dev has it; dev signed off → complete; else Design/UX */
  const currentOwner = (id) => {
    if (getTs(id, 'dev')) return 'done';
    if (getTs(id, 'design')) return 'Dev';
    return 'UX';
  };

  /* both sign-offs complete → Done, otherwise any manual override, otherwise base */
  const resolveStatus = (r) => (getTs(r.id, 'design') && getTs(r.id, 'dev')) ? 'done' : (getStatus(r.id) || r.status);

  const startCol = { key: 'start', dataIndex: 'id', title: 'Start', align: 'center', width: 92, render: (_, r) => {
    const s = resolveStatus(r);
    if (s === 'done') return React.createElement('span', { style: sbStyles.startDone }, React.createElement(Icon, { name: 'check', style: { width: 12, height: 12 } }), 'Done');
    if (s === 'active') return React.createElement('span', { style: sbStyles.startedTag }, 'Started');
    return React.createElement(Button, { size: 'sm', type: 'primary', onClick: () => setStatus(r.id, 'active') }, 'Start');
  } };

  const columns = [
    startCol,
    { key: 'name', dataIndex: 'name', title: 'Deliverable', width: 300, render: (v, r) =>
      React.createElement('div', null,
        React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: 8 } },
          React.createElement('span', { style: sbStyles.rowNum }, r.id),
          React.createElement('span', { style: { fontWeight: 500 } }, v)),
        React.createElement('div', { style: sbStyles.rowNote }, r.note)) },
    { key: 'links', dataIndex: 'id', title: 'Figma / design links', width: 220, render: (_, r) =>
      React.createElement(LinksCell, {
        links: getLinks(r.id),
        onAdd: (l) => addLink(r.id, l),
        onUpdate: (i, l) => updateLink(r.id, i, l),
        onRemove: (i) => removeLink(r.id, i)
      }) },
    { key: 'owner', dataIndex: 'id', title: 'Current owner', width: 112, render: (_, r) => {
      const o = currentOwner(r.id);
      if (o === 'done') return React.createElement('span', { style: sbStyles.startDone }, React.createElement(Icon, { name: 'check', style: { width: 12, height: 12 } }), 'Complete');
      return React.createElement(OwnerBadge, { owner: o });
    } },
    phaseCol(window.PHASES[0], 0),   /* Initial */
    phaseCol(window.PHASES[1], 1),   /* Rev · align */
    phaseCol(window.PHASES[2], 2),   /* Rev · final */
    designCol,                    /* Design done */
    { key: 'total', dataIndex: 'id', title: 'Total', align: 'center', width: 66, render: (_, r) =>
      React.createElement('span', { style: sbStyles.totalCell }, window.rowTotal(r), 'd') },
    { key: 'status', dataIndex: 'status', title: 'Status', width: 240, render: (v, r) => {
      const s = resolveStatus(r);
      const onHold = r.hold && s !== 'done';
      return React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: 5, alignItems: 'flex-start' } },
        React.createElement('div', { style: { display: 'flex', gap: 5, flexWrap: 'wrap' } },
          React.createElement(StatusTag, { status: s }),
          onHold ? React.createElement(Tag, { color: 'orange' }, 'On hold') : null),
        onHold ? React.createElement('div', { style: sbStyles.holdNoteStatus },
          React.createElement('span', { style: sbStyles.holdNoteLabel }, 'Reason'),
          React.createElement('span', null, r.hold)) : null);
    } },
  ];

  const N = window.DELIVERABLES.length;
  const designDone = window.DELIVERABLES.filter((d) => getTs(d.id, 'design')).length;
  const devDone = window.DELIVERABLES.filter((d) => getTs(d.id, 'dev')).length;
  const pill = (label, color, n) => React.createElement('div', { style: sbStyles.soPill },
    React.createElement('span', { style: { ...sbStyles.swatchSm, background: color, borderRadius: '50%' } }),
    React.createElement('span', null, label),
    React.createElement('div', { style: sbStyles.soPillBar },
      React.createElement('div', { style: { ...sbStyles.soPillFill, width: (n / N * 100) + '%', background: color } })),
    React.createElement('b', { style: { fontVariantNumeric: 'tabular-nums' } }, n + '/' + N));

  /* one labeled section per group, with its own phase subtotals */
  const section = (g) => {
    const rows = window.byGroup(g.key);
    return React.createElement('div', { key: g.key, style: sbStyles.tGroup },
      React.createElement('div', { style: sbStyles.tGroupHead },
        React.createElement('span', { style: { ...sbStyles.tGroupBar, background: g.accent } }),
        React.createElement('span', { style: sbStyles.tGroupLabel }, g.label),
        React.createElement('span', { style: sbStyles.tGroupCount }, rows.length + ' items'),
        React.createElement('span', { style: sbStyles.tGroupCap }, g.caption),
        React.createElement('span', { style: sbStyles.tGroupSub }, window.grandTotal(rows) + 'd')
      ),
      React.createElement('div', { style: sbStyles.tScroll },
        React.createElement(Table, { columns, dataSource: rows })),
      React.createElement('div', { style: sbStyles.subTotals },
        React.createElement('span', { style: { color: 'rgba(0,0,0,.45)' } }, g.label + ' subtotal'),
        React.createElement('div', { style: sbStyles.totalsChips },
          window.PHASES.map((p) =>
            React.createElement('span', { key: p.key, style: sbStyles.totalsChip },
              React.createElement('span', { style: { ...sbStyles.swatchSm, background: p.color } }),
              p.short, React.createElement('b', { style: { marginLeft: 6 } }, window.phaseSum(p.key, rows) + 'd'))),
          React.createElement('span', { style: { ...sbStyles.grandChip, background: g.accent } }, 'Subtotal ', React.createElement('b', null, window.grandTotal(rows) + 'd'))
        )
      )
    );
  };

  return (
    React.createElement('div', null,
      React.createElement('div', { style: sbStyles.soProgress },
        React.createElement('span', { style: sbStyles.soHint },
          React.createElement(Icon, { name: 'edit', style: { width: 13, height: 13, color: 'rgba(0,0,0,.4)' } }),
          'Tap a box to mark it done — the date stamps automatically, and the green +Nd shows days elapsed since the previous step. Saved to your browser.'),
        React.createElement('div', { style: { display: 'flex', gap: 10, flexWrap: 'wrap' } },
          pill('Design', '#09B0ED', designDone))),
      window.GROUPS.map((g, i) => i === 0
        ? section(g)
        : React.createElement(React.Fragment, { key: 'sep-' + g.key },
            React.createElement('div', { style: sbStyles.groupDivider }),
            section(g))),
      React.createElement('div', { style: sbStyles.totalsBar },
        React.createElement('span', { style: { color: 'rgba(0,0,0,.45)' } }, 'All deliverables · phase totals'),
        React.createElement('div', { style: sbStyles.totalsChips },
          window.PHASES.map((p) =>
            React.createElement('span', { key: p.key, style: sbStyles.totalsChip },
              React.createElement('span', { style: { ...sbStyles.swatchSm, background: p.color } }),
              p.short, React.createElement('b', { style: { marginLeft: 6 } }, window.phaseSum(p.key) + 'd'))
          ),
          React.createElement('span', { style: sbStyles.grandChip }, 'Grand total ', React.createElement('b', null, window.grandTotal() + 'd'))
        )
      )
    )
  );
}

/* ===========================================================
   OPTION B — Gantt cascade
   =========================================================== */
function GanttView() {
  const pct = (w) => (w / window.AXIS_WEEKS) * 100;
  const todayWeek = 1.15; // Jun 9
  return (
    React.createElement('div', { style: sbStyles.gantt },
      React.createElement('div', { style: sbStyles.gRow },
        React.createElement('div', { style: sbStyles.gLabelHead }, 'Deliverable'),
        React.createElement('div', { style: sbStyles.gAxis },
          window.MONTH_BANDS.map((b) =>
            React.createElement('div', { key: b.m, style: { ...sbStyles.gMonth, left: pct(b.from) + '%', width: pct(b.to - b.from) + '%' } }, b.m)
          ),
          React.createElement('div', { style: { ...sbStyles.today, left: pct(todayWeek) + '%' } },
            React.createElement('span', { style: sbStyles.todayTag }, 'Today'))
        )
      ),
      window.DELIVERABLES.map((d) => {
        const total = window.rowTotal(d);
        return React.createElement('div', { key: d.id, style: sbStyles.gRow },
          React.createElement('div', { style: sbStyles.gLabel },
            React.createElement('span', { style: sbStyles.rowNum }, d.id),
            React.createElement('span', { style: { overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' } }, d.name)),
          React.createElement('div', { style: sbStyles.gTrack },
            window.MONTH_BANDS.map((b) =>
              React.createElement('div', { key: b.m, style: { ...sbStyles.gGrid, left: pct(b.from) + '%' } })),
            React.createElement('div', { style: { ...sbStyles.today, left: pct(todayWeek) + '%', zIndex: 1 } }),
            React.createElement('div', { style: { ...sbStyles.gBar, left: pct(d.start) + '%', width: pct(d.span) + '%' } },
              window.PHASES.map((p) =>
                React.createElement('div', {
                  key: p.key,
                  title: p.label + ': ' + d[p.key] + 'd',
                  style: { flex: d[p.key], background: p.color }
                })
              ),
              React.createElement('span', { style: sbStyles.gBarLabel }, total + 'd')
            )
          )
        );
      })
    )
  );
}

/* ===========================================================
   OPTION C — Monthly roadmap
   =========================================================== */
function RoadmapView() {
  return (
    React.createElement('div', { style: sbStyles.roadmap },
      window.MONTHS.map((m) => {
        const items = window.DELIVERABLES.filter((d) => d.month === m);
        const monthDays = items.reduce((s, d) => s + window.rowTotal(d), 0);
        return React.createElement('div', { key: m, style: sbStyles.rmCol },
          React.createElement('div', { style: sbStyles.rmHead },
            React.createElement('span', { style: sbStyles.rmMonth }, m),
            React.createElement('span', { style: sbStyles.rmCount }, monthDays ? monthDays + 'd' : '—')),
          React.createElement('div', { style: sbStyles.rmStack },
            items.length ? items.map((d) =>
              React.createElement('div', { key: d.id, style: sbStyles.rmCard },
                React.createElement('div', { style: sbStyles.rmCardTop },
                  React.createElement('span', { style: sbStyles.rowNum }, d.id),
                  React.createElement(StatusTag, { status: d.status })),
                React.createElement('div', { style: sbStyles.rmName }, d.name),
                React.createElement('div', { style: sbStyles.rmMini },
                  window.PHASES.map((p) =>
                    React.createElement('span', { key: p.key, style: sbStyles.rmMiniSeg, title: p.label + ': ' + d[p.key] + 'd' },
                      React.createElement('span', { style: { ...sbStyles.swatchSm, background: p.color } }),
                      d[p.key] + 'd'))
                ),
                React.createElement('div', { style: sbStyles.rmFoot },
                  React.createElement(OwnerBadge, { owner: d.owner }),
                  React.createElement('span', { style: { fontWeight: 600 } }, window.rowTotal(d) + 'd total'))
              )
            ) : React.createElement('div', { style: sbStyles.rmEmpty }, 'No deliverables')
          )
        );
      })
    )
  );
}

Object.assign(window, { Hero, Overview, Frame, PhaseLegend, TableView, StatusTag, OwnerBadge, useSignoff });
