// screens-home.jsx — Home screen (the centerpiece)

// ─────────────────────────────────────────────────────────────
// Sunday-morning livestream configuration.
//
// To enable the auto-swap that turns the hero into a live YouTube embed
// during Sunday worship hours, set LIVESTREAM_YT_CHANNEL to the YouTube
// channel ID for the church (the long string starting with "UC", found in
// YouTube Studio → Settings → Channel → Advanced settings, or visible in
// the URL when you go to youtube.com/channel/UC...).
//
// Leave as the empty string to disable. While disabled, the hero stays on
// whatever variant you've selected in Tweaks, even on Sunday morning.
// ─────────────────────────────────────────────────────────────
const LIVESTREAM_YT_CHANNEL = 'UC_v5i5K2orztVKT5sF67gbA';
// Hours window in America/Chicago (Central Time). 0 = Sunday.
const LIVESTREAM_WINDOW = {
  weekday: 0,
  startHour: 10, startMinute: 0,
  endHour:   11, endMinute:   45,
};

// ─────────────────────────────────────────────────────────────
// Featured-image hero entries.
//
// Drop a poster JPG/PNG into assets/ (any name), then add an entry below
// with startDate/endDate (inclusive, ISO yyyy-mm-dd, America/Chicago).
// While today's date falls inside any entry's range, the home page hero
// auto-swaps to that poster, overriding both the live-stream auto-swap
// and the Tweaks-panel hero choice. Multiple overlapping entries: the
// FIRST matching one wins (so put time-sensitive entries first).
//
// Examples (commented out — uncomment and edit when you want to feature one):
//
//   {
//     src: 'assets/featured-easter-2026.jpg',
//     headline: 'Easter Sunday',
//     subhead:  'Sunrise service · 6:30 am · then Worship at 10:30',
//     link:     '/events',
//     startDate:'2026-03-30',
//     endDate:  '2026-04-05',
//   },
// ─────────────────────────────────────────────────────────────
const FEATURED_IMAGES = [
  // Add entries here.
];

function activeFeaturedImage() {
  const local = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Chicago' }));
  const today = local.toISOString().slice(0, 10); // yyyy-mm-dd
  for (const f of FEATURED_IMAGES) {
    if (!f || !f.src) continue;
    if (f.startDate && today < f.startDate) continue;
    if (f.endDate   && today > f.endDate)   continue;
    return f;
  }
  return null;
}

// ─────────────────────────────────────────────────────────────
// Bulletin download.
//
// Each Sunday's bulletin lives at assets/bulletins/YYYY-MM-DD.pdf,
// where the date is the upcoming Sunday in Central Time. The
// BulletinDownload component below probes that file with a HEAD
// request on mount; if it 200s, the download button renders. If
// 404, the component renders nothing (no broken link, no clutter).
//
// To post a new week's bulletin: drop the PDF in assets/bulletins/
// named with the Sunday's date (e.g. 2026-05-10.pdf), commit and push.
// The button auto-appears on the home page.
// ─────────────────────────────────────────────────────────────
function upcomingSundayIsoDates(count = 12) {
  // Returns the next `count` Sunday dates (today inclusive if today is Sunday)
  // in America/Chicago, ISO yyyy-mm-dd.
  //
  // Important: format the date using LOCAL methods, not toISOString(). The
  // toISOString() method converts to UTC first — which silently shifts the
  // date forward by one day after about 7 PM Central. That bug caused the
  // bulletin probe to look for the wrong date and silently miss the file.
  const local = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Chicago' }));
  const day = local.getDay();
  const addThis = day === 0 ? 0 : 7 - day;
  const dates = [];
  const cur = new Date(local);
  cur.setDate(cur.getDate() + addThis);
  const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
  for (let i = 0; i < count; i++) {
    dates.push(fmt(cur));
    cur.setDate(cur.getDate() + 7);
  }
  return dates;
}

function BulletinDownload({ theme, setModal }) {
  // Auto-discovers the bulletin: probes the next 12 Sundays and uses the
  // first PDF that exists. Drop any future Sunday's PDF into the
  // assets/bulletins/ folder and it surfaces here automatically — no
  // code changes needed week to week.
  const [available, setAvailable] = React.useState(null); // { url, date } | null

  React.useEffect(() => {
    let cancelled = false;
    const dates = upcomingSundayIsoDates(12);
    (async () => {
      for (const date of dates) {
        const url = `assets/bulletins/${date}.pdf`;
        try {
          // cache: 'no-store' forces a fresh network roundtrip every time,
          // bypassing both the browser's HTTP cache and any service-worker
          // cache that might be holding a stale "not found" response from
          // before the bulletin PDF was uploaded.
          const r = await fetch(url, { method: 'HEAD', cache: 'no-store' });
          if (cancelled) return;
          // Verify the response is ACTUALLY a PDF, not HTML rewritten by
          // Azure's 404 → web.html fallback. A missing file would look "ok"
          // by HTTP status but ship Content-Type: text/html.
          const ctype = (r.headers.get('content-type') || '').toLowerCase();
          if (r.ok && ctype.includes('application/pdf')) {
            setAvailable({ url, date });
            return;
          }
        } catch (e) {}
      }
      if (!cancelled) setAvailable(null);
    })();
    return () => { cancelled = true; };
  }, []);

  if (!available) return null;

  const labelDate = (() => {
    try {
      return new Date(available.date + 'T12:00:00').toLocaleDateString('en-US', {
        timeZone: 'America/Chicago', weekday: 'short', month: 'short', day: 'numeric',
      });
    } catch (e) { return available.date; }
  })();

  // Header label: "This Sunday's" if it's the upcoming Sunday, else "Upcoming".
  const thisSun = upcomingSundayIsoDates(1)[0];
  const isThisSunday = available.date === thisSun;
  const kicker = isThisSunday ? "†   This Sunday's Bulletin   †" : "†   Upcoming Bulletin   †";

  // Tapping the card opens the in-page PDF viewer modal. If the modal
  // system isn't wired up for some reason, fall back to opening the PDF
  // in a new tab via window.open.
  const handleClick = () => {
    if (setModal) {
      setModal({
        kind: 'pdf',
        url: available.url,
        title: 'Order of Worship · ' + labelDate,
      });
    } else {
      window.open(available.url, '_blank', 'noopener,noreferrer');
    }
  };

  return (
    <div style={{ padding: '14px 22px 22px' }}>
      <button onClick={handleClick} style={{
        width: '100%', textAlign: 'left',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        padding: '14px 18px', background: theme.paper,
        border: `1px solid ${theme.gold}66`, color: 'inherit',
        cursor: 'pointer', fontFamily: 'inherit',
      }}>
        <div>
          <div style={{ ...smallCaps(theme, 9), color: theme.gold, marginBottom: 4 }}>
            {kicker}
          </div>
          <div style={{ fontFamily: theme.fonts.display, fontSize: 16, fontStyle: 'italic', color: theme.ink }}>
            Order of Worship · {labelDate}
          </div>
        </div>
        <div style={{ ...smallCaps(theme, 10), color: theme.accent, flexShrink: 0, marginLeft: 14 }}>
          Open ›
        </div>
      </button>
    </div>
  );
}

function isLivestreamHour() {
  if (!LIVESTREAM_YT_CHANNEL) return false;
  const local = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Chicago' }));
  if (local.getDay() !== LIVESTREAM_WINDOW.weekday) return false;
  const mins = local.getHours() * 60 + local.getMinutes();
  const start = LIVESTREAM_WINDOW.startHour * 60 + LIVESTREAM_WINDOW.startMinute;
  const end   = LIVESTREAM_WINDOW.endHour   * 60 + LIVESTREAM_WINDOW.endMinute;
  return mins >= start && mins <= end;
}

// Sunday-morning easter egg: a soft banner that appears only on Sunday between
// 8am and noon Central, inviting visitors to that morning's worship and showing
// the day's key verse. Dismissable, with dismissal tied to today's date so it
// can come back next Sunday.
function SundayMorningGreeting({ theme }) {
  const [dismissed, setDismissed] = React.useState(true);

  React.useEffect(() => {
    // Get the current time in America/Chicago, regardless of host TZ.
    const now = new Date();
    const local = new Date(now.toLocaleString('en-US', { timeZone: 'America/Chicago' }));
    const isSunday = local.getDay() === 0;
    const hour = local.getHours();
    const inWindow = isSunday && hour >= 8 && hour < 12;
    if (!inWindow) { setDismissed(true); return; }
    // Check localStorage for today-specific dismissal
    const key = 'mumc.sundayGreet.' + local.toISOString().slice(0, 10);
    try {
      if (localStorage.getItem(key) === '1') { setDismissed(true); return; }
    } catch (e) {}
    setDismissed(false);
  }, []);

  if (dismissed) return null;

  let kv = null;
  try { kv = (typeof getKeyVerse === 'function') ? getKeyVerse() : null; } catch (e) {}

  const dismiss = () => {
    try {
      const local = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Chicago' }));
      localStorage.setItem('mumc.sundayGreet.' + local.toISOString().slice(0, 10), '1');
    } catch (e) {}
    setDismissed(true);
  };

  return (
    <div style={{
      padding: '14px 18px',
      background: `linear-gradient(180deg, ${theme.gold}26, ${theme.gold}10)`,
      borderBottom: `1px solid ${theme.gold}55`,
      animation: 'fadein 0.4s ease',
    }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
        <div style={{ color: theme.gold, fontFamily: theme.fonts.display, fontSize: 22, lineHeight: 1, fontStyle: 'italic', flexShrink: 0 }}>†</div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 4 }}>
            This morning · Worship at 10:30
          </div>
          {kv ? (
            <>
              <div style={{ fontFamily: theme.fonts.display, fontSize: 16, fontStyle: 'italic', color: theme.ink, lineHeight: 1.35 }}>
                "{kv.text}"
              </div>
              <div style={{ ...smallCaps(theme, 8), color: theme.inkMute, marginTop: 4 }}>
                {kv.cite} · {kv.sundayName}
              </div>
            </>
          ) : (
            <div style={{ fontFamily: theme.fonts.display, fontSize: 16, fontStyle: 'italic', color: theme.ink }}>
              You are welcome to join us in the sanctuary.
            </div>
          )}
        </div>
        <button onClick={dismiss} aria-label="Dismiss"
          style={{
            background: 'transparent', border: 'none', cursor: 'pointer',
            color: theme.inkMute, padding: 4, fontFamily: theme.fonts.mono, fontSize: 14, lineHeight: 1, flexShrink: 0,
          }}>×</button>
      </div>
    </div>
  );
}

function HomeScreen({ theme, onNav, setModal }) {
  // countdown to next Sunday 10:30am (Sunday School at 9:30)
  const [now, setNow] = React.useState(new Date());
  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  const next = nextSunday();
  const total = 7 * 24 * 3600 * 1000;
  const remaining = Math.max(0, next.getTime() - now.getTime());
  const fillPct = 1 - remaining / total;
  const days = Math.floor(remaining / (24 * 3600 * 1000));
  const hours = Math.floor((remaining % (24 * 3600 * 1000)) / (3600 * 1000));
  const mins = Math.floor((remaining % (3600 * 1000)) / 60000);
  const secs = Math.floor((remaining % 60000) / 1000);

  return (
    <div style={{ background: theme.bg, color: theme.ink, paddingBottom: 60 }} className="paper-grain">
      <SeasonRibbon theme={theme} />
      <SaintRibbon theme={theme} />
      <SundayMorningGreeting theme={theme} />

      {/* HERO — priority: featured image (date-windowed) → livestream
          (Sunday-morning auto-swap) → tweaks-panel selection. */}
      {(() => {
        const featured = activeFeaturedImage();
        if (featured) return <HeroFeatured theme={theme} featured={featured} onNav={onNav} />;
        const effectiveHero = isLivestreamHour() ? 'livestream' : theme.hero;
        switch (effectiveHero) {
          case 'manuscript': return <HeroManuscript theme={theme} fillPct={fillPct} days={days} hours={hours} mins={mins} secs={secs} />;
          case 'verse':      return <HeroVerse      theme={theme} setModal={setModal} />;
          case 'image':      return <HeroImageSunlit theme={theme} />;
          case 'livestream': return <HeroLivestream theme={theme} />;
          case 'countdown':  return <HeroCountdown  theme={theme} fillPct={fillPct} days={days} hours={hours} mins={mins} secs={secs} />;
          default:           return <HeroImageSunlit theme={theme} />;
        }
      })()}

      {/* Pray with us button */}
      <div style={{ padding: '12px 22px 0' }}>
        <button onClick={() => setModal && setModal('pray')} style={{
          width: '100%', padding: '14px',
          background: 'transparent', color: theme.ink,
          border: `1px solid ${theme.gold}`,
          fontFamily: theme.fonts.mono, fontSize: 11, letterSpacing: '0.18em', textTransform: 'uppercase', cursor: 'pointer',
        }}>† &nbsp; Pray with us — 3 minutes &nbsp; †</button>
      </div>

      {/* Chalice + countdown only — between Pray-with-us and The Lord's Day.
          Skipped when the hero is already Manuscript (which contains the same
          chalice/countdown internally) so it doesn't duplicate. */}
      {theme.hero !== 'manuscript' && (
        <div style={{ marginTop: 18 }}>
          <ChaliceCountdown theme={theme} fillPct={fillPct} days={days} hours={hours} mins={mins} secs={secs} />
          <AddToCalendar theme={theme} />
        </div>
      )}

      <MissalRule theme={theme} label="The Lord's Day" />

      {/* This Sunday's bulletin (only renders if a PDF exists for the date) */}
      <BulletinDownload theme={theme} setModal={setModal} />

      {/* QUICK ACTIONS — illuminated index */}
      <div style={{ padding: '0 22px' }}>
        <div style={{ ...smallCaps(theme, 9), color: theme.inkMute, marginBottom: 10 }}>
          The Index · Tap to enter
        </div>
        <IlluminatedIndex theme={theme} onNav={onNav} />
      </div>

      <div style={{ padding: '24px 22px 0' }}>
        <MissalRule theme={theme} label="This Week" />
      </div>

      {/* THIS WEEK — schedule list */}
      <ThisWeek theme={theme} />

      <div style={{ padding: '24px 22px 0' }}>
        <MissalRule theme={theme} label="This Week's Prayer" />
      </div>

      {/* COLLECT — moved up directly under This Week */}
      <Collect theme={theme} />

      <div style={{ padding: '24px 22px 0' }}>
        <MissalRule theme={theme} label="Hymn of the Week" />
      </div>

      {/* HYMN OF THE WEEK — rotates by liturgical season */}
      <HymnOfTheWeekCard theme={theme} onOpen={() => setModal && setModal('hymn')} />

      <div style={{ padding: '24px 22px 0' }}>
        <MissalRule theme={theme} label="Lectionary" />
      </div>

      {/* LECTIONARY — today's readings */}
      <Lectionary theme={theme} setModal={setModal} />

      {/* EXAMEN — appears after 6 PM (the traditional evening practice) */}
      <ExamenCard theme={theme} onOpen={() => setModal && setModal('examen')} />

      {/* Push notification opt-in (renders nothing if unsupported / unconfigured).
          The component renders its own MissalRule so the whole section disappears
          gracefully on browsers that can't subscribe. */}
      <NotificationOptIn theme={theme} />

      {/* Year wheel */}
      <div style={{ padding: '24px 22px 0' }}>
        <MissalRule theme={theme} label="The Year" />
      </div>
      <YearWheel theme={theme} size={300} />

      {/* FOOTER */}
      <div style={{
        padding: '32px 22px 24px', textAlign: 'center',
        ...smallCaps(theme, 9), color: theme.inkMute, lineHeight: 1.8,
      }}>
        Monticello United Methodist<br/>
        <a href="https://maps.apple.com/?address=130+East+Broad+Street,+Monticello,+MS+39654" style={{ color: 'inherit', textDecoration: 'none' }}>
          130 East Broad Street<br/>
          Monticello, Mississippi
        </a><br/>
        <span style={{ fontFamily: theme.fonts.display, fontStyle: 'italic', fontSize: 14, textTransform: 'none', letterSpacing: 0 }}>
          — soli Deo gloria —
        </span>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// ChaliceCountdown — just the chalice + d/h/m ticker box, used standalone
// on the home page as well as inside the Manuscript hero variant.
// ─────────────────────────────────────────────────────────────
// AddToCalendar — generates a standards-compliant .ics (iCalendar) file as a
// data URL. Tapping the button on iOS pops the Calendar's "Add Event" sheet,
// on Android Chrome opens the Google Calendar add-event flow, on desktop
// downloads the file (which double-click opens in Apple Calendar / Outlook /
// Google Calendar).
//
// The event is set to recur weekly forever — one tap subscribes the visitor
// to every Sunday Worship 10:30 am Central. They can edit or delete from
// their own calendar app.
function buildSundayWorshipIcs() {
  // Compute next Sunday at 10:30 AM Central, in Central wall-clock terms.
  const local = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Chicago' }));
  const day = local.getDay();
  const addThis = day === 0 ? 0 : 7 - day;
  const sun = new Date(local);
  sun.setDate(sun.getDate() + addThis);
  const yyyy = sun.getFullYear();
  const mm = String(sun.getMonth() + 1).padStart(2, '0');
  const dd = String(sun.getDate()).padStart(2, '0');
  const dateOnly = `${yyyy}${mm}${dd}`;
  const dtstart = `${dateOnly}T103000`;
  const dtend   = `${dateOnly}T113000`;
  const dtstamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d{3}/, '');
  const uid = `sunday-worship-${dateOnly}@monticelloumc.church`;

  // Minimal but valid VTIMEZONE for America/Chicago (CST/CDT).
  const lines = [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//Monticello UMC//Website//EN',
    'CALSCALE:GREGORIAN',
    'METHOD:PUBLISH',
    'BEGIN:VTIMEZONE',
    'TZID:America/Chicago',
    'BEGIN:STANDARD',
    'DTSTART:19701101T020000',
    'RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU',
    'TZOFFSETFROM:-0500',
    'TZOFFSETTO:-0600',
    'TZNAME:CST',
    'END:STANDARD',
    'BEGIN:DAYLIGHT',
    'DTSTART:19700308T020000',
    'RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU',
    'TZOFFSETFROM:-0600',
    'TZOFFSETTO:-0500',
    'TZNAME:CDT',
    'END:DAYLIGHT',
    'END:VTIMEZONE',
    'BEGIN:VEVENT',
    `UID:${uid}`,
    `DTSTAMP:${dtstamp}`,
    `DTSTART;TZID=America/Chicago:${dtstart}`,
    `DTEND;TZID=America/Chicago:${dtend}`,
    'RRULE:FREQ=WEEKLY;BYDAY=SU',
    'SUMMARY:Sunday Worship at Monticello UMC',
    'LOCATION:Monticello United Methodist Church\\, 130 East Broad Street\\, Monticello\\, Mississippi 39654',
    'DESCRIPTION:Sunday Worship at 10:30 am. Sunday School at 9:30 am. All are welcome.\\nmonticelloumc.church',
    'URL:https://monticelloumc.church/',
    'STATUS:CONFIRMED',
    'TRANSP:OPAQUE',
    'END:VEVENT',
    'END:VCALENDAR',
  ];
  return lines.join('\r\n');
}

function AddToCalendar({ theme }) {
  // Memoize so the data URL is stable across re-renders (avoids the .ics
  // being re-computed every tick of the countdown).
  const href = React.useMemo(() => {
    const ics = buildSundayWorshipIcs();
    return 'data:text/calendar;charset=utf-8,' + encodeURIComponent(ics);
  }, []);

  return (
    <div style={{ padding: '0 22px' }}>
      <a href={href}
         download="monticello-umc-sunday-worship.ics"
         style={{
           display: 'block',
           padding: '12px 14px', marginTop: 10,
           background: theme.accent,
           color: theme.paper,
           border: 'none',
           textAlign: 'center', textDecoration: 'none',
           fontFamily: theme.fonts.mono, fontSize: 11,
           letterSpacing: '0.18em', textTransform: 'uppercase',
           cursor: 'pointer',
         }}>
        † &nbsp; Add to my calendar &nbsp; †
      </a>
    </div>
  );
}

function ChaliceCountdown({ theme, fillPct, days, hours, mins, secs }) {
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 18,
      padding: '14px 22px',
      borderTop: `1px solid ${theme.rule}`,
      borderBottom: `1px solid ${theme.rule}`,
      background: theme.paper,
    }}>
      <Chalice theme={theme} fillPct={fillPct} width={64} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ ...smallCaps(theme, 8), color: theme.inkMute, marginBottom: 4 }}>
          Until the gathering
        </div>
        <div style={{
          fontFamily: theme.fonts.display, fontSize: 28, lineHeight: 1,
          color: theme.ink, fontWeight: 500, marginBottom: 6,
        }}>
          {days}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>d</span>
          <span style={{ color: theme.gold, margin: '0 4px' }}>·</span>
          {String(hours).padStart(2,'0')}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>h</span>
          <span style={{ color: theme.gold, margin: '0 4px' }}>·</span>
          {String(mins).padStart(2,'0')}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>m</span>
        </div>
        <div style={{ fontFamily: theme.fonts.body, fontSize: 13, fontStyle: 'italic', color: theme.inkSoft }}>
          Sunday Worship · 10:30 in the morning
        </div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// HERO: Manuscript page — the headline hero
// ─────────────────────────────────────────────────────────────
function HeroManuscript({ theme, fillPct, days, hours, mins, secs }) {
  return (
    <div style={{
      position: 'relative',
      padding: '24px 22px 24px',
      background: theme.paper,
      borderBottom: `1px solid ${theme.rule}`,
      overflow: 'hidden',
    }}>
      {/* corner ornament — abstract Gothic arch with Celtic cross, line only */}
      <div style={{ position: 'absolute', top: 18, right: 18, opacity: 0.7 }}>
        <svg width="56" height="72" viewBox="0 0 56 72" fill="none">
          {/* Gothic pointed arch */}
          <path d="M6 70 L6 28 Q6 6 28 4 Q50 6 50 28 L50 70"
                stroke={theme.gold} strokeWidth="1" strokeLinecap="round" strokeLinejoin="round"/>
          {/* base */}
          <path d="M4 70 L52 70" stroke={theme.gold} strokeWidth="1" strokeLinecap="round"/>
          {/* Celtic cross — vertical bar */}
          <path d="M28 18 L28 64" stroke={theme.gold} strokeWidth="1.1" strokeLinecap="round"/>
          {/* horizontal crossbar */}
          <path d="M14 38 L42 38" stroke={theme.gold} strokeWidth="1.1" strokeLinecap="round"/>
          {/* nimbus halo at intersection */}
          <circle cx="28" cy="38" r="9" stroke={theme.gold} strokeWidth="1" fill="none"/>
          {/* tiny center dot */}
          <circle cx="28" cy="38" r="1.2" fill={theme.gold}/>
        </svg>
      </div>

      <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 14 }}>
        Anno Domini 2026 · {theme.season.name}
      </div>

      <h1 style={{
        fontFamily: theme.fonts.display, fontWeight: 500,
        fontSize: 44, lineHeight: 0.98, letterSpacing: '-0.01em',
        margin: '0 0 10px', color: theme.ink,
      }}>
        Monticello<br/>
        <span style={{ fontStyle: 'italic', color: theme.accent }}>United Methodist</span>
      </h1>

      <div style={{
        fontFamily: theme.fonts.display, fontStyle: 'italic',
        // Keep readable size (15px) and force one line. Tightening comes
        // from three places: (1) thin spaces (U+2009) around the interpuncts
        // instead of regular spaces — they're visually narrower; (2) negative
        // letter-spacing to compress glyphs; (3) negative word-spacing to
        // compress remaining word gaps. Together this fits the tagline on
        // one line even on iPhone Air in Zoomed display mode (~349px).
        fontSize: 14,
        letterSpacing: '-0.005em',
        whiteSpace: 'nowrap',
        color: theme.inkSoft, lineHeight: 1.4, marginBottom: 18,
      }}>{`The ancient Way · the living Word · the abundant Life`}</div>

      {/* The Chalice + countdown — the "hero metric" */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 18,
        padding: '14px 0',
        borderTop: `1px solid ${theme.rule}`,
        borderBottom: `1px solid ${theme.rule}`,
      }}>
        <Chalice theme={theme} fillPct={fillPct} width={64} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ ...smallCaps(theme, 8), color: theme.inkMute, marginBottom: 4 }}>
            Until the gathering
          </div>
          <div style={{
            fontFamily: theme.fonts.display, fontSize: 28, lineHeight: 1,
            color: theme.ink, fontWeight: 500, marginBottom: 6,
          }}>
            {days}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>d</span>
            <span style={{ color: theme.gold, margin: '0 4px' }}>·</span>
            {String(hours).padStart(2,'0')}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>h</span>
            <span style={{ color: theme.gold, margin: '0 4px' }}>·</span>
            {String(mins).padStart(2,'0')}<span style={{ ...smallCaps(theme, 11), marginLeft: 3, color: theme.inkMute }}>m</span>
          </div>
          <div style={{ fontFamily: theme.fonts.body, fontSize: 13, fontStyle: 'italic', color: theme.inkSoft }}>
            Sunday Worship · 10:30 in the morning
          </div>
        </div>
      </div>

      <button onClick={() => {}} style={{
        marginTop: 14, width: '100%', padding: '13px 18px',
        background: theme.ink, color: theme.paper,
        border: 'none', cursor: 'pointer',
        fontFamily: theme.fonts.mono, fontSize: 11,
        letterSpacing: '0.18em', textTransform: 'uppercase',
      }}>
        † &nbsp; Add to my calendar &nbsp; †
      </button>
    </div>
  );
}

// HERO: Verse of the day
function HeroVerse({ theme, setModal }) {
  // Pull the key verse for this Sunday from the lectionary helper.
  // Falls back to a generic seasonal verse if no curated one exists.
  let verse = 'Comfort, comfort my people, says your God. Speak tenderly to Jerusalem, and proclaim that her warfare is ended.';
  let ref = 'Isaiah 40 : 1—2';
  let kicker = '†   A reading from the prophet Isaiah';
  try {
    if (typeof getKeyVerse === 'function') {
      const k = getKeyVerse();
      if (k && k.text && k.cite) {
        verse  = k.text;
        ref    = k.cite;
        kicker = `†   The verse for ${k.sundayName}`;
      }
    }
  } catch (e) {}

  const first = (verse || 'A').charAt(0);
  const rest  = verse.slice(1);

  return (
    <div style={{ padding: '34px 26px 30px', background: theme.paper, borderBottom: `1px solid ${theme.rule}`, position: 'relative' }}>
      <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 18 }}>{kicker}</div>
      <div style={{ fontFamily: theme.fonts.display, fontSize: 30, lineHeight: 1.1, color: theme.ink, fontStyle: 'italic', marginBottom: 14, fontWeight: 400 }}>
        <DropCap letter={first} theme={theme} size={56} />
        {rest}
      </div>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, marginTop: 12 }}>
        <div style={{ ...smallCaps(theme, 10), color: theme.inkMute }}>{ref}</div>
        {setModal && (
          <button onClick={() => setModal({ kind: 'share-verse', verse, cite: ref })} style={{
            background: 'transparent', color: theme.gold,
            border: `1px solid ${theme.gold}88`, padding: '6px 12px', cursor: 'pointer',
            fontFamily: theme.fonts.mono, fontSize: 9, letterSpacing: '0.18em', textTransform: 'uppercase',
          }}>↗ &nbsp; Share</button>
        )}
      </div>
    </div>
  );
}

// HERO: Image (sanctuary) — hand-tinted photograph of the actual sanctuary
function HeroImageSunlit({ theme }) {
  return (
    <SanctuaryPhoto theme={theme} height={300}>
      <div style={{
        position: 'absolute', left: 0, right: 0, bottom: 0, padding: '24px 22px 26px',
        background: `linear-gradient(180deg, transparent, ${theme.paper}ee 60%, ${theme.paper})`,
      }}>
        <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 8 }}>
          † &nbsp; The sanctuary &nbsp; †
        </div>
        <h1 style={{ fontFamily: theme.fonts.display, fontWeight: 500, fontSize: 36, lineHeight: 1, margin: '0 0 6px', color: theme.ink }}>
          Monticello <span style={{ fontStyle: 'italic', color: theme.accent }}>UMC</span>
        </h1>
        <div style={{
          fontFamily: theme.fonts.display, fontStyle: 'italic',
          fontSize: 14, color: theme.gold,
          letterSpacing: '-0.005em', whiteSpace: 'nowrap',
        }}>{`The ancient Way  ·  the living Word  ·  the abundant Life`}</div>
      </div>
    </SanctuaryPhoto>
  );
}

// HERO: Livestream
// HERO: Featured image — a configurable poster for a date-windowed event.
function HeroFeatured({ theme, featured, onNav }) {
  const isInternal = (featured.link || '').startsWith('/');
  const handleTap = (e) => {
    if (!featured.link) return;
    if (isInternal && onNav) {
      e.preventDefault();
      onNav(featured.link.replace(/^\//, ''));
    }
  };
  const Wrapper = featured.link ? 'a' : 'div';
  return (
    <Wrapper
      href={featured.link || undefined}
      onClick={featured.link ? handleTap : undefined}
      style={{
        display: 'block', textDecoration: 'none', color: 'inherit',
        position: 'relative',
        background: theme.bgAlt,
        borderBottom: `1px solid ${theme.rule}`,
        cursor: featured.link ? 'pointer' : 'default',
      }}>
      <img src={featured.src}
           alt={featured.headline || 'Featured'}
           style={{ display: 'block', width: '100%', height: 'auto' }} />
      {(featured.headline || featured.subhead) && (
        <div style={{
          padding: '14px 22px 18px',
          background: `linear-gradient(180deg, transparent, ${theme.paper})`,
        }}>
          {featured.headline && (
            <div style={{ fontFamily: theme.fonts.display, fontWeight: 500, fontSize: 28, lineHeight: 1.05, color: theme.ink }}>
              {featured.headline}
            </div>
          )}
          {featured.subhead && (
            <div style={{ fontFamily: theme.fonts.display, fontStyle: 'italic', fontSize: 14, color: theme.inkSoft, marginTop: 6, lineHeight: 1.4 }}>
              {featured.subhead}
            </div>
          )}
        </div>
      )}
    </Wrapper>
  );
}

function HeroLivestream({ theme }) {
  // Ring the church bell once per session when the livestream hero appears.
  // Stored in sessionStorage so refreshing during service doesn't re-toll.
  React.useEffect(() => {
    try {
      if (sessionStorage.getItem('mumc.bellRung') === '1') return;
      sessionStorage.setItem('mumc.bellRung', '1');
      window.playSound && window.playSound('church-bell');
    } catch (e) {}
  }, []);
  const live = isLivestreamHour();
  const haveStream = !!LIVESTREAM_YT_CHANNEL;

  // No channel configured yet — show the original placeholder with a quiet
  // setup hint visible only in the source comment, not on the page.
  if (!haveStream) {
    return (
      <div style={{ padding: 22, background: theme.paper, borderBottom: `1px solid ${theme.rule}` }}>
        <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 10 }}>
          ◉ Sunday Worship
        </div>
        <h1 style={{ fontFamily: theme.fonts.display, fontWeight: 500, fontSize: 36, lineHeight: 1, margin: '0 0 14px', color: theme.ink }}>
          Sunday Worship<br/><span style={{ fontStyle: 'italic', color: theme.accent }}>10:30 in the morning</span>
        </h1>
        <div style={{ position: 'relative', aspectRatio: '16 / 10', background: theme.bgAlt, border: `1px solid ${theme.rule}`, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <div style={{ width: 60, height: 60, borderRadius: '50%', background: theme.accent, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <svg width="20" height="20" viewBox="0 0 20 20"><path d="M5 3 L17 10 L5 17 Z" fill={theme.paper}/></svg>
          </div>
        </div>
      </div>
    );
  }

  // YouTube's persistent channel-live embed: shows the current live stream if
  // streaming, or the most recent broadcast/upload if not. We skip autoplay
  // outside the live window so the user has to tap to start playback.
  const embedSrc = `https://www.youtube.com/embed/live_stream?channel=${encodeURIComponent(LIVESTREAM_YT_CHANNEL)}` + (live ? '&autoplay=1' : '');

  return (
    <div style={{ background: theme.paper, borderBottom: `1px solid ${theme.rule}` }}>
      <div style={{ padding: '18px 22px 12px' }}>
        <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 6 }}>
          {live ? '◉   Live now' : '◉   Sunday Worship'}
        </div>
        <h1 style={{ fontFamily: theme.fonts.display, fontWeight: 500, fontSize: 32, lineHeight: 1, margin: 0, color: theme.ink }}>
          {live ? 'We are gathered.' : <>Sunday Worship<br/><span style={{ fontStyle: 'italic', color: theme.accent }}>10:30 in the morning</span></>}
        </h1>
      </div>
      <div style={{ position: 'relative', aspectRatio: '16 / 9', background: theme.bgAlt }}>
        <iframe
          src={embedSrc}
          title="Sunday Worship · Monticello UMC live stream"
          allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen"
          allowFullScreen
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', border: 0 }}
        />
      </div>
    </div>
  );
}

// HERO: pure countdown
function HeroCountdown({ theme, fillPct, days, hours, mins, secs }) {
  return (
    <div style={{ padding: '40px 22px 30px', background: theme.paper, borderBottom: `1px solid ${theme.rule}`, textAlign: 'center' }}>
      <div style={{ ...smallCaps(theme, 9), color: theme.accent, marginBottom: 18 }}>† Until we gather †</div>
      <div style={{ display: 'flex', justifyContent: 'center', gap: 18, marginBottom: 22 }}>
        {[['days', days], ['hours', hours], ['mins', mins], ['secs', secs]].map(([l, v]) => (
          <div key={l}>
            <div style={{ fontFamily: theme.fonts.display, fontSize: 48, lineHeight: 1, color: theme.ink, fontWeight: 500 }}>
              {String(v).padStart(2,'0')}
            </div>
            <div style={{ ...smallCaps(theme, 8), color: theme.inkMute, marginTop: 4 }}>{l}</div>
          </div>
        ))}
      </div>
      <Chalice theme={theme} fillPct={fillPct} width={70} />
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Illuminated Index — the main nav as an illuminated table
// ─────────────────────────────────────────────────────────────
function IlluminatedIndex({ theme, onNav }) {
  const items = [
    { id: 'visit',   title: 'New Here',    sub: 'A guide for first visitors',  icon: 'door',    folio: 'i' },
    { id: 'prayer',  title: 'Prayer Chapel', sub: 'Light a candle · be lifted',  icon: 'candle',  folio: 'ii' },
    { id: 'office',  title: 'The Daily Office', sub: 'Pray the hours with the Church', icon: 'hands',   folio: 'iii' },
    { id: 'give',    title: 'Gifts & Offerings', sub: 'An act of worship',     icon: 'alms',    folio: 'iv' },
    { id: 'events',  title: 'Calendar and Events', sub: 'Feasts, fasts, fellowship', icon: 'star', folio: 'v' },
    { id: 'about',   title: 'What We Believe', sub: 'Creed, sacraments, story', icon: 'book',   folio: 'vi' },
    { id: 'contact', title: 'Get in Touch',    sub: 'Pastoral care · church business', icon: 'pin', folio: 'vii' },
  ];
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      {items.map((it, i) => (
        <button key={it.id} onClick={() => onNav(it.id)}
          style={{
            display: 'flex', alignItems: 'center', gap: 14,
            padding: theme.density === 'compact' ? '10px 0' : '14px 0',
            background: 'transparent', border: 'none',
            borderBottom: i < items.length - 1 ? `1px solid ${theme.ruleSoft}` : 'none',
            cursor: 'pointer', textAlign: 'left',
          }}>
          {/* folio number */}
          <div style={{
            ...smallCaps(theme, 10), color: theme.gold,
            width: 24, textAlign: 'right', fontWeight: 500,
          }}>{it.folio}</div>
          {/* icon */}
          <div style={{
            width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: theme.accent, flexShrink: 0,
          }}>{Icons[it.icon](20, theme.accent)}</div>
          {/* text */}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: theme.fonts.display, fontSize: 20, color: theme.ink, lineHeight: 1.1, fontWeight: 500 }}>
              {it.title}
            </div>
            <div style={{ fontFamily: theme.fonts.body, fontSize: 12, color: theme.inkSoft, fontStyle: 'italic', marginTop: 2 }}>
              {it.sub}
            </div>
          </div>
          {/* leader dots + arrow */}
          <div style={{ color: theme.inkMute, fontSize: 18, fontFamily: theme.fonts.display }}>›</div>
        </button>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// CategoryLabel — small caps tag rendered next to an event when the
// iCal description carries a #hashtag. Whatever word follows the
// hash becomes the category. The five common ones get curated colors;
// any other tag (e.g. #youth, #prayer, #meeting) renders cleanly
// in gold by default. The catchall 'event' renders nothing — the
// absence of a chip is itself a signal of "ordinary event".
//
// Categories are open-ended by design so the pastor can evolve the
// vocabulary in iCloud without touching code.
// ─────────────────────────────────────────────────────────────
const CATEGORY_PALETTE = {
  worship:     { label: 'Worship',     color: 'gold' },
  fellowship:  { label: 'Fellowship',  color: 'accent' },
  celebration: { label: 'Celebration', color: 'gold' },
  study:       { label: 'Study',       color: 'inkSoft' },
  outreach:    { label: 'Outreach',    color: 'accent' },
};

function titleCase(s) {
  if (!s) return '';
  return s.charAt(0).toUpperCase() + s.slice(1);
}

function CategoryLabel({ theme, category }) {
  if (!category || category === 'event') return null;
  const meta = CATEGORY_PALETTE[category];
  const fg = meta ? (theme[meta.color] || theme.gold) : theme.gold;
  const label = meta ? meta.label : titleCase(category);
  return (
    <span style={{
      ...smallCaps(theme, 8),
      color: fg,
      borderLeft: `2px solid ${fg}`,
      paddingLeft: 6,
      lineHeight: 1.2,
    }}>{label}</span>
  );
}

// ─────────────────────────────────────────────────────────────
// This Week schedule
// ─────────────────────────────────────────────────────────────
function ThisWeek({ theme }) {
  const [items, setItems] = React.useState(null); // null = loading, [] = empty, [...] = ok

  React.useEffect(() => {
    let cancelled = false;
    fetch('/api/events')
      .then(r => r.ok ? r.json() : Promise.reject(new Error('HTTP ' + r.status)))
      .then(data => {
        if (cancelled) return;
        const tz = 'America/Chicago';
        const now = new Date();
        const horizon = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); // next 7 days
        const upcoming = (data.events || [])
          .filter(ev => {
            const d = new Date(ev.start);
            return d >= now && d <= horizon;
          })
          .slice(0, 6)
          .map(ev => {
            const d = new Date(ev.start);
            return {
              day:  d.toLocaleDateString('en-US', { weekday: 'short', timeZone: tz }),
              date: d.toLocaleDateString('en-US', { day: '2-digit', timeZone: tz }),
              t:    ev.allDay ? '' : d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', timeZone: tz }).toLowerCase().replace(' ', ''),
              title: ev.title,
              sub:   ev.location ? ev.location.split(',')[0] : '',
              category: ev.category || 'event',
            };
          });
        setItems(upcoming);
      })
      .catch(() => { if (!cancelled) setItems([]); });
    return () => { cancelled = true; };
  }, []);

  if (items === null) {
    return (
      <div style={{ padding: '20px 22px', fontFamily: theme.fonts.body, fontStyle: 'italic', color: theme.inkMute, fontSize: 13 }}>
        Reading the calendar…
      </div>
    );
  }

  if (items.length === 0) {
    return (
      <div style={{ padding: '20px 22px', fontFamily: theme.fonts.body, fontStyle: 'italic', color: theme.inkSoft, fontSize: 13 }}>
        Nothing else on the calendar this week.
      </div>
    );
  }

  return (
    <div style={{ padding: '0 22px' }}>
      {items.map((it, i) => (
        <div key={i} style={{
          display: 'flex', alignItems: 'baseline', gap: 14,
          padding: '12px 0',
          borderBottom: i < items.length - 1 ? `1px solid ${theme.ruleSoft}` : 'none',
        }}>
          {/* date column */}
          <div style={{ width: 38, flexShrink: 0, textAlign: 'center' }}>
            <div style={{ ...smallCaps(theme, 9), color: theme.inkMute }}>{it.day}</div>
            <div style={{ fontFamily: theme.fonts.display, fontSize: 22, color: theme.accent, lineHeight: 1, fontWeight: 500 }}>{it.date}</div>
          </div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontFamily: theme.fonts.display, fontSize: 17, color: theme.ink, fontWeight: 500 }}>{it.title}</div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, flexWrap: 'wrap', marginTop: 2 }}>
              {it.category && it.category !== 'event' && <CategoryLabel theme={theme} category={it.category} />}
              {it.sub && <div style={{ fontFamily: theme.fonts.body, fontSize: 12, color: theme.inkSoft, fontStyle: 'italic' }}>{it.sub}</div>}
            </div>
          </div>
          {it.t && <div style={{ ...smallCaps(theme, 9), color: theme.inkMute, flexShrink: 0 }}>{it.t}</div>}
        </div>
      ))}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Lectionary — today's readings
// ─────────────────────────────────────────────────────────────
function Lectionary({ theme, setModal }) {
  // Pull live readings for the upcoming Sunday from the RCL helper.
  // Falls back gracefully if for some reason the helper isn't available.
  let readings = null;
  let sundayName = '';
  let yearLetter = '';
  let keyVerse = null;
  try {
    if (typeof getRCLToday === 'function') {
      const rcl = getRCLToday();
      if (rcl && rcl.readings) {
        sundayName = rcl.name || '';
        yearLetter = rcl.year || '';
        readings = [
          { kind: 'First Lesson', ref: rcl.readings.first,   key: 'first' },
          { kind: 'Psalter',      ref: rcl.readings.psalm,   key: 'psalm' },
          { kind: 'Epistle',      ref: rcl.readings.epistle, key: 'epistle' },
          { kind: 'Holy Gospel',  ref: rcl.readings.gospel,  key: 'gospel', highlight: true },
        ];
      }
    }
    if (typeof getKeyVerse === 'function') {
      const kv = getKeyVerse();
      if (kv && kv.text && kv.cite) keyVerse = kv;
    }
  } catch (e) { /* fall through */ }

  if (!readings) {
    return (
      <div style={{ padding: '12px 22px', fontFamily: theme.fonts.body, fontStyle: 'italic', color: theme.inkMute, fontSize: 13 }}>
        Lectionary readings will appear here.
      </div>
    );
  }

  // Build a Bible Gateway link for tap-through to the full passage. NRSVUE is
  // the Methodist/UMC default; swap version code if the church prefers another.
  const bgLink = (ref) => {
    const search = encodeURIComponent(ref.replace(/—/g, '-').replace(/\s+/g, ' '));
    return `https://www.biblegateway.com/passage/?search=${search}&version=NRSVUE`;
  };

  return (
    <div style={{ padding: '0 22px' }}>
      {sundayName && (
        <div style={{ marginBottom: 6 }}>
          <div style={{ fontFamily: theme.fonts.display, fontSize: 19, color: theme.ink, fontStyle: 'italic', fontWeight: 500, lineHeight: 1.2 }}>
            {sundayName}
          </div>
          {yearLetter && (
            <div style={{ ...smallCaps(theme, 9), color: theme.inkMute, marginTop: 2 }}>
              Year {yearLetter} · Revised Common Lectionary
            </div>
          )}
        </div>
      )}
      {readings.map((r, i) => (
        <a key={i} href={bgLink(r.ref)} target="_blank" rel="noopener noreferrer"
          style={{
            display: 'block', textDecoration: 'none', cursor: 'pointer',
            padding: '14px 0',
            borderBottom: i < readings.length - 1 ? `1px solid ${theme.ruleSoft}` : 'none',
          }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline' }}>
            <span style={{ ...smallCaps(theme, 9), color: r.highlight ? theme.accent : theme.inkMute }}>{r.kind}</span>
            <span style={{ fontFamily: theme.fonts.display, fontSize: 15, color: theme.ink, fontStyle: 'italic' }}>{r.ref}</span>
          </div>
        </a>
      ))}

      {keyVerse && setModal && (
        <div style={{ marginTop: 14, paddingTop: 12, borderTop: `1px solid ${theme.ruleSoft}`, display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', gap: 12 }}>
          <div style={{ fontFamily: theme.fonts.body, fontStyle: 'italic', fontSize: 13, color: theme.inkSoft, flex: 1 }}>
            "{keyVerse.text}"
          </div>
          <button onClick={() => setModal({ kind: 'share-verse', verse: keyVerse.text, cite: keyVerse.cite })}
            style={{
              background: 'transparent', color: theme.gold,
              border: `1px solid ${theme.gold}88`, padding: '6px 12px', cursor: 'pointer',
              fontFamily: theme.fonts.mono, fontSize: 9, letterSpacing: '0.18em', textTransform: 'uppercase',
              flexShrink: 0,
            }}>↗ &nbsp; Share</button>
        </div>
      )}

      {/* Read ahead — next Sunday's full lectionary, sitting on the home
          page (not inside the share modal) so visitors can prepare to
          read ahead without opening anything else. */}
      {typeof ReadAheadCard === 'function' && (
        <div style={{ marginTop: 16 }}>
          <ReadAheadCard theme={theme} />
        </div>
      )}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Collect of the Day
// ─────────────────────────────────────────────────────────────
function Collect({ theme }) {
  // Pull the proper Collect for this Sunday from the date-aware helper.
  // Falls back to a generic prayer if the helper isn't loaded.
  let text = '';
  try {
    if (typeof getCollect === 'function') {
      const c = getCollect();
      if (c && c.text) text = c.text;
    }
  } catch (e) { /* fall through */ }
  if (!text) {
    text = 'O Lord, mercifully receive the prayers of your people who call upon you, and grant that they may know and understand what things they ought to do, and also may have grace and power faithfully to accomplish them; through Jesus Christ our Lord.';
  }

  // Strip a trailing "Amen." — we render that ourselves in styled small caps.
  const body = text.replace(/\s*Amen\.?\s*$/i, '').trim();
  // First character becomes the drop-cap; the rest renders inline.
  const first = body.charAt(0) || 'O';
  const rest = body.slice(1);

  return (
    <div style={{
      padding: '8px 22px 4px', background: theme.paper, margin: '0 22px',
      borderLeft: `2px solid ${theme.gold}`, marginTop: 4,
    }}>
      <div style={{ fontFamily: theme.fonts.display, fontSize: 16, lineHeight: 1.5, color: theme.ink, fontStyle: 'italic', padding: '14px 14px 6px', fontWeight: 400 }}>
        <DropCap letter={first} theme={theme} size={48} />
        {rest} <span style={{ ...smallCaps(theme, 10), color: theme.gold, fontStyle: 'normal' }}>Amen.</span>
      </div>
    </div>
  );
}

// helper: next Sunday at 10:30
function nextSunday() {
  const d = new Date();
  const day = d.getDay();
  const add = day === 0 ? (d.getHours() < 11 ? 0 : 7) : (7 - day);
  const target = new Date(d);
  target.setDate(d.getDate() + add);
  target.setHours(10, 30, 0, 0);
  return target;
}

Object.assign(window, { HomeScreen, isLivestreamHour, LIVESTREAM_YT_CHANNEL, LIVESTREAM_WINDOW });
