<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<script src="store.js"></script>
<style>
  @keyframes sheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
  @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
  .rm-scroll::-webkit-scrollbar { width: 0; height: 0; }
  .rm-root button, .rm-root input, .rm-root textarea { font-family: inherit; }
  .rm-root {
    --sans:'IBM Plex Sans','Segoe UI',sans-serif; --mono:'IBM Plex Mono',monospace;
    --grad1:#1a3c5e44; --grad2:#27496b33;
    --base:#0b1118; --panel:#111a27; --elev:#152233; --input:#0d1622; --hover:#1b2a3a;
    --border:#263548; --bstrong:#35506a; --divider:#1c2735;
    --t1:#e5edf5; --t2:#c7d3e0; --t3:#8ea2b7; --t4:#70859b;
    --accent:#3b82c4; --accentlight:#93c5fd; --danger:#e06c6c; --money:#6ee7b7;
    --shadow-card:0 14px 26px rgba(2,12,24,0.28), inset 0 1px 0 #ffffff07;
    --nav-bg:#0d1622cc;
  }
  .rm-root[data-theme="light"] {
    --grad1:#3b82c41c; --grad2:#27496b10;
    --base:#eaeef3; --panel:#ffffff; --elev:#f4f7fb; --input:#eef2f7; --hover:#e6ecf4;
    --border:#d6dde7; --bstrong:#b6c3d4; --divider:#e8edf3;
    --t1:#16202c; --t2:#33414f; --t3:#5a6b7d; --t4:#84909e;
    --accent:#3b82c4; --accentlight:#1f6fb8; --danger:#c0322f; --money:#057a55;
    --shadow-card:0 8px 20px rgba(40,70,110,0.10), inset 0 1px 0 #ffffff;
    --nav-bg:#ffffffd9;
  }
</style>
</helmet>
<div class="rm-root" data-theme="{{ themeAttr }}" style="position:absolute; inset:0; background:radial-gradient(900px 460px at 12% -8%, var(--grad1), transparent 60%), radial-gradient(760px 380px at 92% -2%, var(--grad2), transparent 58%), var(--base); display:flex; flex-direction:column; font-family:var(--sans); color:var(--t1); letter-spacing:0.01em; overflow:hidden;">

  <!-- status bar -->
  <div style="height:46px; flex:none; display:flex; align-items:flex-end; justify-content:space-between; padding:0 24px 6px; font-family:var(--mono); font-size:13px; color:var(--t2);">
    <span>9:41</span>
    <span style="display:flex; gap:6px; align-items:center; font-size:11px; letter-spacing:0.02em;">5G ▮▮▮▯ 84%</span>
  </div>

  <!-- top bar -->
  <div style="flex:none; height:52px; display:flex; align-items:center; justify-content:space-between; padding:0 16px; border-bottom:1px solid var(--border);">
    <span style="font-family:var(--mono); font-weight:600; font-size:15px; letter-spacing:0.04em; color:var(--t1);">·Ten31·</span>
    <div style="display:flex; align-items:center; gap:10px;">
      <button onClick="{{ toggleTheme }}" aria-label="Toggle theme" style="width:36px; height:36px; border-radius:999px; border:1px solid var(--border); background:var(--elev); color:var(--t3); font-size:15px; cursor:pointer; display:flex; align-items:center; justify-content:center; line-height:1;">{{ themeIcon }}</button>
      <button onClick="{{ toggleAccount }}" aria-label="Account" style="width:36px; height:36px; border-radius:999px; border:1px solid var(--bstrong); background:var(--elev); color:var(--accentlight); font-family:var(--mono); font-weight:600; font-size:13px; cursor:pointer; display:flex; align-items:center; justify-content:center;">GG</button>
    </div>
  </div>

  <!-- title + add -->
  <div style="flex:none; padding:14px 16px 12px; display:flex; align-items:flex-start; justify-content:space-between; gap:10px;">
    <div style="display:flex; flex-direction:column; gap:3px;">
      <span style="font-size:21px; font-weight:600; letter-spacing:-0.01em;">Reminders</span>
      <span style="font-family:var(--mono); font-size:12px; color:{{ summaryColor }};">{{ summary }}</span>
    </div>
    <button onClick="{{ openAdd }}" aria-label="Add reminder" style="flex:none; width:44px; height:44px; border-radius:10px; border:none; background:linear-gradient(#3b82c4,#2f6ea9); color:#fff; font-size:22px; font-weight:500; line-height:1; cursor:pointer; box-shadow:0 6px 14px rgba(12,40,68,0.35);">+</button>
  </div>

  <!-- list -->
  <div class="rm-scroll" style="flex:1; min-height:0; overflow-y:auto; padding:2px 16px 20px; display:flex; flex-direction:column; gap:18px;">
    <sc-for list="{{ sections }}" as="sec" hint-placeholder-count="3">
      <div>
        <div style="display:flex; align-items:center; gap:8px; padding:0 2px 9px;">
          <span style="width:7px; height:7px; border-radius:999px; background:{{ sec.dot }};"></span>
          <span style="font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:0.08em; text-transform:uppercase; color:var(--t3);">{{ sec.label }}</span>
          <span style="font-family:var(--mono); font-size:11px; color:var(--t4);">{{ sec.count }}</span>
        </div>
        <div style="display:flex; flex-direction:column; gap:9px;">
          <sc-for list="{{ sec.items }}" as="r" hint-placeholder-count="2">
            <div style="position:relative; overflow:hidden; border-radius:10px;">
              <!-- snooze reveal (swipe right) -->
              <div data-act="snooze" style="position:absolute; inset:0; display:flex; align-items:center; gap:9px; padding-left:20px; border-radius:10px; background:{{ snoozeBg }}; color:{{ snoozeFg }}; opacity:0; pointer-events:none;">
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"></circle><path d="M12 7v5l3 2"></path></svg>
                <span style="font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:0.07em; text-transform:uppercase;">Snooze</span>
              </div>
              <!-- complete reveal (swipe left) -->
              <div data-act="done" style="position:absolute; inset:0; display:flex; align-items:center; justify-content:flex-end; gap:9px; padding-right:20px; border-radius:10px; background:{{ doneBg }}; color:{{ doneFg }}; opacity:0; pointer-events:none;">
                <span style="font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:0.07em; text-transform:uppercase;">Complete</span>
                <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"></path></svg>
              </div>
              <!-- draggable card -->
              <div onPointerDown="{{ r.dragStart }}" onPointerMove="{{ r.dragMove }}" onPointerUp="{{ r.dragEnd }}" onPointerCancel="{{ r.dragEnd }}" style="position:relative; background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:13px 14px; box-shadow:var(--shadow-card); display:flex; flex-direction:column; gap:5px; color:var(--t1); cursor:grab; touch-action:pan-y; user-select:none; transform:translateX(0);">
                <span style="font-size:15px; font-weight:500; line-height:1.3;">{{ r.note }}</span>
                <span style="display:flex; align-items:center; gap:8px; flex-wrap:wrap;">
                  <span style="font-size:12px; color:var(--t3);">{{ r.org }}</span>
                  <span style="font-family:var(--mono); font-size:10px; font-weight:600; letter-spacing:0.04em; text-transform:uppercase; padding:2px 8px; border-radius:999px; background:{{ r.chipBg }}; color:{{ r.chipText }}; border:1px solid {{ r.chipBorder }};">{{ r.dueText }}</span>
                </span>
              </div>
            </div>
          </sc-for>
        </div>
      </div>
    </sc-for>

    <sc-if value="{{ allClear }}" hint-placeholder-val="{{ false }}">
      <div style="padding:40px 20px; text-align:center; display:flex; flex-direction:column; align-items:center; gap:10px;">
        <span style="font-size:26px; color:var(--money);">✓</span>
        <span style="font-size:15px; color:var(--t2); font-weight:500;">Inbox zero</span>
        <span style="font-size:13px; color:var(--t4);">No open reminders. Nice.</span>
      </div>
    </sc-if>

    <!-- completed -->
    <sc-if value="{{ hasDone }}" hint-placeholder-val="{{ false }}">
      <div>
        <button onClick="{{ toggleCompleted }}" style="width:100%; background:none; border:none; cursor:pointer; display:flex; align-items:center; gap:8px; padding:0 2px 9px; color:var(--t3);">
          <span style="font-size:12px; width:12px; transform:rotate({{ completedRot }}deg); transition:transform 150ms;">▸</span>
          <span style="font-family:var(--mono); font-size:11px; font-weight:600; letter-spacing:0.08em; text-transform:uppercase;">Completed</span>
          <span style="font-family:var(--mono); font-size:11px; color:var(--t4);">{{ doneCount }}</span>
        </button>
        <sc-if value="{{ completedOpen }}" hint-placeholder-val="{{ false }}">
          <div style="display:flex; flex-direction:column; gap:9px;">
            <sc-for list="{{ doneItems }}" as="r" hint-placeholder-count="1">
              <div style="display:flex; align-items:center; gap:12px; background:var(--panel); border:1px solid var(--border); border-radius:10px; padding:12px 13px; opacity:0.6;">
                <button onClick="{{ r.toggle }}" aria-label="Reopen" style="flex:none; width:24px; height:24px; border-radius:999px; border:2px solid var(--accent); background:var(--accent); cursor:pointer; display:flex; align-items:center; justify-content:center; color:#fff; font-size:12px; line-height:1;">✓</button>
                <button onClick="{{ r.open }}" style="flex:1; min-width:0; text-align:left; background:none; border:none; cursor:pointer; display:flex; flex-direction:column; gap:5px; color:var(--t1);">
                  <span style="font-size:15px; font-weight:500; line-height:1.3; text-decoration:line-through; color:var(--t3);">{{ r.note }}</span>
                  <span style="font-size:12px; color:var(--t4);">{{ r.org }}</span>
                </button>
              </div>
            </sc-for>
          </div>
        </sc-if>
      </div>
    </sc-if>
  </div>

  <!-- bottom tab bar -->
  <div style="flex:none; display:flex; border-top:1px solid var(--border); background:var(--nav-bg); backdrop-filter:blur(8px); padding-bottom:18px;">
    <sc-for list="{{ tabs }}" as="t" hint-placeholder-count="4">
      <button onClick="{{ t.go }}" style="flex:1; background:none; border:none; cursor:pointer; height:56px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:5px; color:{{ t.color }};">
        <span style="width:20px; height:20px; display:flex; align-items:center; justify-content:center;">{{ t.icon }}</span>
        <span style="font-family:var(--mono); font-size:10px; letter-spacing:0.04em;">{{ t.label }}</span>
      </button>
    </sc-for>
  </div>

  <!-- account menu -->
  <sc-if value="{{ accountMenu }}" hint-placeholder-val="{{ false }}">
    <div onClick="{{ closeAccount }}" style="position:absolute; inset:0; z-index:40; animation:fadeIn 120ms ease;">
      <div style="position:absolute; top:96px; right:16px; width:208px; background:var(--elev); border:1px solid var(--bstrong); border-radius:10px; box-shadow:0 24px 56px rgba(1,8,17,0.5); overflow:hidden;">
        <div style="padding:14px 16px; border-bottom:1px solid var(--border);">
          <div style="font-size:14px; font-weight:600; color:var(--t1);">Grant Gilliam</div>
          <div style="font-size:12px; color:var(--t3); margin-top:2px;">grant@ten31.xyz</div>
        </div>
        <div style="padding:6px;">
          <div style="padding:11px 12px; border-radius:7px; font-size:14px; color:var(--t2);">Profile</div>
          <div style="padding:11px 12px; border-radius:7px; font-size:14px; color:var(--danger);">Log out</div>
        </div>
      </div>
    </div>
  </sc-if>

  <!-- generic sheet -->
  <sc-if value="{{ sheetOpen }}" hint-placeholder-val="{{ false }}">
    <div onClick="{{ closeSheet }}" style="position:absolute; inset:0; z-index:60; background:rgba(4,9,16,0.55); animation:fadeIn 150ms ease; display:flex; flex-direction:column; justify-content:flex-end;">
      <div onClick="{{ stop }}" style="background:var(--panel); border-top:1px solid var(--bstrong); border-radius:20px 20px 0 0; box-shadow:0 -24px 56px rgba(1,8,17,0.4); animation:sheetUp 280ms cubic-bezier(.2,.8,.2,1); padding:0 20px 26px; max-height:90%; display:flex; flex-direction:column;">
        <div style="padding:10px 0 4px; display:flex; justify-content:center; flex:none;"><div style="width:38px; height:4px; border-radius:999px; background:var(--bstrong);"></div></div>
        <div style="display:flex; align-items:center; justify-content:space-between; padding:8px 0 4px; flex:none;">
          <span style="font-size:18px; font-weight:600; color:var(--t1);">{{ sheetTitle }}</span>
          <button onClick="{{ closeSheet }}" style="background:none; border:none; color:var(--t3); font-size:22px; cursor:pointer; line-height:1; padding:0 4px;">×</button>
        </div>
        <div class="rm-scroll" style="overflow-y:auto; margin-top:8px;">
          {{ sheetBody }}
        </div>
      </div>
    </div>
  </sc-if>

  <!-- toast -->
  <sc-if value="{{ toast }}" hint-placeholder-val="{{ false }}">
    <div style="position:absolute; left:16px; right:16px; bottom:92px; z-index:70; background:var(--elev); border:1px solid var(--bstrong); border-radius:10px; box-shadow:0 10px 24px rgba(4,12,22,0.35); padding:13px 16px; font-size:14px; color:var(--t1); display:flex; align-items:center; gap:10px; animation:fadeIn 150ms ease;">
      <span style="color:var(--money);">✓</span>{{ toast }}
    </div>
  </sc-if>

</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;$preview&quot;:{&quot;width&quot;:393,&quot;height&quot;:812},&quot;theme&quot;:{&quot;editor&quot;:&quot;enum&quot;,&quot;options&quot;:[&quot;dark&quot;,&quot;light&quot;],&quot;default&quot;:&quot;dark&quot;,&quot;tsType&quot;:&quot;'dark'|'light'&quot;}}">
class Component extends DCLogic {
  constructor(props) {
    super(props);
    this.today = new Date(2026, 5, 19); // Jun 19 2026
    this.state = {
      theme: props.theme === 'light' ? 'light' : 'dark',
      accountMenu: false,
      completedOpen: false,
      sheet: null,
      toast: null,
    };
  }

  componentDidMount() { if (window.T31Store) this._unsub = window.T31Store.subscribe(() => this.forceUpdate()); }
  componentWillUnmount() { if (this._unsub) this._unsub(); }

  seed() {
    return [
      { id: 1, note: 'Resend deck — bounced', org: 'Vance & Co', orgId: 4, due: '2026-06-18', done: false },
      { id: 2, note: 'Re-engage — cold 2 weeks', org: 'Hartman Group', orgId: 6, due: '2026-06-16', done: false },
      { id: 3, note: 'IC memo due', org: 'Polaris Endowment', orgId: 5, due: '2026-06-19', done: false },
      { id: 4, note: 'Follow up after intro call', org: 'Brightseed Partners', orgId: 2, due: '2026-06-19', done: false },
      { id: 5, note: 'Share data room link', org: 'Atlas Ventures Fund', orgId: 8, due: '2026-06-20', done: false },
      { id: 6, note: 'Countersign side letter', org: 'Meridian Trust', orgId: 7, due: '2026-06-21', done: false },
      { id: 7, note: 'Send Q2 update deck', org: 'Northwall Capital', orgId: 1, due: '2026-06-24', done: false },
      { id: 8, note: 'Quarterly check-in call', org: 'Cedarline Family Office', orgId: 3, due: '2026-07-08', done: false },
      { id: 9, note: 'Thank-you note post-wire', org: 'Granite Bay LP', orgId: 10, due: '2026-06-13', done: true },
    ];
  }

  investorList() {
    if (window.T31Store) return window.T31Store.investors.map(i => ({ id: i.id, name: i.name }));
    return [
      { id: 1, name: 'Northwall Capital' }, { id: 2, name: 'Brightseed Partners' }, { id: 3, name: 'Cedarline Family Office' },
      { id: 4, name: 'Vance & Co' }, { id: 5, name: 'Polaris Endowment' }, { id: 6, name: 'Hartman Group' },
      { id: 7, name: 'Meridian Trust' }, { id: 8, name: 'Atlas Ventures Fund' }, { id: 10, name: 'Granite Bay LP' },
    ];
  }

  parse(iso) { const p = iso.split('-'); return new Date(+p[0], +p[1] - 1, +p[2]); }
  diffDays(iso) { return Math.round((this.parse(iso) - this.today) / 86400000); }
  monthDay(iso) { const m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; const d = this.parse(iso); return m[d.getMonth()] + ' ' + d.getDate(); }

  urgency(iso, theme) {
    const light = theme === 'light';
    const d = this.diffDays(iso);
    const red = light ? { t: '#c0322f', bg: '#c0322f14', bd: '#e3b4b2' } : { t: '#f87171', bg: '#f8717118', bd: '#f8717140' };
    const amber = light ? { t: '#8a6c12', bg: '#e0b34122', bd: '#e4d29a' } : { t: '#e0b341', bg: '#e0b3411f', bd: '#e0b3413d' };
    const blue = light ? { t: '#1f6fb8', bg: '#3b82c416', bd: '#bcd2ea' } : { t: '#93c5fd', bg: '#3b82c422', bd: '#3b82c44d' };
    const grey = light ? { t: '#5a6b7d', bg: '#5a6b7d12', bd: '#d6dde7' } : { t: '#8ea2b7', bg: '#1b2a3a', bd: '#263548' };
    if (d < 0) return { bucket: 0, text: (-d) + 'd overdue', c: red };
    if (d === 0) return { bucket: 1, text: 'Today', c: amber };
    if (d === 1) return { bucket: 2, text: 'Tomorrow', c: blue };
    if (d <= 7) return { bucket: 2, text: 'in ' + d + 'd', c: blue };
    return { bucket: 3, text: this.monthDay(iso), c: grey };
  }

  toast(msg) { this.setState({ toast: msg }); clearTimeout(this._tt); this._tt = setTimeout(() => this.setState({ toast: null }), 2000); }

  dragStart(e, id) {
    const card = e.currentTarget;
    card.style.transition = 'none';
    this._drag = { id, x0: e.clientX, card, wrap: card.parentNode, dx: 0, moved: false, cap: false };
  }
  dragMove(e) {
    const d = this._drag; if (!d) return;
    let dx = e.clientX - d.x0;
    if (Math.abs(dx) > 5) d.moved = true;
    if (!d.cap && Math.abs(dx) > 6) { try { d.card.setPointerCapture(e.pointerId); } catch (_) {} d.cap = true; }
    dx = Math.max(-160, Math.min(160, dx));
    d.dx = dx;
    d.card.style.transform = 'translateX(' + dx + 'px)';
    const TH = 70;
    const done = d.wrap.querySelector('[data-act="done"]');
    const snooze = d.wrap.querySelector('[data-act="snooze"]');
    if (dx < 0) { done.style.opacity = Math.min(1, -dx / TH); snooze.style.opacity = 0; }
    else if (dx > 0) { snooze.style.opacity = Math.min(1, dx / TH); done.style.opacity = 0; }
    else { done.style.opacity = 0; snooze.style.opacity = 0; }
  }
  dragEnd(e) {
    const d = this._drag; if (!d) return; this._drag = null;
    const dx = d.dx, TH = 70;
    const done = d.wrap.querySelector('[data-act="done"]');
    const snooze = d.wrap.querySelector('[data-act="snooze"]');
    const clearBg = () => { done.style.opacity = 0; snooze.style.opacity = 0; };
    d.card.style.transition = 'transform 200ms ease';
    const S = window.T31Store;
    const r = S ? S.reminders.find(x => x.id === d.id) : null;
    const inv = (r && S) ? S.investorById(r.orgId) : null;
    const orgName = inv ? inv.name : '';
    if (dx <= -TH) {
      d.card.style.transform = 'translateX(-110%)';
      const card = d.card, id = d.id;
      setTimeout(() => {
        card.style.transition = 'none';
        card.style.transform = 'translateX(0)';
        clearBg();
        this.toggleDone(id);
      }, 190);
    } else if (dx >= TH) {
      d.card.style.transform = 'translateX(0)'; clearBg();
      this.setState({ sheet: { kind: 'snooze', id: d.id, org: orgName } });
    } else {
      d.card.style.transform = 'translateX(0)'; clearBg();
      if (r) this.setState({ sheet: { kind: 'edit', id: r.id, orgId: r.orgId, note: r.note, due: r.due, org: orgName } });
    }
  }
  toggleDone(id) {
    const S = window.T31Store; const r = S && S.reminders.find(x => x.id === id);
    const nowDone = r ? !r.done : true;
    if (S) S.toggleReminder(id);
    this.toast(nowDone ? 'Marked done' : 'Reopened');
  }
  setSheet(patch) { this.setState(s => ({ sheet: Object.assign({}, s.sheet, patch) })); }

  renderVals() {
    const s = this.state;
    const theme = s.theme;
    const accent = '#3b82c4';

    const S = window.T31Store;
    const orgName = (id) => { const inv = S && S.investorById(id); return inv ? inv.name : ''; };
    const allR = (S ? S.reminders : []).map(r => Object.assign({}, r, { org: orgName(r.orgId) }));
    const open = allR.filter(r => !r.done);
    const done = allR.filter(r => r.done);

    const overdue = open.filter(r => this.diffDays(r.due) < 0).length;
    const todayN = open.filter(r => this.diffDays(r.due) === 0).length;
    let summary, summaryColor;
    if (open.length === 0) { summary = 'All clear'; summaryColor = 'var(--money)'; }
    else { summary = overdue + ' overdue · ' + todayN + ' today · ' + open.length + ' open'; summaryColor = overdue ? (theme === 'light' ? '#c0322f' : '#f87171') : 'var(--t4)'; }

    const dots = ['#f87171', '#e0b341', accent, theme === 'light' ? '#84909e' : '#70859b'];
    const labels = ['Overdue', 'Today', 'This week', 'Later'];
    const buckets = [[], [], [], []];
    open.forEach(r => { const u = this.urgency(r.due, theme); buckets[u.bucket].push({ r, u }); });
    buckets.forEach(b => b.sort((a, z) => this.diffDays(a.r.due) - this.diffDays(z.r.due)));

    const mkItem = ({ r, u }) => ({
      note: r.note, org: r.org,
      dueText: u.text, chipBg: u.c.bg, chipText: u.c.t, chipBorder: u.c.bd,
      dragStart: (e) => this.dragStart(e, r.id),
      dragMove: (e) => this.dragMove(e),
      dragEnd: (e) => this.dragEnd(e),
    });

    const sections = [];
    buckets.forEach((b, i) => { if (b.length) sections.push({ label: labels[i], count: String(b.length), dot: dots[i], items: b.map(mkItem) }); });

    const doneItems = done.map(r => ({ note: r.note, org: r.org, toggle: () => this.toggleDone(r.id), open: () => this.setState({ sheet: { kind: 'edit', id: r.id, orgId: r.orgId, note: r.note, due: r.due, org: r.org } }) }));

    const tabs = [
      { key: 'grid', label: 'Grid' }, { key: 'pipeline', label: 'Pipeline' },
      { key: 'reminders', label: 'Reminders' }, { key: 'contacts', label: 'Contacts' },
    ].map(t => ({
      label: t.label, color: t.key === 'reminders' ? 'var(--accent)' : 'var(--t4)',
      icon: this.tabIcon(t.key, t.key === 'reminders'),
      go: () => { if (window.T31Store) window.T31Store.setTab(t.key); },
    }));

    const sheetBody = s.sheet ? this.buildSheet(s.sheet) : null;

    return {
      themeAttr: theme, themeIcon: theme === 'light' ? '☾' : '☀',
      toggleTheme: () => { const t = theme === 'light' ? 'dark' : 'light'; if (window.T31Store) window.T31Store.setTheme(t); this.setState({ theme: t }); },
      toggleAccount: () => this.setState(st => ({ accountMenu: !st.accountMenu })),
      closeAccount: () => this.setState({ accountMenu: false }),
      accountMenu: s.accountMenu,
      summary, summaryColor,
      sections, allClear: open.length === 0 && done.length === 0 ? false : open.length === 0,
      tabs,
      doneBg: theme === 'light' ? '#10b98118' : '#10b9812e', doneFg: theme === 'light' ? '#057a55' : '#6ee7b7',
      snoozeBg: theme === 'light' ? '#e0b34120' : '#e0b3412e', snoozeFg: theme === 'light' ? '#8a6c12' : '#e0b341',
      hasDone: done.length > 0, doneCount: String(done.length), doneItems,
      completedOpen: s.completedOpen, completedRot: s.completedOpen ? 90 : 0,
      toggleCompleted: () => this.setState(st => ({ completedOpen: !st.completedOpen })),
      openAdd: () => this.setState({ sheet: { kind: 'add', orgId: null, q: '', note: '', due: '2026-06-20' } }),
      sheetOpen: !!s.sheet, sheetTitle: s.sheet ? ({ add: 'New reminder', edit: 'Edit reminder', snooze: 'Snooze reminder' })[s.sheet.kind] : '',
      sheetBody, closeSheet: () => this.setState({ sheet: null }), stop: e => e.stopPropagation(),
      toast: s.toast,
    };
  }

  duePresets() {
    return [ ['Today', '2026-06-19'], ['Tomorrow', '2026-06-20'], ['In 3 days', '2026-06-22'], ['Next week', '2026-06-26'] ];
  }
  snoozePresets() {
    return [ ['Tomorrow', '2026-06-20'], ['In 3 days', '2026-06-22'], ['1 week', '2026-06-26'], ['2 weeks', '2026-07-03'] ];
  }

  buildSheet(sh) {
    const h = React.createElement;
    const theme = this.state.theme;
    const dark = theme !== 'light';
    const T = { input: dark ? '#0d1622' : '#eef2f7', border: dark ? '#263548' : '#d6dde7', bstrong: dark ? '#35506a' : '#b6c3d4',
      t1: dark ? '#e5edf5' : '#16202c', t2: dark ? '#c7d3e0' : '#33414f', t3: dark ? '#8ea2b7' : '#5a6b7d', t4: dark ? '#70859b' : '#84909e',
      elev: dark ? '#152233' : '#f4f7fb', accentlight: dark ? '#93c5fd' : '#1f6fb8', danger: dark ? '#e06c6c' : '#c0322f' };
    const inputStyle = { width: '100%', height: 46, background: T.input, border: '1px solid ' + T.border, borderRadius: 8, color: T.t1, fontFamily: 'var(--sans)', fontSize: 15, padding: '0 14px', outline: 'none', boxSizing: 'border-box' };
    const label = (t) => h('div', { style: { fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.08em', textTransform: 'uppercase', color: T.t3, margin: '16px 0 8px' } }, t);
    const dueChips = (sel, on) => h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, this.duePresets().map(d => {
      const active = sel === d[1];
      return h('button', { key: d[1], onClick: () => on(d[1]), style: { flex: '1 0 40%', height: 42, borderRadius: 7, cursor: 'pointer', fontSize: 13, fontWeight: 500, border: '1px solid ' + (active ? T.bstrong : T.border), background: active ? T.elev : T.input, color: active ? T.t1 : T.t3 } }, d[0] + ' · ' + this.monthDay(d[1]));
    }));

    if (sh.kind === 'edit') {
      return h('div', null,
        h('div', { style: { fontSize: 13, color: T.t3 } }, 'For ' + sh.org),
        label('Reminder'),
        h('input', { value: sh.note, onChange: e => this.setSheet({ note: e.target.value }), style: inputStyle, autoFocus: true }),
        label('Due'),
        dueChips(sh.due, v => this.setSheet({ due: v })),
        h('button', { onClick: () => { if (window.T31Store) window.T31Store.updateReminder(sh.id, { note: sh.note, due: sh.due }); this.setState({ sheet: null }); this.toast('Reminder saved'); }, disabled: !sh.note.trim(), style: { width: '100%', height: 48, marginTop: 22, borderRadius: 8, border: 'none', background: !sh.note.trim() ? T.elev : 'linear-gradient(#3b82c4,#2f6ea9)', color: !sh.note.trim() ? T.t4 : '#fff', fontSize: 15, fontWeight: 600, cursor: 'pointer' } }, 'Save reminder'),
        h('div', { style: { display: 'flex', gap: 10, marginTop: 10 } },
          h('button', { onClick: () => { this.toggleDone(sh.id); this.setState({ sheet: null }); }, style: { flex: 1, height: 46, borderRadius: 8, border: '1px solid ' + T.bstrong, background: T.elev, color: T.t2, fontSize: 14, fontWeight: 500, cursor: 'pointer' } }, 'Mark done'),
          h('button', { onClick: () => { if (window.T31Store) window.T31Store.deleteReminder(sh.id); this.setState({ sheet: null }); this.toast('Reminder deleted'); }, style: { flex: 'none', height: 46, padding: '0 18px', borderRadius: 8, border: '1px solid ' + (dark ? '#dc262655' : '#e3b4b2'), background: dark ? '#2a1416' : '#fbeceb', color: dark ? '#fca5a5' : '#c0322f', fontSize: 14, fontWeight: 500, cursor: 'pointer' } }, 'Delete')),
        h('button', { onClick: () => { if (window.T31Store) window.T31Store.openInvestor(sh.orgId); }, style: { width: '100%', marginTop: 14, background: 'none', border: 'none', cursor: 'pointer', color: T.accentlight, fontSize: 13 } }, 'Open ' + sh.org + ' in Grid ›')
      );
    }

    if (sh.kind === 'snooze') {
      return h('div', null,
        h('div', { style: { fontSize: 13, color: T.t3, marginBottom: 4 } }, 'For ' + sh.org),
        label('Snooze until'),
        h('div', { style: { display: 'flex', flexDirection: 'column', gap: 8 } }, this.snoozePresets().map(d =>
          h('button', { key: d[1], onClick: () => { if (window.T31Store) window.T31Store.updateReminder(sh.id, { due: d[1], done: false }); this.setState({ sheet: null }); this.toast('Snoozed to ' + this.monthDay(d[1])); }, style: { width: '100%', height: 50, borderRadius: 8, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 16px', border: '1px solid ' + T.border, background: T.input, color: T.t1, fontSize: 15, fontWeight: 500 } },
            h('span', null, d[0]),
            h('span', { style: { fontFamily: 'var(--mono)', fontSize: 13, color: T.t4 } }, this.monthDay(d[1])))
        ))
      );
    }

    // add
    if (!sh.orgId) {
      const qn = (sh.q || '').trim().toLowerCase();
      let pool = this.investorList();
      if (qn) pool = pool.filter(i => i.name.toLowerCase().includes(qn));
      return h('div', null,
        h('div', { style: { fontSize: 13, color: T.t3, marginBottom: 12 } }, 'Which investor is this reminder for?'),
        h('input', { value: sh.q, onChange: e => this.setSheet({ q: e.target.value }), style: inputStyle, placeholder: 'Search investor…', autoFocus: true }),
        h('div', { style: { display: 'flex', flexDirection: 'column', gap: 8, marginTop: 12 } }, pool.length ? pool.map(i =>
          h('button', { key: i.id, onClick: () => this.setSheet({ orgId: i.id, org: i.name }), style: { width: '100%', textAlign: 'left', cursor: 'pointer', background: T.input, border: '1px solid ' + T.border, borderRadius: 10, padding: '13px 14px', color: T.t1, fontSize: 15, fontWeight: 500 } }, i.name)
        ) : h('div', { style: { fontSize: 13, color: T.t4, padding: '16px 4px' } }, 'No matches.'))
      );
    }
    return h('div', null,
      h('div', { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, background: T.input, border: '1px solid ' + T.border, borderRadius: 10, padding: '11px 13px' } },
        h('span', { style: { display: 'flex', flexDirection: 'column', gap: 2, minWidth: 0 } },
          h('span', { style: { fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.06em', textTransform: 'uppercase', color: T.t4 } }, 'Reminder for'),
          h('span', { style: { fontSize: 15, fontWeight: 600, color: T.t1 } }, sh.org)),
        h('button', { onClick: () => this.setSheet({ orgId: null }), style: { flex: 'none', background: 'none', border: 'none', color: T.accentlight, fontSize: 13, cursor: 'pointer' } }, 'Change')),
      label('Reminder'),
      h('input', { value: sh.note, onChange: e => this.setSheet({ note: e.target.value }), style: inputStyle, placeholder: 'What needs doing?', autoFocus: true }),
      label('Due'),
      dueChips(sh.due, v => this.setSheet({ due: v })),
      h('button', { onClick: () => { if (window.T31Store) window.T31Store.addReminder(sh.orgId, sh.note.trim(), sh.due); this.setState({ sheet: null }); this.toast('Reminder added'); }, disabled: !sh.note.trim(), style: { width: '100%', height: 48, marginTop: 22, borderRadius: 8, border: 'none', background: !sh.note.trim() ? T.elev : 'linear-gradient(#3b82c4,#2f6ea9)', color: !sh.note.trim() ? T.t4 : '#fff', fontSize: 15, fontWeight: 600, cursor: 'pointer' } }, 'Add reminder')
    );
  }

  tabIcon(key, active) {
    const c = active ? '#3b82c4' : (this.state.theme === 'light' ? '#84909e' : '#70859b');
    const mk = (children) => React.createElement('svg', { width: 20, height: 20, viewBox: '0 0 20 20', fill: 'none' }, children);
    const r = (pp) => React.createElement('rect', pp);
    const ln = (pp) => React.createElement('line', Object.assign({}, pp, { stroke: c, strokeWidth: 1.6, strokeLinecap: 'round' }));
    if (key === 'grid') return mk([
      r({ key: 1, x: 3, y: 3, width: 6, height: 6, rx: 1, stroke: c, strokeWidth: 1.6 }),
      r({ key: 2, x: 11, y: 3, width: 6, height: 6, rx: 1, stroke: c, strokeWidth: 1.6 }),
      r({ key: 3, x: 3, y: 11, width: 6, height: 6, rx: 1, stroke: c, strokeWidth: 1.6 }),
      r({ key: 4, x: 11, y: 11, width: 6, height: 6, rx: 1, stroke: c, strokeWidth: 1.6 }),
    ]);
    if (key === 'pipeline') return mk([
      r({ key: 1, x: 3, y: 3, width: 4.5, height: 14, rx: 1, stroke: c, strokeWidth: 1.6 }),
      r({ key: 2, x: 9.25, y: 3, width: 4.5, height: 10, rx: 1, stroke: c, strokeWidth: 1.6 }),
      r({ key: 3, x: 15.5, y: 3, width: 1.5, height: 6, rx: 0.7, fill: c }),
    ]);
    if (key === 'reminders') return mk([
      React.createElement('circle', { key: 1, cx: 10, cy: 11, r: 6.2, stroke: c, strokeWidth: 1.6 }),
      ln({ key: 2, x1: 10, y1: 11, x2: 10, y2: 7.5 }),
      ln({ key: 3, x1: 10, y1: 11, x2: 12.4, y2: 12 }),
      ln({ key: 4, x1: 7, y1: 3.4, x2: 4.4, y2: 5.4 }),
      ln({ key: 5, x1: 13, y1: 3.4, x2: 15.6, y2: 5.4 }),
    ]);
    return mk([
      React.createElement('circle', { key: 1, cx: 10, cy: 7, r: 3.2, stroke: c, strokeWidth: 1.6 }),
      React.createElement('path', { key: 2, d: 'M4 16.5c0-3 2.7-4.8 6-4.8s6 1.8 6 4.8', stroke: c, strokeWidth: 1.6, strokeLinecap: 'round' }),
    ]);
  }
}
</script>
</body>
</html>
