/* Saints Calendar — Workspace (pinned saints as floating tabs on the right edge),
   Etymology / CCC reference panel, and global helpers. */

const { useState: useStateW, useEffect: useEffectW, useCallback: useCallbackW, useRef: useRefW } = React;

// ===== WorkspaceContext: pinned saints + reference state, persisted =====
const WORKSPACE_KEY = "sc.workspace.v1";
const REFERENCE_KEY = "sc.reference.v1";

const WorkspaceContext = React.createContext(null);

const WorkspaceProvider = ({ children, onOpenSaint }) => {
  const [pinned, setPinned] = useStateW(() => {
    try { return JSON.parse(localStorage.getItem(WORKSPACE_KEY) || "[]"); } catch { return []; }
  });
  const [activeId, setActiveId] = useStateW(null); // currently expanded floating panel
  const [refOpen, setRefOpen] = useStateW(false);
  const [refTab, setRefTab] = useStateW("etymology"); // etymology | ccc | bookmarks

  useEffectW(() => {
    localStorage.setItem(WORKSPACE_KEY, JSON.stringify(pinned));
  }, [pinned]);

  const pin = useCallbackW((saintId) => {
    setPinned(p => p.includes(saintId) ? p : [...p, saintId]);
  }, []);
  const unpin = useCallbackW((saintId) => {
    setPinned(p => p.filter(id => id !== saintId));
    setActiveId(a => a === saintId ? null : a);
  }, []);
  const isPinned = useCallbackW((saintId) => pinned.includes(saintId), [pinned]);
  const togglePin = useCallbackW((saintId) => {
    setPinned(p => p.includes(saintId) ? p.filter(id => id !== saintId) : [...p, saintId]);
  }, []);

  const value = {
    pinned, pin, unpin, isPinned, togglePin,
    activeId, setActiveId,
    refOpen, setRefOpen, refTab, setRefTab,
    onOpenSaint,
  };

  return <WorkspaceContext.Provider value={value}>{children}</WorkspaceContext.Provider>;
};

const useWorkspace = () => React.useContext(WorkspaceContext);

// ===== Floating workspace rail (right edge) =====
const WorkspaceRail = () => {
  const ws = useWorkspace();
  if (!ws) return null;
  const { pinned, activeId, setActiveId, unpin, onOpenSaint, refOpen, setRefOpen, refTab, setRefTab } = ws;

  return (
    <>
      {/* Right rail */}
      <div className="ws-rail">
        <button
          className={`ws-rail-tab ws-rail-ref ${refOpen ? "active" : ""}`}
          onClick={() => { setRefOpen(o => !o); setActiveId(null); }}
          title="Reference (etymology, CCC, bookmarks)"
        >
          <span className="ws-rail-glyph">℞</span>
          <span className="ws-rail-label">Reference</span>
        </button>

        {pinned.map((id, i) => {
          const s = window.getSaintById(id);
          if (!s) return null;
          const isActive = activeId === id;
          return (
            <button
              key={id}
              className={`ws-rail-tab ${isActive ? "active" : ""}`}
              style={{ animationDelay: `${i * 60}ms` }}
              onClick={() => { setActiveId(isActive ? null : id); setRefOpen(false); }}
              title={`${s.honorific} ${s.name} — click to peek, drag away to dismiss`}
            >
              <span className="ws-rail-glyph">{s.name.charAt(0)}</span>
              <span className="ws-rail-label">{s.name}</span>
            </button>
          );
        })}

        {pinned.length === 0 && !refOpen && (
          <div className="ws-rail-hint">
            <div className="ws-rail-glyph" style={{ opacity: 0.4 }}>＋</div>
            <div className="ws-rail-label" style={{ opacity: 0.5 }}>Pin saints here</div>
          </div>
        )}
      </div>

      {/* Floating saint peek panel */}
      {activeId && (() => {
        const s = window.getSaintById(activeId);
        if (!s) return null;
        return (
          <div className="ws-peek" key={activeId}>
            <div className="ws-peek-head">
              <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>{s.rank} · {formatDate(s.feast.month, s.feast.day)}</div>
              <div className="ws-peek-actions">
                <button onClick={() => { onOpenSaint(activeId); setActiveId(null); }} title="Open full profile">↗</button>
                <button onClick={() => unpin(activeId)} title="Unpin">×</button>
              </div>
            </div>
            <div style={{ fontFamily: "var(--font-display)", fontSize: 26, lineHeight: 1.1 }}>
              <span style={{ color: "var(--ink-mute)", fontStyle: "italic", fontSize: 15 }}>{s.honorific} </span>{s.name}
            </div>
            <div className="t-meta" style={{ fontStyle: "italic", marginTop: 4 }}>{s.epithet}</div>
            <div className="t-meta" style={{ marginTop: 8 }}>
              {yearLabel(s.dates.born)}–{yearLabel(s.dates.died)} · {s.region}{s.order ? ` · ${s.order.split(" ")[0]}` : ""}
            </div>
            <p style={{ fontSize: 14, color: "var(--ink-soft)", lineHeight: 1.55, marginTop: 12 }}>
              {s.summary.slice(0, 220)}{s.summary.length > 220 ? "…" : ""}
            </p>
            {s.quotes && s.quotes[0] && (
              <blockquote style={{ marginTop: 12, paddingLeft: 14, borderLeft: "2px solid var(--gilt)", fontFamily: "var(--font-display)", fontStyle: "italic", fontSize: 15, color: "var(--ink-soft)", lineHeight: 1.5 }}>
                “{s.quotes[0].text.slice(0, 140)}{s.quotes[0].text.length > 140 ? "…" : ""}”
              </blockquote>
            )}
            <div className="ws-peek-foot">
              <div className="t-meta">Patronage</div>
              <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 4 }}>
                {s.patronage.slice(0, 5).join(" · ")}
              </div>
            </div>
          </div>
        );
      })()}

      {/* Reference panel */}
      {refOpen && <ReferencePanel tab={refTab} setTab={setRefTab} onClose={() => setRefOpen(false)} />}
    </>
  );
};

// ===== Reference panel (etymology, CCC, bookmarks) =====
const ReferencePanel = ({ tab, setTab, onClose }) => {
  const ws = useWorkspace();
  return (
    <div className="ws-ref">
      <div className="ws-ref-head">
        <div className="ws-ref-tabs">
          <button className={tab === "etymology" ? "active" : ""} onClick={() => setTab("etymology")}>Etymology</button>
          <button className={tab === "ccc" ? "active" : ""} onClick={() => setTab("ccc")}>CCC</button>
          <button className={tab === "epistemology" ? "active" : ""} onClick={() => setTab("epistemology")}>Epistemology</button>
          <button className={tab === "bookmarks" ? "active" : ""} onClick={() => setTab("bookmarks")}>Bookmarks</button>
          <button className={tab === "subscribe" ? "active" : ""} onClick={() => setTab("subscribe")}>Subscribe</button>
        </div>
        <button onClick={onClose} className="ws-ref-close">×</button>
      </div>

      <div className="ws-ref-body">
        {tab === "etymology" && <EtymologyTab />}
        {tab === "ccc" && <CCCTab />}
        {tab === "epistemology" && <EpistemologyTab />}
        {tab === "bookmarks" && <BookmarksTab onOpenSaint={ws.onOpenSaint} />}
        {tab === "subscribe" && <SubscribeTab />}
      </div>
    </div>
  );
};

// ----- Etymology -----
const ETYMOLOGY = [
  { term: "Saint", root: "Lat. sanctus", meaning: "set apart, made holy. From sancire (to consecrate, render inviolable).", note: "Greek hagios; Hebrew qadosh — the same conceptual root: ritually distinguished, belonging wholly to God." },
  { term: "Beatus", root: "Lat. beatus", meaning: "happy, blessed. The first formal step of the Roman Catholic process.", note: "Beatification permits public veneration in particular dioceses or orders; canonisation extends it to the universal Church." },
  { term: "Martyr", root: "Gk. μάρτυς (martys)", meaning: "witness — one whose testimony is sealed in blood.", note: "Tertullian, c. 197: ‘the blood of the martyrs is the seed of the Church.’ The word originally bore no necessary connotation of death." },
  { term: "Confessor", root: "Lat. confessor", meaning: "one who confesses the faith publicly without dying for it.", note: "In the early Church, confessores were those who endured imprisonment or torture but were not killed." },
  { term: "Hagiography", root: "Gk. ἅγιος (hagios) + γραφία (graphia)", meaning: "sacred writing — the literary genre of saints' lives.", note: "Bollandist scholarship (since 1643) is the modern critical school." },
  { term: "Canonisation", root: "Gk. κανών (kanon, ‘rule, list’)", meaning: "inscription on the canon (official list) of those publicly venerated.", note: "Reserved to the Pope since the late 12th century." },
  { term: "Doctor of the Church", root: "Lat. doctor (‘teacher’)", meaning: "a saint of eminent learning whose theology the Church holds up as guide.", note: "Currently 37, including four women: Teresa of Ávila, Catherine of Siena, Thérèse of Lisieux, Hildegard." },
  { term: "Patron", root: "Lat. patronus", meaning: "protector, intercessor — by analogy with the Roman patron-client relation.", note: "Patron saints are not invoked as gods but as friends in the heavenly court who pray for those entrusted to them." },
  { term: "Relic", root: "Lat. reliquiae", meaning: "remnants — bones, garments, or objects sanctified by contact with a holy life.", note: "First-class: body. Second-class: possessions. Third-class: objects touched to a first-class relic." },
  { term: "Feast", root: "Lat. festum", meaning: "a day kept festal — set apart from labour for sacred memory.", note: "In the 1969 Roman calendar: Solemnity > Feast > Memorial > Optional Memorial." },
  { term: "Vigil", root: "Lat. vigilia", meaning: "watching — the night-prayer preceding a great feast.", note: "Originally an all-night liturgy; now usually anticipated Mass on the eve." },
  { term: "Octave", root: "Lat. octava (‘eighth’)", meaning: "an eight-day extension of a major feast.", note: "Easter and Christmas retain octaves in the modern Roman calendar." },
  { term: "Novena", root: "Lat. novem (‘nine’)", meaning: "nine days of prayer in preparation or petition.", note: "Patterned on the nine days the apostles spent in the upper room between the Ascension and Pentecost." },
  { term: "Liturgy", root: "Gk. λειτουργία", meaning: "public work, work done on behalf of the people.", note: "In Christian usage from the Septuagint onward: the formal worship of the assembled Church." },
  { term: "Eucharist", root: "Gk. εὐχαριστία (eucharistia)", meaning: "thanksgiving — the central sacrament of Christian worship.", note: "Already so named in the Didache (c. 100)." },
  { term: "Stigmata", root: "Gk. στίγματα (stigmata, ‘marks’)", meaning: "the wounds of Christ visibly impressed on the body of a saint.", note: "First documented case: Francis of Assisi, 1224, on Mt La Verna." },
  { term: "Mystic", root: "Gk. μυστικός (mystikos)", meaning: "hidden, initiated — pertaining to mystery.", note: "In Christian usage: one granted experiential knowledge of God beyond the ordinary sacramental life." },
  { term: "Apostle", root: "Gk. ἀπόστολος (apostolos)", meaning: "one sent forth — emissary.", note: "Used in the New Testament for the Twelve, for Paul, and analogically for later evangelists (e.g. ‘Apostle of Ireland’)." },
  { term: "Cenobite", root: "Gk. κοινός βίος (koinos bios, ‘common life’)", meaning: "monk living in community — distinguished from the hermit (anchorite).", note: "Pachomius of Egypt (d. 348) is reckoned the founder of cenobitic monasticism." },
  { term: "Anchorite", root: "Gk. ἀναχωρητής (anachoretes)", meaning: "one who has withdrawn — a solitary monastic.", note: "Often enclosed in a cell attached to a church; Julian of Norwich is the most famous medieval English anchoress." },
];

const EtymologyTab = () => {
  const [q, setQ] = useStateW("");
  const filtered = ETYMOLOGY.filter(e => !q || (e.term + " " + e.meaning + " " + e.note + " " + e.root).toLowerCase().includes(q.toLowerCase()));
  return (
    <div>
      <div className="t-rubric mb-1" style={{ color: "var(--gilt-deep)" }}>Glossary</div>
      <h3 style={{ fontFamily: "var(--font-display)", fontSize: 22, marginBottom: 4 }}>Catholic etymology</h3>
      <p style={{ fontSize: 13, color: "var(--ink-soft)", marginBottom: 14, lineHeight: 1.55 }}>
        The vocabulary of holiness — Greek, Latin, and Hebrew roots of the words by which the Church names her saints, her sacraments, and her seasons.
      </p>
      <input value={q} onChange={e => setQ(e.target.value)} placeholder="Filter terms…"
        style={{ width: "100%", padding: "8px 12px", border: "1px solid var(--hairline)", background: "var(--parchment)", marginBottom: 14, fontFamily: "var(--font-mono)", fontSize: 12 }} />
      <div className="ws-ref-list">
        {filtered.map(e => (
          <div key={e.term} className="ws-ref-item">
            <div style={{ display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }}>
              <span style={{ fontFamily: "var(--font-display)", fontSize: 19 }}>{e.term}</span>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.08em", color: "var(--ink-mute)", textTransform: "uppercase" }}>{e.root}</span>
            </div>
            <div style={{ fontSize: 14, color: "var(--ink)", marginTop: 4, fontStyle: "italic" }}>{e.meaning}</div>
            <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 4, lineHeight: 1.55 }}>{e.note}</div>
          </div>
        ))}
        {filtered.length === 0 && <div className="t-meta">No matching term.</div>}
      </div>
    </div>
  );
};

// ----- CCC -----
const CCC_REFERENCES = [
  { range: "§946–948", title: "The Communion of Saints", body: "‘What is the Church if not the assembly of all the saints?’ The communion of saints is precisely the Church. It is communion in holy things (sancta) and among holy persons (sancti)." },
  { range: "§954–957", title: "Communion of the heavenly and earthly Church", body: "‘The intercession of the saints. Being more closely united to Christ, those who dwell in heaven fix the whole Church more firmly in holiness…’ They do not cease to intercede with the Father for us." },
  { range: "§828", title: "Canonisation as confirmation of holiness", body: "By canonising some of the faithful, the Church recognises the power of the Spirit of holiness within her and sustains the hope of believers by proposing the saints to them as models and intercessors." },
  { range: "§2683", title: "Saints as witnesses to prayer", body: "The witnesses who have preceded us into the kingdom… contemplate God, praise him, and constantly care for those whom they have left on earth. Their intercession is their most exalted service to God's plan." },
  { range: "§1159–1162", title: "Sacred images and veneration", body: "The Christian icon is not painted with words but with colours. The veneration paid to the image passes to its prototype (St Basil) — Christians do not adore the image but honour the one represented." },
  { range: "§1173", title: "The sanctoral cycle", body: "When the Church keeps the memorials of martyrs and other saints during the annual cycle, she proclaims the Paschal mystery in those who have suffered and been glorified with Christ. She proposes them to the faithful as examples." },
  { range: "§1717", title: "The beatitudes and the saints", body: "The Beatitudes depict the countenance of Jesus Christ and portray his charity. They proclaim the blessings and rewards already secured, however dimly, for Christ's disciples." },
  { range: "§688", title: "The Church teaches us by way of the saints", body: "The Church… knows the Holy Spirit through the apostolic tradition that she preserves; in Sacred Scripture, which the Spirit inspired; in the Magisterium, which he assists; in the sacramental liturgy; in prayer; in charisms and ministries; in the signs of apostolic and missionary life; in the witness of saints, through whom he manifests his holiness and continues the work of salvation." },
  { range: "§1090", title: "Earthly liturgy as foretaste of heavenly", body: "In the earthly liturgy we share in a foretaste of that heavenly liturgy which is celebrated in the holy city of Jerusalem toward which we journey as pilgrims." },
  { range: "§2030", title: "The Church as mother and teacher", body: "It is in the Church, in communion with all the baptised, that the Christian fulfils his vocation. From the Church he receives the Word of God containing the teachings of ‘the law of Christ.’ From the Church he receives the grace of the sacraments… The example of the saints in their varied forms of life and apostolate is offered to the Christian." },
];

const CCCTab = () => {
  const [q, setQ] = useStateW("");
  const filtered = CCC_REFERENCES.filter(r => !q || (r.range + r.title + r.body).toLowerCase().includes(q.toLowerCase()));
  return (
    <div>
      <div className="t-rubric mb-1" style={{ color: "var(--gilt-deep)" }}>Catechism</div>
      <h3 style={{ fontFamily: "var(--font-display)", fontSize: 22, marginBottom: 4 }}>The saints in the CCC</h3>
      <p style={{ fontSize: 13, color: "var(--ink-soft)", marginBottom: 14, lineHeight: 1.55 }}>
        Selected paragraphs from the Catechism of the Catholic Church bearing on the doctrine of holiness, intercession, and the communion of saints.
      </p>
      <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search the catechism…"
        style={{ width: "100%", padding: "8px 12px", border: "1px solid var(--hairline)", background: "var(--parchment)", marginBottom: 14, fontFamily: "var(--font-mono)", fontSize: 12 }} />
      <div className="ws-ref-list">
        {filtered.map(r => (
          <div key={r.range} className="ws-ref-item">
            <div style={{ display: "flex", alignItems: "baseline", justifyContent: "space-between", gap: 10 }}>
              <span style={{ fontFamily: "var(--font-display)", fontSize: 18 }}>{r.title}</span>
              <span style={{ fontFamily: "var(--font-mono)", fontSize: 10, letterSpacing: "0.08em", color: "var(--rubric)", textTransform: "uppercase" }}>{r.range}</span>
            </div>
            <p style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.6, fontStyle: "italic" }}>“{r.body}”</p>
          </div>
        ))}
      </div>
    </div>
  );
};

// ----- Epistemology -----
const EPISTEMOLOGY = [
  { title: "Sources of saintly knowledge", body: "Catholic knowledge of the saints flows from four braided streams: scripture (the apostles and Old Testament holy ones), liturgy (the sanctoral calendar), magisterial declaration (canonisation), and tradition — including the testimony of contemporaries, miracles, and the cultus." },
  { title: "Acta sanctorum", body: "Since 1643 the Bollandists, a Jesuit scholarly society, have been compiling a critical, source-based edition of saints' lives — over 60 folio volumes that distinguish historically reliable material from pious legend." },
  { title: "The four-step process", body: "Servant of God → Venerable → Blessed → Saint. The cause is opened in the diocese of death; heroic virtue is proven; a miracle is verified for beatification; a second for canonisation. (Martyrs may skip the first miracle.)" },
  { title: "Equipollent canonisation", body: "An older form, by which a Pope extends to the universal Church the public cultus of one already venerated locally for a long time without formal canonisation — used by Benedict XVI for Hildegard and by Francis for Peter Faber." },
  { title: "What canonisation does and does not assert", body: "Canonisation is held to be infallible regarding the present beatitude of the saint and the propriety of public veneration. It does not pronounce on the historical accuracy of every detail of the saint's life nor on the prudence of every action they performed." },
  { title: "Cultus and reception", body: "Veneration is not granted by decree alone but received and lived. A saint becomes ‘popular’ when their intercession proves fruitful in the lives of the faithful — a sociological as well as theological reality." },
  { title: "Hagiographic genre", body: "Lives of saints are not modern biographies; they are theological portraits. The reader must read them within their convention: typology, miracle, scriptural allusion, and didactic purpose are constitutive of the genre, not failures of historicity." },
];

const EpistemologyTab = () => (
  <div>
    <div className="t-rubric mb-1" style={{ color: "var(--gilt-deep)" }}>Method</div>
    <h3 style={{ fontFamily: "var(--font-display)", fontSize: 22, marginBottom: 4 }}>Epistemology of holiness</h3>
    <p style={{ fontSize: 13, color: "var(--ink-soft)", marginBottom: 14, lineHeight: 1.55 }}>
      How the Church knows whom she names a saint, and how the historian reads what she has written about them.
    </p>
    <div className="ws-ref-list">
      {EPISTEMOLOGY.map(e => (
        <div key={e.title} className="ws-ref-item">
          <div style={{ fontFamily: "var(--font-display)", fontSize: 18 }}>{e.title}</div>
          <p style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 4, lineHeight: 1.6 }}>{e.body}</p>
        </div>
      ))}
    </div>
  </div>
);

// ----- Bookmarks -----
const BookmarksTab = ({ onOpenSaint }) => {
  const [bookmarks, setBookmarks] = useStateW(() => {
    try { return JSON.parse(localStorage.getItem("sc.bookmarks") || "[]"); } catch { return []; }
  });
  useEffectW(() => {
    const onStorage = () => {
      try { setBookmarks(JSON.parse(localStorage.getItem("sc.bookmarks") || "[]")); } catch {}
    };
    window.addEventListener("storage", onStorage);
    const i = setInterval(onStorage, 800);
    return () => { window.removeEventListener("storage", onStorage); clearInterval(i); };
  }, []);

  const saints = bookmarks.map(id => window.getSaintById(id)).filter(Boolean);
  return (
    <div>
      <div className="t-rubric mb-1" style={{ color: "var(--gilt-deep)" }}>Marginalia</div>
      <h3 style={{ fontFamily: "var(--font-display)", fontSize: 22, marginBottom: 14 }}>Your bookmarks</h3>
      {saints.length === 0 && (
        <p style={{ fontSize: 13, color: "var(--ink-soft)", lineHeight: 1.55 }}>
          No saints bookmarked yet. From any saint's profile, click the bookmark icon to save them here.
        </p>
      )}
      <div className="ws-ref-list">
        {saints.map(s => (
          <button key={s.id} onClick={() => onOpenSaint(s.id)} className="ws-ref-item ws-ref-item-button">
            <div style={{ fontFamily: "var(--font-display)", fontSize: 17 }}>{s.honorific} {s.name}</div>
            <div className="t-meta" style={{ fontStyle: "italic", marginTop: 2 }}>{s.epithet}</div>
            <div className="t-meta" style={{ marginTop: 4 }}>{formatDate(s.feast.month, s.feast.day)} · {yearLabel(s.dates.born)}–{yearLabel(s.dates.died)}</div>
          </button>
        ))}
      </div>
    </div>
  );
};

// ----- Subscribe (ICS feed + email-style digest options) -----
const SUB_KEY = "sc.subscription.v1";

function pad2(n) { return String(n).padStart(2, "0"); }
function escIcs(s) { return String(s || "").replace(/\\/g, "\\\\").replace(/,/g, "\\,").replace(/;/g, "\\;").replace(/\n/g, "\\n"); }

function buildIcs(saints, { years = [2026, 2027], includeAll = false, scopeIds = null } = {}) {
  const lines = [
    "BEGIN:VCALENDAR",
    "VERSION:2.0",
    "PRODID:-//Saints Calendar//Research Platform//EN",
    "CALSCALE:GREGORIAN",
    "METHOD:PUBLISH",
    "X-WR-CALNAME:Saints Calendar",
    "X-WR-CALDESC:Daily feasts of the saints — from Saints Calendar",
    "X-WR-TIMEZONE:UTC",
    "REFRESH-INTERVAL;VALUE=DURATION:PT12H",
    "X-PUBLISHED-TTL:PT12H",
  ];
  const list = includeAll ? saints : saints.filter(s => scopeIds && scopeIds.includes(s.id));
  list.forEach(s => {
    years.forEach(yr => {
      const m = pad2(s.feast.month), d = pad2(s.feast.day);
      const dt = `${yr}${m}${d}`;
      const next = new Date(yr, s.feast.month - 1, s.feast.day + 1);
      const dtEnd = `${next.getFullYear()}${pad2(next.getMonth()+1)}${pad2(next.getDate())}`;
      lines.push(
        "BEGIN:VEVENT",
        `UID:${s.id}-${yr}@saintscalendar.org`,
        `DTSTAMP:${yr}0101T000000Z`,
        `DTSTART;VALUE=DATE:${dt}`,
        `DTEND;VALUE=DATE:${dtEnd}`,
        `SUMMARY:${escIcs((s.honorific || "St") + " " + s.name + (s.epithet ? " — " + s.epithet : ""))}`,
        `DESCRIPTION:${escIcs(s.summary + "\n\nRank: " + s.rank + "\nFeast: " + formatDate(s.feast.month, s.feast.day) + "\nLifespan: " + yearLabel(s.dates.born) + "–" + yearLabel(s.dates.died) + "\nRegion: " + s.region + (s.order ? "\nOrder: " + s.order : "") + "\n\nhttps://saintscalendar.org/saint/" + s.id)}`,
        `CATEGORIES:Saint,${s.classification}${s.order ? ",Order" : ""}`,
        "TRANSP:TRANSPARENT",
        "END:VEVENT"
      );
    });
  });
  lines.push("END:VCALENDAR");
  return lines.join("\r\n");
}

const SubscribeTab = () => {
  const [scope, setScope] = useStateW(() => {
    try { return JSON.parse(localStorage.getItem(SUB_KEY) || '{"mode":"all"}'); } catch { return { mode: "all" }; }
  });
  const [copied, setCopied] = useStateW(false);
  const [email, setEmail] = useStateW("");
  const ws = useWorkspace();

  useEffectW(() => { localStorage.setItem(SUB_KEY, JSON.stringify(scope)); }, [scope]);

  const bookmarks = (() => { try { return JSON.parse(localStorage.getItem("sc.bookmarks") || "[]"); } catch { return []; } })();
  const pinned = ws.pinned;

  const ids = scope.mode === "all" ? null
            : scope.mode === "bookmarks" ? bookmarks
            : scope.mode === "pinned" ? pinned
            : scope.mode === "doctors" ? window.SAINTS.filter(s => s.titles?.includes("Doctor of the Church")).map(s => s.id)
            : scope.mode === "martyrs" ? window.SAINTS.filter(s => s.classification === "martyr").map(s => s.id)
            : [];

  const ics = buildIcs(window.SAINTS, { includeAll: scope.mode === "all", scopeIds: ids });
  const blob = new Blob([ics], { type: "text/calendar" });
  const downloadUrl = URL.createObjectURL(blob);
  const webcalUrl = "webcal://saintscalendar.org/feed.ics" + (scope.mode === "all" ? "" : `?scope=${scope.mode}`);
  const httpsUrl = "https://saintscalendar.org/feed.ics" + (scope.mode === "all" ? "" : `?scope=${scope.mode}`);
  const nov3naUrl = "https://nov3na.com/calendar/subscribe?source=saintscalendar&scope=" + scope.mode;

  const count = ids ? ids.length : window.SAINTS.length;

  return (
    <div>
      <div className="t-rubric mb-1" style={{ color: "var(--gilt-deep)" }}>Calendar feed</div>
      <h3 style={{ fontFamily: "var(--font-display)", fontSize: 22, marginBottom: 4 }}>Subscribe to feasts</h3>
      <p style={{ fontSize: 13, color: "var(--ink-soft)", marginBottom: 14, lineHeight: 1.55 }}>
        Add the sanctoral cycle to Apple Calendar, Google Calendar, Outlook, or your existing Nov3na devotional planner — feasts arrive automatically each year and update when the calendar does.
      </p>

      <div className="t-eyebrow mb-2">Choose what to follow</div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 6, marginBottom: 18 }}>
        {[
          ["all", `Every saint (${window.SAINTS.length})`],
          ["bookmarks", `My bookmarks (${bookmarks.length})`],
          ["pinned", `Pinned saints (${pinned.length})`],
          ["doctors", "Doctors of the Church"],
          ["martyrs", "Martyrs only"],
        ].map(([mode, label]) => (
          <button key={mode}
            className={`chip ${scope.mode === mode ? "active" : ""}`}
            onClick={() => setScope({ mode })}
            style={{ justifyContent: "flex-start", textAlign: "left" }}
          >
            {label}
          </button>
        ))}
      </div>

      <div className="ws-ref-item" style={{ marginBottom: 10 }}>
        <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>One-click subscribe</div>
        <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.55 }}>
          {count} feast{count !== 1 ? "s" : ""} per year, recurring 2026 → 2027.
        </div>
        <div style={{ display: "flex", flexDirection: "column", gap: 6, marginTop: 12 }}>
          <a className="btn btn-primary btn-sm" href={webcalUrl}>📅 Subscribe in Apple Calendar (webcal)</a>
          <a className="btn btn-sm" href={`https://calendar.google.com/calendar/r?cid=${encodeURIComponent(httpsUrl)}`} target="_blank" rel="noopener">Add to Google Calendar</a>
          <a className="btn btn-sm" href={`https://outlook.live.com/calendar/0/addfromweb?url=${encodeURIComponent(httpsUrl)}&name=${encodeURIComponent("Saints Calendar")}`} target="_blank" rel="noopener">Add to Outlook</a>
        </div>
      </div>

      <div className="ws-ref-item" style={{ marginBottom: 10 }}>
        <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>Sister site · Nov3na</div>
        <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.55 }}>
          Your Nov3na novena planner can pull this feed directly. Each feast becomes the candidate first day of a nine-day novena.
        </div>
        <a className="btn btn-primary btn-sm" href={nov3naUrl} target="_blank" rel="noopener" style={{ marginTop: 10 }}>
          Sync with Nov3na <IconExternal />
        </a>
      </div>

      <div className="ws-ref-item" style={{ marginBottom: 10 }}>
        <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>Or download .ics</div>
        <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.55 }}>
          For one-time import without auto-update.
        </div>
        <a className="btn btn-sm" href={downloadUrl} download={`saints-calendar-${scope.mode}.ics`} style={{ marginTop: 10 }}>
          Download {scope.mode}.ics
        </a>
      </div>

      <div className="ws-ref-item" style={{ marginBottom: 10 }}>
        <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>Feed URL</div>
        <div style={{ display: "flex", gap: 6, marginTop: 8 }}>
          <input value={httpsUrl} readOnly
            style={{ flex: 1, padding: "6px 10px", border: "1px solid var(--hairline)", background: "var(--parchment)", fontFamily: "var(--font-mono)", fontSize: 11 }}
            onFocus={e => e.target.select()} />
          <button className="btn btn-sm" onClick={() => { navigator.clipboard.writeText(httpsUrl); setCopied(true); setTimeout(() => setCopied(false), 1400); }}>
            {copied ? "Copied" : "Copy"}
          </button>
        </div>
      </div>

      <div className="ws-ref-item">
        <div className="t-rubric" style={{ color: "var(--gilt-deep)" }}>Email digest (planned)</div>
        <div style={{ fontSize: 13, color: "var(--ink-soft)", marginTop: 6, lineHeight: 1.55 }}>
          Receive each morning's feast in your inbox.
        </div>
        <div style={{ display: "flex", gap: 6, marginTop: 8 }}>
          <input type="email" value={email} onChange={e => setEmail(e.target.value)} placeholder="you@example.com"
            style={{ flex: 1, padding: "6px 10px", border: "1px solid var(--hairline)", background: "var(--parchment)", fontFamily: "var(--font-mono)", fontSize: 11 }} />
          <button className="btn btn-sm" disabled={!email}>Notify me</button>
        </div>
      </div>
    </div>
  );
};

// ===== Pin button (reusable) =====
const PinButton = ({ saintId, size = "sm" }) => {
  const ws = useWorkspace();
  if (!ws) return null;
  const pinned = ws.isPinned(saintId);
  return (
    <button
      onClick={(e) => { e.stopPropagation(); ws.togglePin(saintId); }}
      className={`pin-btn ${pinned ? "pinned" : ""} ${size === "sm" ? "pin-btn-sm" : ""}`}
      title={pinned ? "Unpin from workspace" : "Pin to workspace"}
    >
      <svg viewBox="0 0 24 24" width="14" height="14" fill={pinned ? "currentColor" : "none"} stroke="currentColor" strokeWidth="1.5">
        <path d="M12 2l2 6h6l-5 4 2 7-5-4-5 4 2-7-5-4h6z"/>
      </svg>
      <span>{pinned ? "Pinned" : "Pin"}</span>
    </button>
  );
};

Object.assign(window, {
  WorkspaceProvider, useWorkspace, WorkspaceRail, PinButton,
});
