/* Build-free edition: React from CDN, Babel in-browser, no imports.
   Set the analytics collector once by visiting:
   https://YOUR-APP-URL/?collector=https://YOUR-WORKER-URL
   (saved on-device; every visit after that just works) */

const { useState, useEffect, useRef } = React;

/* ---------- inlined: IndexedDB key-value store ---------- */
const DB_NAME = "now-next", DB_STORE = "kv";
function openDB() {
  return new Promise((resolve, reject) => {
    const req = indexedDB.open(DB_NAME, 1);
    req.onupgradeneeded = () => req.result.createObjectStore(DB_STORE);
    req.onsuccess = () => resolve(req.result);
    req.onerror = () => reject(req.error);
  });
}
async function kvGet(key) {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const req = db.transaction(DB_STORE, "readonly").objectStore(DB_STORE).get(key);
    req.onsuccess = () => resolve(req.result == null ? null : { value: req.result });
    req.onerror = () => reject(req.error);
  });
}
async function kvSet(key, value) {
  const db = await openDB();
  return new Promise((resolve, reject) => {
    const tx = db.transaction(DB_STORE, "readwrite");
    tx.objectStore(DB_STORE).put(value, key);
    tx.oncomplete = () => resolve({ key, value });
    tx.onerror = () => reject(tx.error);
  });
}

/* ---------- inlined: analytics (collector set via ?collector= URL param) ---------- */
let _endpoint = null, _anonId = null, _flushing = false;
async function initAnalytics() {
  const param = new URLSearchParams(location.search).get("collector");
  if (param) await kvSet("collector-url", param.replace(/\/+$/, ""));
  _endpoint = (await kvGet("collector-url"))?.value || null;
}
async function getAnonId() {
  if (_anonId) return _anonId;
  const existing = await kvGet("anon-id");
  if (existing) { _anonId = existing.value; return _anonId; }
  _anonId = crypto.randomUUID();
  await kvSet("anon-id", _anonId);
  return _anonId;
}
async function track(event, props = {}) {
  try {
    const id = await getAnonId();
    const buf = (await kvGet("event-buffer"))?.value || [];
    buf.push({ id, event, props, ts: Date.now(), tz: Intl.DateTimeFormat().resolvedOptions().timeZone });
    await kvSet("event-buffer", buf.slice(-500));
    flush();
  } catch (e) { /* analytics never breaks the app */ }
}
async function flush() {
  if (!_endpoint || _flushing || !navigator.onLine) return;
  _flushing = true;
  try {
    const buf = (await kvGet("event-buffer"))?.value || [];
    if (buf.length) {
      const res = await fetch(_endpoint + "/events", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ events: buf }),
      });
      if (res.ok) await kvSet("event-buffer", []);
    }
  } catch (e) { /* keep buffering */ } finally { _flushing = false; }
}
window.addEventListener("online", flush);

/* ---------- inlined: notifications (session nudges; push comes later) ---------- */
function notificationsSupported() {
  return "Notification" in window && "serviceWorker" in navigator;
}
function permissionState() {
  return notificationsSupported() ? Notification.permission : "unsupported";
}
async function requestPermission() {
  if (!notificationsSupported()) return "unsupported";
  const result = await Notification.requestPermission();
  track("notif_permission", { result });
  return result;
}
let _nudgeTimers = [];
function scheduleSessionNudges() {
  _nudgeTimers.forEach(clearTimeout);
  _nudgeTimers = [];
  if (permissionState() !== "granted") return;
  const now = new Date();
  [{ hour: 12, title: "Afternoon", body: "Morning's done. Here's your next thing." },
   { hour: 17, title: "Evening", body: "Home stretch. One thing at a time." }].forEach((b) => {
    const at = new Date(now); at.setHours(b.hour, 0, 0, 0);
    const ms = at - now;
    if (ms > 0 && ms < 12 * 60 * 60 * 1000) {
      _nudgeTimers.push(setTimeout(async () => {
        try {
          const reg = await navigator.serviceWorker.ready;
          reg.showNotification(b.title, { body: b.body, icon: "/icon-192.png", data: { source: "session-nudge" } });
        } catch (e) { /* no-op */ }
      }, ms));
    }
  });
}

/* ============================================================
   NOW + NEXT — v2
   Same one-thing-at-a-time UX. New restrained visual system:
   - "Mono"  (default): near-monochrome, quiet, one slate accent
   - "Dark":  charcoal, low-glare, muted steel accent
   - "Color": time-of-day keyed accents (the v1 idea, decluttered)
   Block icons are geometric (○ ◐ ●), no emoji anywhere.
   ============================================================ */

const BLOCKS = ["morning", "afternoon", "evening"];
const BLOCK_LABEL = { morning: "Morning", afternoon: "Afternoon", evening: "Evening" };
const BLOCK_GLYPH = { morning: "○", afternoon: "◐", evening: "●" };

const STORAGE_KEY = "now-next-state-v2";

/* ---------- themes ---------- */
const THEMES = {
  mono: {
    name: "Mono",
    desc: "Quiet, near-monochrome",
    bg: "#F6F6F4",
    card: "#FFFFFF",
    ink: "#20242A",
    sub: "#7A8088",
    faint: "#A6ABB2",
    border: "#E4E5E3",
    hairline: "#EFEFED",
    rowBg: "#FAFAF9",
    track: "#E4E5E3",
    accent: () => "#3A4148",
    deep: () => "#20242A",
    tint: () => "#ECEDEB",
    wash: null,
    done: "#20242A",
    doneText: "#FFFFFF",
    fab: "#20242A",
    fabText: "#FFFFFF",
    check: "#3A4148",
    shadow: "0 2px 16px rgba(32,36,42,0.06)",
    overlay: "rgba(32,36,42,0.4)",
  },
  dark: {
    name: "Dark",
    desc: "Low glare, easy at night",
    bg: "#15181C",
    card: "#1E2228",
    ink: "#E9ECEF",
    sub: "#8B939C",
    faint: "#5F6770",
    border: "#2C323A",
    hairline: "#262B32",
    rowBg: "#1A1E24",
    track: "#2C323A",
    accent: () => "#8FA3B8",
    deep: () => "#C4D2DF",
    tint: () => "#262C34",
    wash: null,
    done: "#40556B",
    doneText: "#E9ECEF",
    fab: "#E9ECEF",
    fabText: "#15181C",
    check: "#8FA3B8",
    shadow: "0 2px 16px rgba(0,0,0,0.35)",
    overlay: "rgba(0,0,0,0.55)",
  },
  color: {
    name: "Color",
    desc: "Accents follow the time of day",
    bg: "#F3F5F7",
    card: "#FFFFFF",
    ink: "#1C2733",
    sub: "#6B7683",
    faint: "#9AA4AF",
    border: "#DDE2E7",
    hairline: "#F0F2F4",
    rowBg: "#FAFBFC",
    track: "#E3E7EB",
    accent: (b) => ({ morning: "#D98A1F", afternoon: "#3B7CB8", evening: "#6E63B8" }[b]),
    deep: (b) => ({ morning: "#8A5606", afternoon: "#1B4E7E", evening: "#463A85" }[b]),
    tint: (b) => ({ morning: "#F7EEDF", afternoon: "#E5EEF6", evening: "#EBE8F6" }[b]),
    wash: (b) => ({ morning: "#F7EEDF", afternoon: "#E5EEF6", evening: "#EBE8F6" }[b]),
    done: null, // uses accent(block)
    doneText: "#FFFFFF",
    fab: "#1C2733",
    fabText: "#FFFFFF",
    check: "#3B7CB8",
    shadow: "0 2px 16px rgba(28,39,51,0.07)",
    overlay: "rgba(28,39,51,0.45)",
  },
};

const todayStr = () => {
  const d = new Date();
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}`;
};

const currentBlock = () => {
  const h = new Date().getHours();
  if (h < 12) return "morning";
  if (h < 17) return "afternoon";
  return "evening";
};

const uid = () => Math.random().toString(36).slice(2, 10);

const SAMPLE_TASKS = [
  { title: "Pack the kids' lunches", block: "morning", tag: "Kids", repeats: true },
  { title: "School drop-off", block: "morning", tag: "Kids", repeats: true },
  { title: "Answer priority emails", block: "morning", tag: "Work", repeats: false },
  { title: "Team check-in call", block: "afternoon", tag: "Work", repeats: false },
  { title: "Book dentist for Maya", block: "afternoon", tag: "Kids", repeats: false },
  { title: "School pickup", block: "afternoon", tag: "Kids", repeats: true },
  { title: "Start dinner", block: "evening", tag: "Home", repeats: true },
  { title: "Homework check", block: "evening", tag: "Kids", repeats: true },
  { title: "Lay out clothes for tomorrow", block: "evening", tag: "Home", repeats: false },
];

function rolloverTasks(tasks, lastDate) {
  if (lastDate === todayStr()) return tasks;
  const next = [];
  for (const t of tasks) {
    if (t.repeats) next.push({ ...t, done: false, carried: false });
    else if (!t.done) next.push({ ...t, carried: true });
  }
  return next;
}

function App() {
  const [tasks, setTasks] = useState([]);
  const [themeKey, setThemeKey] = useState("mono");
  const [loading, setLoading] = useState(true);
  const [expanded, setExpanded] = useState({});
  const [showAdd, setShowAdd] = useState(false);
  const [showThemes, setShowThemes] = useState(false);
  const [activeRow, setActiveRow] = useState(null);
  const [justDone, setJustDone] = useState(false);
  const [nowKey, setNowKey] = useState(0);
  const [notifState, setNotifState] = useState(permissionState());
  const saveTimer = useRef(null);

  const block = currentBlock();
  const T = THEMES[themeKey] || THEMES.mono;
  const S = makeStyles(T);

  /* ---------- load ---------- */
  useEffect(() => {
    (async () => {
      await initAnalytics();
      track("app_open", { hour: new Date().getHours() });
      if (new URLSearchParams(location.search).get("from") === "notif") track("notif_open");
      if (permissionState() === "granted") scheduleSessionNudges();
      flush();
      try {
        const res = await kvGet(STORAGE_KEY);
        if (res && res.value) {
          const data = JSON.parse(res.value);
          const rolled = rolloverTasks(data.tasks || [], data.lastDate);
          setTasks(rolled);
          if (data.theme && THEMES[data.theme]) setThemeKey(data.theme);
          persist(rolled, data.theme || "mono");
        }
      } catch (e) {
        /* fresh start */
      }
      setLoading(false);
    })();
  }, []);

  /* ---------- save ---------- */
  const persist = (t, th) => {
    if (saveTimer.current) clearTimeout(saveTimer.current);
    saveTimer.current = setTimeout(async () => {
      try {
        await kvSet(STORAGE_KEY, JSON.stringify({ tasks: t, theme: th, lastDate: todayStr() }));
      } catch (e) {
        console.error("Save failed", e);
      }
    }, 250);
  };

  const update = (fn) => {
    setTasks((prev) => {
      const next = fn(prev);
      persist(next, themeKey);
      return next;
    });
  };

  const setTheme = (k) => {
    track("theme_change", { theme: k });
    setThemeKey(k);
    persist(tasks, k);
    setShowThemes(false);
  };

  /* ---------- derived ---------- */
  const byBlock = (b) => tasks.filter((t) => t.block === b);
  const remaining = (b) => byBlock(b).filter((t) => !t.done);
  const doneCount = tasks.filter((t) => t.done).length;
  const total = tasks.length;

  const blockOrder = [...BLOCKS.slice(BLOCKS.indexOf(block)), ...BLOCKS.slice(0, BLOCKS.indexOf(block))];
  let nowTask = null;
  let nowBlock = block;
  for (const b of blockOrder) {
    const r = remaining(b);
    if (r.length) { nowTask = r[0]; nowBlock = b; break; }
  }
  const nextTask = (() => {
    if (!nowTask) return null;
    let found = false;
    for (const b of blockOrder) {
      for (const t of remaining(b)) {
        if (found) return t;
        if (t.id === nowTask.id) found = true;
      }
    }
    return null;
  })();

  const accent = T.accent(nowBlock);
  const doneColor = T.done || T.accent(nowBlock);

  /* ---------- actions ---------- */
  const completeTask = (id) => {
    setJustDone(true);
    track("task_complete", { block: nowBlock });
    setTimeout(() => {
      update((prev) => prev.map((t) => (t.id === id ? { ...t, done: true } : t)));
      setJustDone(false);
      setNowKey((k) => k + 1);
    }, 420);
  };

  const laterTask = (id) => {
    track("task_later", { block: nowBlock });
    update((prev) => {
      const t = prev.find((x) => x.id === id);
      if (!t) return prev;
      const rest = prev.filter((x) => x.id !== id);
      let lastIdx = -1;
      rest.forEach((x, i) => { if (x.block === t.block) lastIdx = i; });
      const copy = [...rest];
      copy.splice(lastIdx + 1, 0, t);
      return copy;
    });
    setNowKey((k) => k + 1);
  };

  const toggleDone = (id) => update((prev) => prev.map((t) => (t.id === id ? { ...t, done: !t.done } : t)));
  const deleteTask = (id) => { update((prev) => prev.filter((t) => t.id !== id)); setActiveRow(null); };
  const moveTask = (id, b) => { update((prev) => prev.map((t) => (t.id === id ? { ...t, block: b } : t))); setActiveRow(null); };
  const addTask = (title, b, tag, repeats) => {
    track("task_add", { block: b, repeats });
    update((prev) => [...prev, { id: uid(), title, block: b, tag, repeats, done: false, carried: false }]);
    setShowAdd(false);
  };
  const loadSample = () => {
    track("day_setup_complete", { count: SAMPLE_TASKS.length });
    update(() => SAMPLE_TASKS.map((t) => ({ ...t, id: uid(), done: false, carried: false })));
  };

  const enableReminders = async () => {
    const result = await requestPermission();
    if (result === "granted") scheduleSessionNudges();
    setNotifState(result);
  };

  const dateLabel = new Date().toLocaleDateString(undefined, { weekday: "long", month: "long", day: "numeric" });

  if (loading) {
    return (
      <div style={{ ...S.page, display: "flex", alignItems: "center", justifyContent: "center" }}>
        <FontLink />
        <div style={{ color: T.sub, fontSize: 16 }}>Loading your day…</div>
      </div>
    );
  }

  return (
    <div style={S.page}>
      <FontLink />
      {T.wash && (
        <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: 240, pointerEvents: "none", background: `linear-gradient(180deg, ${T.wash(block)} 0%, transparent 100%)` }} />
      )}

      <div style={S.container}>
        {/* header */}
        <header style={S.header}>
          <div>
            <div style={S.dateLine}>{dateLabel}</div>
            <div style={S.blockLine}>
              <span style={{ color: T.accent(block), fontSize: 11, marginRight: 6 }}>{BLOCK_GLYPH[block]}</span>
              {BLOCK_LABEL[block]}
            </div>
          </div>
          <button style={S.themeBtn} onClick={() => setShowThemes(true)} aria-label="Change theme">
            <span style={{ display: "inline-flex", gap: 3, marginRight: 7, verticalAlign: "middle" }}>
              <span style={{ width: 8, height: 8, borderRadius: 999, background: T.ink, display: "inline-block" }} />
              <span style={{ width: 8, height: 8, borderRadius: 999, background: T.accent(block), display: "inline-block" }} />
              <span style={{ width: 8, height: 8, borderRadius: 999, border: `1.5px solid ${T.border}`, boxSizing: "border-box", display: "inline-block" }} />
            </span>
            Theme
          </button>
        </header>

        {/* progress */}
        {total > 0 && (
          <div style={S.progressRow}>
            <div style={S.progressTrack} role="progressbar" aria-valuenow={doneCount} aria-valuemin={0} aria-valuemax={total}>
              <div style={{ ...S.progressFill, width: `${(doneCount / total) * 100}%`, background: accent }} />
            </div>
            <div style={S.progressLabel}>{doneCount}/{total}</div>
          </div>
        )}

        {/* reminders opt-in */}
        {notificationsSupported() && notifState === "default" && total > 0 && (
          <button
            style={{ ...S.upNext, width: "100%", cursor: "pointer", marginTop: 0, marginBottom: 18, border: `1.5px solid ${T.border}`, background: T.card, fontFamily: "inherit", textAlign: "left" }}
            onClick={enableReminders}
          >
            <span style={S.upNextLabel}>Reminders</span>
            <span style={{ color: T.ink }}>Get a nudge when the day moves on — tap to turn on</span>
          </button>
        )}

        {/* NOW */}
        {nowTask ? (
          <section key={nowKey} style={{ animation: "rise .3s ease" }}>
            <div style={S.eyebrow}>
              Now
              {nowTask.carried && <span style={S.carried}>from yesterday</span>}
            </div>
            <div style={{ ...S.nowCard, opacity: justDone ? 0.35 : 1, transform: justDone ? "scale(.985)" : "none", transition: "all .4s ease" }}>
              <div style={S.nowTitle}>{justDone ? "Done." : nowTask.title}</div>
              {!justDone && (nowTask.tag || nowTask.repeats) && (
                <div style={{ display: "flex", gap: 6, marginTop: 10 }}>
                  {nowTask.tag && <span style={S.chip}>{nowTask.tag}</span>}
                  {nowTask.repeats && <span style={S.chip}>Daily</span>}
                </div>
              )}
              <button style={{ ...S.doneBtn, background: doneColor, color: T.doneText }} onClick={() => completeTask(nowTask.id)} disabled={justDone}>
                Mark done
              </button>
              <button style={S.laterBtn} onClick={() => laterTask(nowTask.id)} disabled={justDone}>
                Not now — later
              </button>
            </div>
            {nextTask && (
              <div style={S.upNext}>
                <span style={S.upNextLabel}>Next</span>
                <span style={{ color: T.ink }}>{nextTask.title}</span>
              </div>
            )}
          </section>
        ) : total > 0 ? (
          <section style={{ ...S.nowCard, textAlign: "center", padding: "44px 24px" }}>
            <div style={{ ...S.nowTitle, fontSize: 26 }}>All clear.</div>
            <div style={{ color: T.sub, fontSize: 15, marginTop: 8 }}>Nothing left today. The time is yours.</div>
          </section>
        ) : (
          <section style={{ ...S.nowCard, textAlign: "center", padding: "40px 24px" }}>
            <div style={{ ...S.nowTitle, fontSize: 23 }}>Set up your day</div>
            <div style={{ color: T.sub, fontSize: 15, margin: "10px 0 22px" }}>
              Add your first task, or start from a typical day and edit it.
            </div>
            <button style={{ ...S.doneBtn, background: doneColor, color: T.doneText, marginTop: 0 }} onClick={loadSample}>
              Load a sample day
            </button>
          </section>
        )}

        {/* day plan */}
        {total > 0 && (
          <section style={{ marginTop: 30 }}>
            <div style={S.sectionHeading}>Today</div>
            {BLOCKS.map((b) => {
              const list = byBlock(b);
              const left = remaining(b).length;
              const isOpen = expanded[b] ?? b === block;
              return (
                <div key={b} style={S.blockGroup}>
                  <button style={S.blockHeader} onClick={() => setExpanded((e) => ({ ...e, [b]: !isOpen }))} aria-expanded={isOpen}>
                    <span style={{ color: T.accent(b), fontSize: 11, width: 14 }}>{BLOCK_GLYPH[b]}</span>
                    <span style={S.blockName}>{BLOCK_LABEL[b]}</span>
                    <span style={S.blockCount}>
                      {list.length === 0 ? "—" : left === 0 ? "done" : `${left} left`}
                    </span>
                    <span style={{ marginLeft: "auto", color: T.faint, fontSize: 11 }}>{isOpen ? "▲" : "▼"}</span>
                  </button>
                  {isOpen && list.map((t) => (
                    <div key={t.id}>
                      <div style={{ ...S.row, opacity: t.done ? 0.4 : 1 }}>
                        <button
                          style={{ ...S.check, borderColor: t.done ? T.check : T.border, background: t.done ? T.check : "transparent" }}
                          onClick={() => toggleDone(t.id)}
                          aria-label={t.done ? "Mark not done" : "Mark done"}
                        >
                          {t.done && <span style={{ color: T.card, fontSize: 14, fontWeight: 700 }}>✓</span>}
                        </button>
                        <button style={S.rowTitleBtn} onClick={() => setActiveRow(activeRow === t.id ? null : t.id)}>
                          <span style={{ textDecoration: t.done ? "line-through" : "none" }}>{t.title}</span>
                          {(t.tag || t.repeats || t.carried) && (
                            <span style={{ display: "flex", gap: 6, marginTop: 4 }}>
                              {t.tag && <span style={S.chipMini}>{t.tag}</span>}
                              {t.repeats && <span style={S.chipMini}>Daily</span>}
                              {t.carried && <span style={S.chipMini}>Yesterday</span>}
                            </span>
                          )}
                        </button>
                      </div>
                      {activeRow === t.id && (
                        <div style={S.rowActions}>
                          <span style={{ fontSize: 12, color: T.faint, marginRight: 2 }}>Move to</span>
                          {BLOCKS.filter((x) => x !== t.block).map((x) => (
                            <button key={x} style={S.actionChip} onClick={() => moveTask(t.id, x)}>
                              {BLOCK_LABEL[x]}
                            </button>
                          ))}
                          <button style={{ ...S.actionChip, color: "#B0524F" }} onClick={() => deleteTask(t.id)}>
                            Delete
                          </button>
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              );
            })}
          </section>
        )}

        <div style={{ height: 110 }} />
      </div>

      <button style={S.fab} onClick={() => setShowAdd(true)} aria-label="Add a task">
        ＋ Add task
      </button>

      {showAdd && <AddSheet T={T} S={S} defaultBlock={block} onAdd={addTask} onClose={() => setShowAdd(false)} />}
      {showThemes && (
        <ThemeSheet T={T} S={S} current={themeKey} onPick={setTheme} onClose={() => setShowThemes(false)} />
      )}

      <style>{`
        @keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
        @keyframes sheetUp { from { transform: translateY(100%); } to { transform: none; } }
        @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }
        button:focus-visible { outline: 2px solid ${T.accent(block)}; outline-offset: 2px; }
        button { -webkit-tap-highlight-color: transparent; }
        input::placeholder { color: ${T.faint}; }
      `}</style>
    </div>
  );
}

/* ---------- Add sheet ---------- */
function AddSheet({ T, S, defaultBlock, onAdd, onClose }) {
  const [title, setTitle] = useState("");
  const [b, setB] = useState(defaultBlock);
  const [tag, setTag] = useState(null);
  const [repeats, setRepeats] = useState(false);
  const inputRef = useRef(null);

  useEffect(() => { inputRef.current?.focus(); }, []);

  const submit = () => {
    const t = title.trim();
    if (!t) return;
    onAdd(t, b, tag, repeats);
  };

  return (
    <div style={S.sheetOverlay} onClick={onClose}>
      <div style={S.sheet} onClick={(e) => e.stopPropagation()}>
        <div style={S.sheetHandle} />
        <div style={S.sheetTitle}>Add a task</div>
        <input
          ref={inputRef}
          style={S.input}
          placeholder="What needs doing?"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          onKeyDown={(e) => e.key === "Enter" && submit()}
        />
        <div style={S.fieldLabel}>When</div>
        <div style={{ display: "flex", gap: 8 }}>
          {BLOCKS.map((x) => (
            <button
              key={x}
              style={{ ...S.pickChip, borderColor: b === x ? T.ink : T.border, color: b === x ? T.ink : T.sub, fontWeight: b === x ? 700 : 500, background: b === x ? T.tint(x) : T.card }}
              onClick={() => setB(x)}
            >
              {BLOCK_LABEL[x]}
            </button>
          ))}
        </div>
        <div style={S.fieldLabel}>Tag <span style={{ fontWeight: 400, color: T.faint }}>(optional)</span></div>
        <div style={{ display: "flex", gap: 8 }}>
          {["Kids", "Work", "Home"].map((k) => (
            <button
              key={k}
              style={{ ...S.pickChip, borderColor: tag === k ? T.ink : T.border, color: tag === k ? T.ink : T.sub, fontWeight: tag === k ? 700 : 500, background: tag === k ? T.tint(b) : T.card }}
              onClick={() => setTag(tag === k ? null : k)}
            >
              {k}
            </button>
          ))}
        </div>
        <button
          style={{ ...S.repeatRow, borderColor: repeats ? T.ink : T.border }}
          onClick={() => setRepeats(!repeats)}
        >
          <span style={{ ...S.check, width: 22, height: 22, minWidth: 22, borderColor: repeats ? T.check : T.border, background: repeats ? T.check : "transparent" }}>
            {repeats && <span style={{ color: T.card, fontSize: 12, fontWeight: 700 }}>✓</span>}
          </span>
          <span style={{ fontSize: 15, color: T.ink }}>
            Repeats daily <span style={{ color: T.faint }}>— routines like lunches, pickup</span>
          </span>
        </button>
        <button
          style={{ ...S.doneBtn, background: title.trim() ? T.done || T.accent(b) : T.border, color: T.doneText, marginTop: 18 }}
          onClick={submit}
          disabled={!title.trim()}
        >
          Add task
        </button>
      </div>
    </div>
  );
}

/* ---------- Theme sheet ---------- */
function ThemeSheet({ T, S, current, onPick, onClose }) {
  return (
    <div style={S.sheetOverlay} onClick={onClose}>
      <div style={S.sheet} onClick={(e) => e.stopPropagation()}>
        <div style={S.sheetHandle} />
        <div style={S.sheetTitle}>Appearance</div>
        {Object.entries(THEMES).map(([k, th]) => (
          <button
            key={k}
            style={{
              display: "flex", alignItems: "center", gap: 14, width: "100%",
              padding: "14px 14px", borderRadius: 14, marginBottom: 8,
              border: `1.5px solid ${current === k ? T.ink : T.border}`,
              background: T.card, cursor: "pointer", textAlign: "left", fontFamily: "inherit",
            }}
            onClick={() => onPick(k)}
          >
            {/* swatch */}
            <span style={{ display: "flex", gap: 3, padding: 6, borderRadius: 10, background: th.bg, border: `1px solid ${T.hairline}` }}>
              <span style={{ width: 14, height: 22, borderRadius: 4, background: th.card, border: `1px solid ${th.border}` }} />
              <span style={{ width: 14, height: 22, borderRadius: 4, background: th.accent("morning") }} />
              <span style={{ width: 14, height: 22, borderRadius: 4, background: th.ink }} />
            </span>
            <span style={{ flex: 1 }}>
              <span style={{ display: "block", fontWeight: 700, fontSize: 15, color: T.ink }}>{th.name}</span>
              <span style={{ display: "block", fontSize: 13, color: T.sub, marginTop: 2 }}>{th.desc}</span>
            </span>
            {current === k && <span style={{ color: T.ink, fontWeight: 700 }}>✓</span>}
          </button>
        ))}
      </div>
    </div>
  );
}

function FontLink() {
  return (
    <style>{`@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap');`}</style>
  );
}

/* ---------- styles ---------- */
function makeStyles(T) {
  const display = { fontFamily: "Inter, -apple-system, sans-serif", letterSpacing: "-0.02em" };
  return {
    page: {
      minHeight: "100vh",
      background: T.bg,
      color: T.ink,
      fontFamily: "Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
      position: "relative",
    },
    container: { maxWidth: 460, margin: "0 auto", padding: "22px 18px 0", position: "relative" },
    header: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 18 },
    dateLine: { ...display, fontWeight: 800, fontSize: 21 },
    blockLine: { fontSize: 13, fontWeight: 600, color: T.sub, marginTop: 5 },
    themeBtn: {
      display: "inline-flex", alignItems: "center", padding: "9px 14px",
      borderRadius: 999, border: `1.5px solid ${T.border}`,
      background: T.card, color: T.sub, fontSize: 13, fontWeight: 700,
      cursor: "pointer", fontFamily: "inherit",
    },
    progressRow: { display: "flex", alignItems: "center", gap: 10, marginBottom: 26 },
    progressTrack: { flex: 1, height: 4, borderRadius: 999, background: T.track, overflow: "hidden" },
    progressFill: { height: "100%", borderRadius: 999, transition: "width .4s ease" },
    progressLabel: { fontSize: 12, fontWeight: 700, color: T.sub, fontVariantNumeric: "tabular-nums" },
    eyebrow: {
      ...display, display: "flex", alignItems: "center", gap: 8,
      fontWeight: 800, fontSize: 11, letterSpacing: "0.16em", textTransform: "uppercase",
      color: T.sub, marginBottom: 10,
    },
    carried: {
      padding: "2px 8px", borderRadius: 999, background: T.tint("morning"),
      color: T.sub, fontSize: 10, letterSpacing: "0.02em", fontWeight: 700, textTransform: "none",
    },
    nowCard: {
      background: T.card, borderRadius: 18, padding: "26px 22px 20px",
      border: `1px solid ${T.hairline}`, boxShadow: T.shadow,
    },
    nowTitle: { ...display, fontWeight: 800, fontSize: 27, lineHeight: 1.2 },
    chip: {
      display: "inline-block", padding: "3px 10px", borderRadius: 999,
      border: `1px solid ${T.border}`, color: T.sub, fontSize: 12, fontWeight: 600,
    },
    doneBtn: {
      display: "block", width: "100%", marginTop: 22, padding: "17px 0",
      borderRadius: 14, border: "none", ...display,
      fontWeight: 700, fontSize: 18, cursor: "pointer",
    },
    laterBtn: {
      display: "block", width: "100%", marginTop: 10, padding: "13px 0",
      borderRadius: 12, border: `1.5px solid ${T.border}`, background: "transparent",
      color: T.sub, fontSize: 15, fontWeight: 600, cursor: "pointer", fontFamily: "inherit",
    },
    upNext: {
      marginTop: 12, padding: "12px 16px", background: T.card,
      border: `1px solid ${T.hairline}`, borderRadius: 12, fontSize: 14,
      display: "flex", alignItems: "baseline", gap: 10,
    },
    upNextLabel: {
      ...display, fontWeight: 800, fontSize: 10, letterSpacing: "0.14em",
      textTransform: "uppercase", color: T.faint,
    },
    sectionHeading: {
      ...display, fontWeight: 800, fontSize: 11, letterSpacing: "0.16em",
      textTransform: "uppercase", color: T.sub, marginBottom: 10,
    },
    blockGroup: {
      background: T.card, borderRadius: 14, marginBottom: 8, overflow: "hidden",
      border: `1px solid ${T.hairline}`,
    },
    blockHeader: {
      display: "flex", alignItems: "center", gap: 10, width: "100%",
      padding: "14px 16px", background: "transparent", border: "none",
      cursor: "pointer", textAlign: "left", fontFamily: "inherit",
    },
    blockName: { ...display, fontWeight: 700, fontSize: 15, color: T.ink },
    blockCount: { fontSize: 12, color: T.faint, fontWeight: 600 },
    row: { display: "flex", alignItems: "center", gap: 12, padding: "12px 16px", borderTop: `1px solid ${T.hairline}` },
    check: {
      width: 26, height: 26, minWidth: 26, borderRadius: 8, border: "1.5px solid",
      display: "flex", alignItems: "center", justifyContent: "center",
      cursor: "pointer", transition: "all .15s ease", background: "transparent",
    },
    rowTitleBtn: {
      background: "none", border: "none", padding: 0, textAlign: "left",
      fontSize: 15, color: T.ink, cursor: "pointer", flex: 1,
      display: "flex", flexDirection: "column", fontFamily: "inherit",
    },
    chipMini: {
      padding: "1px 7px", borderRadius: 999, border: `1px solid ${T.hairline}`,
      color: T.faint, fontSize: 10, fontWeight: 600,
    },
    rowActions: {
      display: "flex", alignItems: "center", gap: 6, flexWrap: "wrap",
      padding: "8px 16px 14px 54px", borderTop: `1px dashed ${T.hairline}`, background: T.rowBg,
    },
    actionChip: {
      padding: "7px 12px", borderRadius: 999, border: `1.5px solid ${T.border}`,
      background: T.card, fontSize: 13, fontWeight: 600, color: T.ink,
      cursor: "pointer", fontFamily: "inherit",
    },
    fab: {
      position: "fixed", bottom: 20, left: "50%", transform: "translateX(-50%)",
      padding: "15px 32px", borderRadius: 999, border: "none",
      background: T.fab, color: T.fabText, fontFamily: "Inter, sans-serif",
      fontWeight: 700, fontSize: 16, letterSpacing: "-0.01em",
      boxShadow: "0 6px 20px rgba(0,0,0,0.25)", cursor: "pointer", zIndex: 20,
    },
    sheetOverlay: {
      position: "fixed", inset: 0, background: T.overlay, zIndex: 30,
      display: "flex", alignItems: "flex-end", justifyContent: "center",
    },
    sheet: {
      background: T.bg, borderRadius: "20px 20px 0 0", padding: "10px 20px 28px",
      width: "100%", maxWidth: 460, animation: "sheetUp .26s ease",
    },
    sheetHandle: { width: 40, height: 4, borderRadius: 999, background: T.border, margin: "6px auto 14px" },
    sheetTitle: { ...display, fontWeight: 800, fontSize: 19, marginBottom: 14, color: T.ink },
    input: {
      width: "100%", boxSizing: "border-box", padding: "15px 16px", fontSize: 16,
      borderRadius: 13, border: `1.5px solid ${T.border}`, outline: "none",
      fontFamily: "inherit", background: T.card, color: T.ink, marginBottom: 4,
    },
    fieldLabel: { ...display, fontWeight: 700, fontSize: 12, color: T.sub, margin: "16px 0 8px" },
    pickChip: {
      flex: 1, padding: "11px 6px", borderRadius: 12, border: "1.5px solid",
      fontSize: 14, cursor: "pointer", fontFamily: "inherit",
    },
    repeatRow: {
      display: "flex", alignItems: "center", gap: 12, width: "100%",
      marginTop: 16, padding: "13px 14px", borderRadius: 13,
      border: "1.5px solid", background: T.card, cursor: "pointer",
      textAlign: "left", fontFamily: "inherit",
    },
  };
}

/* ---------- mount ---------- */
ReactDOM.createRoot(document.getElementById("root")).render(<App />);
