// ShareCite.jsx — Cite + Share system for The Amos Project.
// Exports (on window):
//   ShareButton, CiteButton       → topbar pills (pair)
//   ShareIconButton               → compact doc-card share icon
//   ShareSheet, CiteSheet         → modals (controlled)
//   HighlightSharePill            → floating selection pill (mounts once at app root; auto-activates)
//   useCiteShare()                → hook returning { openShare(ref), openCite(ref), closeAll, sharing, citing }
//   CiteShareProvider             → wraps the app, owns the sheet state + renders modals once
//   buildShareRef(...)            → normalizer for ref objects

(function(){
  const BASE = 'https://worldmission.media';

  // ── Ref normalizer ────────────────────────────────────
  // Accepts ad-hoc objects from different surfaces and produces a shared shape:
  //   { kind, title, subtitle, edition, editor, year, url, description, authors, doi, section, highlight }
  function buildShareRef(partial) {
    const r = Object.assign({
      kind: 'work',          // 'work' | 'article' | 'collection' | 'study' | 'pericope' | 'library'
      title: 'Untitled',
      subtitle: '',
      edition: 'Amos Project edition 2026',
      editor: 'World Mission Media',
      year: 2026,
      url: BASE,
      description: '',
      authors: [],
      doi: null,
      section: null,         // e.g. "Chapter 9", "Ode 11"
      highlight: null,
      collectionKey: null,   // 'patristic' | 'parabiblical' | 'qumran' | 'vernacular' | 'greek' | 'hebrew' | 'latin'
      accent: null            // explicit hex override; wins over collectionKey
    }, partial || {});
    return r;
  }

  // Collection accent palette (mirrors CollectionPage.ACCENT).
  const COLL_ACCENT = {
    patristic:    '#b8443a',
    parabiblical: '#8b6d9e',
    qumran:       '#8a7b58',
    vernacular:   '#26828F',
    greek:        '#5b7aa8',
    hebrew:       '#7a9579',
    latin:        '#d4a24c'
  };
  function accentFor(target) {
    if (!target) return '#0a3f48';
    if (target.accent) return target.accent;
    if (target.collectionKey && COLL_ACCENT[target.collectionKey]) return COLL_ACCENT[target.collectionKey];
    return '#0a3f48'; // default Amos Project teal
  }
  // Darken a hex by `amt` in 0..1.
  function shade(hex, amt) {
    const h = hex.replace('#','');
    const n = parseInt(h.length === 3 ? h.split('').map(c=>c+c).join('') : h, 16);
    let r = (n>>16)&255, g = (n>>8)&255, b = n&255;
    if (amt < 0) { const k = 1 + amt; r*=k; g*=k; b*=k; }
    else { r += (255-r)*amt; g += (255-g)*amt; b += (255-b)*amt; }
    const to = v => Math.max(0, Math.min(255, Math.round(v))).toString(16).padStart(2,'0');
    return '#' + to(r) + to(g) + to(b);
  }

  // ── URL builders ──────────────────────────────────────
  function urlFor(ref) {
    let u = ref.url || BASE;
    if (ref.section && !/[?#]/.test(u)) u += '#' + slug(ref.section);
    if (ref.highlight) u += (u.includes('?') ? '&' : '?') + 'h=' + encodeURIComponent(ref.highlight).slice(0, 120);
    return u;
  }
  function slug(s) {
    return String(s).toLowerCase().replace(/[^\w]+/g,'-').replace(/^-+|-+$/g,'');
  }

  function autoShareText(ref) {
    const section = ref.section ? ' · ' + ref.section : '';
    const hl = ref.highlight ? '\n\n\u201C' + trunc(ref.highlight, 180) + '\u201D' : '';
    if (ref.kind === 'library')    return 'The Amos Project — an open, scholarly library of early Christian writings.' + hl;
    if (ref.kind === 'collection') return 'Reading ' + ref.title + ' on The Amos Project — ' + (ref.description || 'a critical edition of early Christian texts.') + hl;
    if (ref.kind === 'study')      return 'A deep study of ' + ref.title + section + ' on The Amos Project.' + hl;
    if (ref.kind === 'article')    return ref.title + ' — editorial article, The Amos Project.' + hl;
    return ref.title + section + (ref.subtitle ? ' — ' + ref.subtitle : '') + hl;
  }
  function trunc(s, n) { s = String(s); return s.length > n ? s.slice(0, n-1) + '\u2026' : s; }

  // ── OG card preview (rendered inside share sheet) ─────
  function OgCard({ target }) {
    const url = urlFor(target);
    const host = url.replace(/^https?:\/\//,'').split('/')[0];
    const accent = accentFor(target);
    const dark = shade(accent, -0.45);
    const mid = shade(accent, -0.2);
    const ogStyle = {
      '--og-accent': accent,
      '--og-accent-dark': dark,
      '--og-accent-mid': mid,
      background:
        'radial-gradient(circle at 18% 28%, ' + accent + '55, transparent 55%),' +
        'radial-gradient(circle at 85% 85%, ' + dark + 'cc, transparent 60%),' +
        'linear-gradient(135deg, ' + dark + ' 0%, ' + mid + ' 100%)'
    };
    return React.createElement('div', { className:'amos-sc-og' },
      React.createElement('div', { className:'amos-sc-og-img', style: ogStyle },
        React.createElement('div', { className:'amos-sc-og-brand' },
          'WORLDMISSION.MEDIA',
          React.createElement('span', { className:'dot' }, '·'),
          (target.kind === 'library' ? 'LIBRARY' : (target.kind === 'collection' ? 'COLLECTION' : (target.kind === 'article' ? 'EDITORIAL ARTICLE' : (target.kind === 'study' ? 'DEEP STUDY' : 'CRITICAL EDITION'))))
        ),
        React.createElement('div', { className:'amos-sc-og-title' },
          target.title + (target.section ? ' · ' + target.section : '')
        ),
        React.createElement('div', { className:'amos-sc-og-meta' },
          target.edition && React.createElement('span', null, 'Ed. ', React.createElement('b', null, target.editor || 'Amos Project')),
          target.year && React.createElement('span', null, '© ', React.createElement('b', null, target.year)),
          target.doi && React.createElement('span', null, 'DOI ', React.createElement('b', null, target.doi))
        )
      ),
      React.createElement('div', { className:'amos-sc-og-foot' },
        React.createElement('span', { className:'url' }, host + (url.split(host)[1] || '/')),
        React.createElement('span', { className:'amos-sc-og-label' }, 'PREVIEW')
      )
    );
  }

  // ── Network icons (inline SVG) ────────────────────────
  const NetIcon = (kind, size=16) => {
    const base = { width:size, height:size, viewBox:'0 0 24 24', fill:'currentColor' };
    switch (kind) {
      case 'x': return React.createElement('svg', base,
        React.createElement('path', { d:'M18.244 2H21.5l-7.5 8.57L23 22h-6.85l-5.36-6.72L4.6 22H1.34l8.05-9.2L1 2h7.04l4.84 6.17L18.244 2Zm-1.2 18h1.89L7.05 4H5.04l12 16Z' })
      );
      case 'facebook': return React.createElement('svg', base,
        React.createElement('path', { d:'M22 12a10 10 0 1 0-11.56 9.88v-7H8v-2.88h2.44V9.84c0-2.42 1.44-3.75 3.64-3.75 1.06 0 2.16.18 2.16.18v2.38H15.1c-1.2 0-1.58.75-1.58 1.52V12H16.9l-.43 2.88h-2.94v7A10 10 0 0 0 22 12Z' })
      );
      case 'linkedin': return React.createElement('svg', base,
        React.createElement('path', { d:'M4.98 3.5a2.5 2.5 0 1 1 0 5 2.5 2.5 0 0 1 0-5ZM3 9.5h4v11H3v-11Zm6 0h3.84v1.52h.05c.53-1 1.84-2.05 3.78-2.05 4.05 0 4.8 2.66 4.8 6.12v5.4H17.4V15.5c0-1.3-.02-2.97-1.8-2.97-1.82 0-2.1 1.42-2.1 2.88v5.08H9.5v-11Z' })
      );
      case 'whatsapp': return React.createElement('svg', base,
        React.createElement('path', { d:'M20.52 3.48A11.76 11.76 0 0 0 12.02 0C5.43 0 .08 5.34.08 11.9a11.8 11.8 0 0 0 1.6 5.95L0 24l6.33-1.66a11.88 11.88 0 0 0 5.7 1.45h.01c6.58 0 11.93-5.35 11.93-11.92 0-3.18-1.24-6.17-3.45-8.39Zm-8.5 18.3a9.9 9.9 0 0 1-5.04-1.38l-.36-.21-3.74.98 1-3.64-.24-.38a9.87 9.87 0 0 1-1.51-5.24c0-5.46 4.45-9.9 9.92-9.9 2.65 0 5.13 1.03 7 2.9a9.8 9.8 0 0 1 2.9 7c0 5.46-4.45 9.88-9.93 9.88Zm5.44-7.4c-.3-.15-1.77-.87-2.04-.97-.27-.1-.47-.15-.67.15-.2.3-.77.97-.94 1.17-.17.2-.35.22-.65.08-.3-.15-1.26-.47-2.4-1.48a9 9 0 0 1-1.66-2.07c-.17-.3-.02-.46.13-.6.14-.14.3-.36.45-.54.15-.18.2-.3.3-.5.1-.2.05-.37-.02-.52-.08-.15-.67-1.62-.92-2.22-.24-.58-.49-.5-.67-.5-.17 0-.37-.03-.57-.03s-.52.07-.8.37c-.27.3-1.04 1.02-1.04 2.48 0 1.47 1.07 2.88 1.22 3.08.15.2 2.1 3.22 5.1 4.52.72.3 1.27.48 1.7.62.71.23 1.36.2 1.87.12.57-.08 1.77-.72 2.02-1.42.25-.7.25-1.3.18-1.42-.07-.12-.27-.2-.57-.35Z' })
      );
      case 'telegram': return React.createElement('svg', base,
        React.createElement('path', { d:'M12 24C5.373 24 0 18.627 0 12S5.373 0 12 0s12 5.373 12 12-5.373 12-12 12Zm5.56-16.92c.1-.34-.1-.5-.37-.37L5.9 11.1c-.37.15-.37.35-.07.45l2.9.9 6.7-4.22c.32-.2.6-.1.37.13l-5.4 4.88-.2 3 1.43-1.38 2.47 1.83c.45.25.78.12.9-.42l1.56-7.2Z' })
      );
      case 'email': return React.createElement('svg', base,
        React.createElement('path', { d:'M3 5h18a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1Zm1 2.3V18h16V7.3l-8 5.2-8-5.2ZM4.4 7l7.6 4.94L19.6 7H4.4Z' })
      );
      case 'reddit': return React.createElement('svg', base,
        React.createElement('path', { d:'M22 12.05c0-1.1-.9-2-2-2-.54 0-1.03.22-1.4.57-1.42-.97-3.33-1.58-5.45-1.65l1.05-3.32 2.9.65a1.5 1.5 0 1 0 .2-.88l-3.32-.75c-.2-.05-.4.07-.47.26l-1.17 3.7c-2.15.07-4.1.68-5.55 1.68-.38-.37-.88-.6-1.44-.6-1.1 0-2 .9-2 2 0 .72.38 1.34.95 1.68a3.9 3.9 0 0 0-.08.77c0 2.93 3.8 5.3 8.45 5.3s8.45-2.37 8.45-5.3c0-.26-.03-.52-.08-.77.57-.34.95-.96.95-1.68ZM7 13.75a1.5 1.5 0 1 1 3 0 1.5 1.5 0 0 1-3 0Zm8.35 3.8c-1.03 1.02-3 1.1-3.58 1.1-.58 0-2.55-.08-3.58-1.1a.35.35 0 0 1 0-.5.37.37 0 0 1 .5 0c.65.65 2.04.88 3.08.88 1.04 0 2.43-.23 3.08-.88a.37.37 0 0 1 .5 0c.15.14.15.36 0 .5Zm-.28-2.3a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3Z' })
      );
      case 'bluesky': return React.createElement('svg', base,
        React.createElement('path', { d:'M5.8 3.78C8.87 6.08 12.16 10.75 13.3 13.3c1.15-2.55 4.44-7.22 7.5-9.52 2.22-1.66 5.8-2.94 5.8 1.14 0 .82-.47 6.85-.74 7.83-.95 3.4-4.42 4.27-7.5 3.75 5.4.92 6.77 3.95 3.8 6.98-5.65 5.76-8.12-1.45-8.76-3.3l-.1-.3-.1.3c-.64 1.85-3.11 9.06-8.76 3.3-2.97-3.03-1.6-6.06 3.8-6.98-3.08.52-6.55-.35-7.5-3.75C.46 11.77 0 5.74 0 4.92c0-4.08 3.58-2.8 5.8-1.14Z' })
      );
      case 'mastodon': return React.createElement('svg', base,
        React.createElement('path', { d:'M23.27 5.34c-.35-2.6-2.65-4.65-5.38-5.05C17.43.23 15.68 0 11.85 0h-.03c-3.83 0-4.65.23-5.1.3C4.06.69 1.64 2.52 1.05 5.16.77 6.46.74 7.9.79 9.22c.07 1.9.09 3.78.26 5.66.12 1.25.34 2.48.63 3.7.57 2.24 2.82 4.11 5.04 4.89 2.38.8 4.95.94 7.4.38.26-.06.53-.13.79-.22a12 12 0 0 0 2.55-1.3c.03-.02.04-.05.04-.1v-2.4c0-.04-.02-.09-.06-.12-.05-.03-.1-.04-.14-.03-1.57.36-3.18.55-4.8.55-2.78 0-3.53-1.3-3.75-1.84a5.7 5.7 0 0 1-.33-1.48.1.1 0 0 1 .04-.1.12.12 0 0 1 .1 0c1.55.36 3.13.54 4.72.54.38 0 .77 0 1.16-.01 1.6-.04 3.3-.13 4.87-.44.04 0 .08-.02.11-.03 2.49-.47 4.86-1.95 5.1-5.7.01-.15.04-1.55.04-1.7.01-.52.18-3.7-.02-5.65ZM19.5 14.6h-2.4V9c0-1.23-.51-1.86-1.54-1.86-1.13 0-1.7.72-1.7 2.15v3.12h-2.4V9.29c0-1.43-.57-2.15-1.7-2.15-1.03 0-1.54.63-1.54 1.86v5.6H5.83V8.85c0-1.24.32-2.22.95-2.94a3.3 3.3 0 0 1 2.63-1.1c1.2 0 2.11.46 2.72 1.38l.6.99.6-.99c.61-.92 1.52-1.38 2.72-1.38 1.07 0 1.96.37 2.63 1.1.63.72.95 1.7.95 2.94v5.75Z' })
      );
      case 'copy': return React.createElement('svg', Object.assign({}, base, { fill:'none', stroke:'currentColor', strokeWidth:2, strokeLinecap:'round', strokeLinejoin:'round' }),
        React.createElement('rect', { x:9, y:9, width:13, height:13, rx:2 }),
        React.createElement('path', { d:'M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1' })
      );
      case 'qr': return React.createElement('svg', Object.assign({}, base, { fill:'none', stroke:'currentColor', strokeWidth:2 }),
        React.createElement('rect', { x:3, y:3, width:7, height:7, rx:1 }),
        React.createElement('rect', { x:14, y:3, width:7, height:7, rx:1 }),
        React.createElement('rect', { x:3, y:14, width:7, height:7, rx:1 }),
        React.createElement('path', { d:'M14 14h3v3M21 14v7M17 17v4M14 21h3' })
      );
      case 'share': return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:1.75, strokeLinecap:'round', strokeLinejoin:'round' },
        React.createElement('circle', { cx:18, cy:5, r:3 }),
        React.createElement('circle', { cx:6, cy:12, r:3 }),
        React.createElement('circle', { cx:18, cy:19, r:3 }),
        React.createElement('path', { d:'M8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98' })
      );
      case 'cite': return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:1.75, strokeLinecap:'round', strokeLinejoin:'round' },
        React.createElement('path', { d:'M8 10a3 3 0 0 0-3 3 3 3 0 0 0 3 3h1v1a3 3 0 0 1-3 3' }),
        React.createElement('path', { d:'M17 10a3 3 0 0 0-3 3 3 3 0 0 0 3 3h1v1a3 3 0 0 1-3 3' })
      );
      case 'download': return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:1.75, strokeLinecap:'round', strokeLinejoin:'round' },
        React.createElement('path', { d:'M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4' }),
        React.createElement('path', { d:'M7 10l5 5 5-5' }),
        React.createElement('path', { d:'M12 15V3' })
      );
      case 'check': return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:2.2, strokeLinecap:'round', strokeLinejoin:'round' },
        React.createElement('path', { d:'M20 6 9 17l-5-5' })
      );
      case 'x-close': return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:1.75, strokeLinecap:'round', strokeLinejoin:'round' },
        React.createElement('path', { d:'M18 6 6 18M6 6l12 12' })
      );
    }
    return null;
  };

  // ── QR code renderer — tiny pure-JS Type-1 QR (21×21 modules, ~17 chars) ──
  // For longer URLs, we render a stylized QR placeholder (a deterministic pattern) rather than fail.
  // The pattern is recognizable and lets us mock the feature without a QR lib.
  function drawQR(canvas, text) {
    const ctx = canvas.getContext('2d');
    const S = 29;         // 29x29 for visual weight
    const cell = canvas.width / S;
    ctx.fillStyle = '#fff';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = '#0d1117';

    // Deterministic hash → boolean grid
    const hash = strHash(text);
    const grid = [];
    for (let y = 0; y < S; y++) {
      grid[y] = [];
      for (let x = 0; x < S; x++) {
        grid[y][x] = ((hash * (x + 1) * 31 + y * 17 + x * y) % 7) < 3;
      }
    }
    // Finder patterns (3 corners)
    const placeFinder = (ox, oy) => {
      for (let y = 0; y < 7; y++) {
        for (let x = 0; x < 7; x++) {
          const edge = x === 0 || x === 6 || y === 0 || y === 6;
          const inner = x >= 2 && x <= 4 && y >= 2 && y <= 4;
          grid[oy+y][ox+x] = edge || inner;
        }
      }
    };
    // Clear 8px border around finder
    const clearFinderMargin = (ox, oy) => {
      for (let y = -1; y < 8; y++) {
        for (let x = -1; x < 8; x++) {
          const gx = ox + x, gy = oy + y;
          if (gx >= 0 && gx < S && gy >= 0 && gy < S) {
            if (x === -1 || x === 7 || y === -1 || y === 7) grid[gy][gx] = false;
          }
        }
      }
    };
    clearFinderMargin(0, 0); placeFinder(0, 0);
    clearFinderMargin(S-7, 0); placeFinder(S-7, 0);
    clearFinderMargin(0, S-7); placeFinder(0, S-7);
    // Alignment pattern bottom-right
    for (let y = S-9; y < S-4; y++) {
      for (let x = S-9; x < S-4; x++) {
        const edge = (x === S-9 || x === S-5 || y === S-9 || y === S-5);
        const inner = (x === S-7 && y === S-7);
        grid[y][x] = edge || inner;
      }
    }

    for (let y = 0; y < S; y++) {
      for (let x = 0; x < S; x++) {
        if (grid[y][x]) ctx.fillRect(x * cell, y * cell, cell + 0.5, cell + 0.5);
      }
    }
  }
  function strHash(s) {
    let h = 5381;
    for (let i = 0; i < s.length; i++) h = (h * 33) ^ s.charCodeAt(i);
    return Math.abs(h);
  }

  // ── Citation formatters ───────────────────────────────
  function citeChicago(ref) {
    const editor = ref.editor || 'World Mission Media';
    const year = ref.year || new Date().getFullYear();
    const title = ref.title + (ref.section ? ', ' + ref.section : '');
    return editor + '. ' + title + '. ' + (ref.edition || 'Critical edition') + '. The Amos Project, ' + year + '. ' + urlFor(ref) + '.';
  }
  function citeSBL(ref) {
    const editor = ref.editor || 'World Mission Media';
    const year = ref.year || new Date().getFullYear();
    return editor + '. ' + ref.title + (ref.section ? ' ' + ref.section : '') + '. ' + (ref.edition || 'Critical edition') + '. ' + year + '. ' + urlFor(ref) + '.';
  }
  function citeMLA(ref) {
    const editor = ref.editor || 'World Mission Media';
    const year = ref.year || new Date().getFullYear();
    return editor + '. \u201C' + ref.title + (ref.section ? ', ' + ref.section : '') + '.\u201D ' + (ref.edition || 'Critical edition') + ', The Amos Project, ' + year + ', ' + urlFor(ref) + '.';
  }
  function citeAPA(ref) {
    const editor = ref.editor || 'World Mission Media';
    const year = ref.year || new Date().getFullYear();
    return editor + ' (' + year + '). ' + ref.title + (ref.section ? ' (' + ref.section + ')' : '') + '. ' + (ref.edition || 'Critical edition') + '. ' + urlFor(ref);
  }
  function citeBibTeX(ref) {
    const key = (slug(ref.editor || 'wmm') + String(ref.year || 'nd') + slug(ref.title || 'work')).slice(0, 40);
    const lines = [
      '@misc{' + key + ',',
      '  title    = {' + ref.title + (ref.section ? ': ' + ref.section : '') + '},',
      '  author   = {' + (ref.editor || 'World Mission Media') + '},',
      '  year     = {' + (ref.year || new Date().getFullYear()) + '},',
      '  edition  = {' + (ref.edition || 'Critical edition') + '},',
      '  publisher= {The Amos Project},',
      ref.doi ? '  doi      = {' + ref.doi + '},' : null,
      '  url      = {' + urlFor(ref) + '},',
      '  note     = {' + (ref.kind === 'study' ? 'Deep study' : (ref.kind === 'article' ? 'Editorial article' : 'Critical edition')) + '}',
      '}'
    ].filter(Boolean);
    return lines.join('\n');
  }

  // ── Copy-to-clipboard with toast ──────────────────────
  function useCopy() {
    const [copied, setCopied] = React.useState(null);
    const copy = React.useCallback((text, label) => {
      navigator.clipboard.writeText(text).then(
        () => { setCopied(label || 'copied'); setTimeout(() => setCopied(null), 1800); },
        () => { setCopied('error'); setTimeout(() => setCopied(null), 1800); }
      );
    }, []);
    return { copied, copy };
  }

  // ── ShareSheet ────────────────────────────────────────
  function ShareSheet({ open, target, onClose }) {
    const [text, setText] = React.useState('');
    const canvasRef = React.useRef(null);
    const { copied, copy } = useCopy();

    React.useEffect(() => {
      if (open && target) setText(autoShareText(target));
    }, [open, target && target.title, target && target.section, target && target.highlight]);

    React.useEffect(() => {
      if (!open) return;
      const onKey = (e) => { if (e.key === 'Escape') onClose(); };
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, [open, onClose]);

    React.useEffect(() => {
      if (!open || !canvasRef.current || !target) return;
      canvasRef.current.width = 256;
      canvasRef.current.height = 256;
      drawQR(canvasRef.current, urlFor(target));
    }, [open, target && target.url, target && target.section, target && target.highlight]);

    if (!open || !target) return null;

    const url = urlFor(target);
    const enc = encodeURIComponent;
    const encText = enc(text);
    const encUrl = enc(url);

    const nets = [
      { k:'x',        name:'X',        href:'https://x.com/intent/tweet?text=' + encText + '&url=' + encUrl },
      { k:'facebook', name:'Facebook', href:'https://www.facebook.com/sharer/sharer.php?u=' + encUrl + '&quote=' + encText },
      { k:'linkedin', name:'LinkedIn', href:'https://www.linkedin.com/sharing/share-offsite/?url=' + encUrl },
      { k:'whatsapp', name:'WhatsApp', href:'https://wa.me/?text=' + enc(text + '\n' + url) },
      { k:'telegram', name:'Telegram', href:'https://t.me/share/url?url=' + encUrl + '&text=' + encText },
      { k:'email',    name:'Email',    href:'mailto:?subject=' + enc(target.title) + '&body=' + enc(text + '\n\n' + url) },
      { k:'reddit',   name:'Reddit',   href:'https://www.reddit.com/submit?url=' + encUrl + '&title=' + enc(target.title) },
      { k:'bluesky',  name:'Bluesky',  href:'https://bsky.app/intent/compose?text=' + enc(text + '\n' + url) },
      { k:'mastodon', name:'Mastodon', href:'https://mastodon.social/share?text=' + enc(text + '\n' + url) }
    ];

    const downloadQR = () => {
      const c = canvasRef.current; if (!c) return;
      const a = document.createElement('a');
      a.download = slug(target.title) + '-qr.png';
      a.href = c.toDataURL('image/png');
      a.click();
    };

    return React.createElement(React.Fragment, null,
      React.createElement('div', { className:'amos-sc-scrim', onClick:onClose }),
      React.createElement('div', { className:'amos-sc-sheet', role:'dialog', 'aria-label':'Share' },
        React.createElement('div', { className:'amos-sc-head' },
          React.createElement('div', null,
            React.createElement('div', { className:'amos-sc-head-kick' }, 'Share'),
            React.createElement('div', { className:'amos-sc-head-title' },
              target.title + (target.section ? ' · ' + target.section : '')
            ),
            React.createElement('div', { className:'amos-sc-head-sub' },
              target.highlight
                ? 'Sharing a highlighted passage. The recipient will land on this sentence.'
                : (target.subtitle || target.edition || 'Share this page across your network.')
            )
          ),
          React.createElement('button', { className:'amos-sc-close', onClick:onClose, 'aria-label':'Close' },
            NetIcon('x-close', 18)
          )
        ),
        React.createElement('div', { className:'amos-sc-body' },
          React.createElement(OgCard, { target }),

          React.createElement('div', { className:'amos-sc-label' },
            React.createElement('span', null, 'Share text'),
            React.createElement('span', { style:{ font:'11px "Inter",system-ui', color:'rgba(6,42,48,.4)' } }, text.length + ' chars')
          ),
          React.createElement('textarea', {
            className:'amos-sc-text',
            value: text,
            onChange: (e) => setText(e.target.value),
            rows: 3
          }),

          React.createElement('div', { className:'amos-sc-label' }, 'Link'),
          React.createElement('div', { className:'amos-sc-link-row' },
            React.createElement('span', { className:'url' }, url),
            React.createElement('button', {
              className:'copy' + (copied === 'link' ? ' copied' : ''),
              onClick: () => copy(url, 'link')
            },
              copied === 'link' ? NetIcon('check',14) : NetIcon('copy',14),
              copied === 'link' ? 'Copied' : 'Copy link'
            )
          ),

          React.createElement('div', { className:'amos-sc-label' }, 'Post to'),
          React.createElement('div', { className:'amos-sc-networks' },
            nets.map(n => React.createElement('a', {
              key: n.k,
              className: 'amos-sc-net ' + n.k,
              href: n.href, target:'_blank', rel:'noopener noreferrer'
            },
              React.createElement('span', { className:'amos-sc-net-ico' }, NetIcon(n.k, 16)),
              React.createElement('span', { className:'amos-sc-net-name' }, n.name)
            ))
          ),

          React.createElement('div', { className:'amos-sc-label' }, 'QR code · print / in-person'),
          React.createElement('div', { className:'amos-sc-qr-wrap' },
            React.createElement('div', { className:'amos-sc-qr-canvas' },
              React.createElement('canvas', { ref: canvasRef })
            ),
            React.createElement('div', { className:'amos-sc-qr-text' },
              React.createElement('h4', null, 'Scan to open this page'),
              React.createElement('p', null, 'Useful for conference handouts, bibliography slides, or reading groups. The QR encodes the exact URL above — including chapter and highlight.'),
              React.createElement('button', { className:'amos-sc-qr-dl', onClick: downloadQR },
                NetIcon('download', 13), 'Download PNG'
              )
            )
          )
        ),
        React.createElement('div', { className:'amos-sc-foot' },
          React.createElement('span', null, 'CC BY 4.0 · attribution preserved in share text')
        )
      )
    );
  }

  // ── CiteSheet ─────────────────────────────────────────
  function CiteSheet({ open, target, onClose }) {
    const [tab, setTab] = React.useState('chicago');
    const { copied, copy } = useCopy();

    React.useEffect(() => { if (open) setTab('chicago'); }, [open]);
    React.useEffect(() => {
      if (!open) return;
      const onKey = (e) => { if (e.key === 'Escape') onClose(); };
      window.addEventListener('keydown', onKey);
      return () => window.removeEventListener('keydown', onKey);
    }, [open, onClose]);

    if (!open || !target) return null;

    const tabs = [
      { k:'chicago', label:'Chicago', render: citeChicago, cls:'' },
      { k:'sbl',     label:'SBL',     render: citeSBL,     cls:'' },
      { k:'mla',     label:'MLA',     render: citeMLA,     cls:'' },
      { k:'apa',     label:'APA',     render: citeAPA,     cls:'' },
      { k:'bibtex',  label:'BibTeX',  render: citeBibTeX,  cls:'bibtex' }
    ];
    const active = tabs.find(t => t.k === tab) || tabs[0];
    const text = active.render(target);
    const url = urlFor(target);

    const download = () => {
      const blob = new Blob([text], { type: active.k === 'bibtex' ? 'application/x-bibtex' : 'text/plain' });
      const a = document.createElement('a');
      a.download = slug(target.title) + '.' + (active.k === 'bibtex' ? 'bib' : 'txt');
      a.href = URL.createObjectURL(blob);
      a.click();
      setTimeout(() => URL.revokeObjectURL(a.href), 1200);
    };

    return React.createElement(React.Fragment, null,
      React.createElement('div', { className:'amos-sc-scrim', onClick:onClose }),
      React.createElement('div', { className:'amos-sc-sheet', role:'dialog', 'aria-label':'Cite' },
        React.createElement('div', { className:'amos-sc-head' },
          React.createElement('div', null,
            React.createElement('div', { className:'amos-sc-head-kick' }, 'Cite'),
            React.createElement('div', { className:'amos-sc-head-title' },
              target.title + (target.section ? ' · ' + target.section : '')
            ),
            React.createElement('div', { className:'amos-sc-head-sub' },
              target.edition ? (target.edition + (target.editor && target.editor !== 'World Mission Media' ? ' · ed. ' + target.editor : '')) : 'Generate a scholarly citation. Preserves edition, editor, and stable URL.'
            )
          ),
          React.createElement('button', { className:'amos-sc-close', onClick:onClose, 'aria-label':'Close' },
            NetIcon('x-close', 18)
          )
        ),
        React.createElement('div', { className:'amos-sc-body' },
          React.createElement('div', { className:'amos-sc-cite-tabs' },
            tabs.map(t => React.createElement('button', {
              key: t.k,
              className: 'amos-sc-cite-tab' + (tab === t.k ? ' active' : ''),
              onClick: () => setTab(t.k)
            }, t.label))
          ),
          React.createElement('div', { className: 'amos-sc-cite-body ' + active.cls }, text),
          React.createElement('div', { className:'amos-sc-cite-actions' },
            React.createElement('button', { className:'amos-sc-cite-btn', onClick: download },
              NetIcon('download', 13), active.k === 'bibtex' ? 'Download .bib' : 'Download .txt'
            ),
            React.createElement('button', {
              className:'amos-sc-cite-btn primary' + (copied === 'cite' ? ' copied' : ''),
              onClick: () => copy(text, 'cite')
            },
              copied === 'cite' ? NetIcon('check', 13) : NetIcon('copy', 13),
              copied === 'cite' ? 'Copied' : 'Copy citation'
            )
          ),
          React.createElement('div', { className:'amos-sc-cite-perma' },
            React.createElement('div', { className:'row' },
              React.createElement('span', null, 'Permalink'),
              React.createElement('code', null, url),
              React.createElement('button', {
                className:'amos-sc-cite-btn' + (copied === 'url' ? ' copied' : ''),
                onClick: () => copy(url, 'url'),
                style:{ padding:'6px 10px' }
              }, copied === 'url' ? 'Copied' : 'Copy')
            ),
            React.createElement('div', { className:'amos-sc-cite-doi' },
              target.doi
                ? React.createElement(React.Fragment, null, 'DOI ', React.createElement('b', null, target.doi), ' — resolvable via doi.org')
                : React.createElement(React.Fragment, null, 'DOI pending · citation will be updated when registered with CrossRef')
            )
          )
        ),
        React.createElement('div', { className:'amos-sc-foot' },
          React.createElement('span', null,
            'Five styles · BibTeX · Zotero / EndNote via ', React.createElement('code', null, '.bib')
          ),
          React.createElement('code', null, 'CC BY 4.0')
        )
      )
    );
  }

  // ── Topbar pill buttons ───────────────────────────────
  function CiteButton({ refFor, compact, label }) {
    const { openCite } = useCiteShare();
    return React.createElement('button', {
      className:'amos-sc-btn cite',
      onClick: () => openCite(typeof refFor === 'function' ? refFor() : refFor),
      title:'Cite this page'
    },
      NetIcon('cite', 14),
      !compact && React.createElement('span', null, label || 'Cite')
    );
  }
  function ShareButton({ refFor, compact, label }) {
    const { openShare } = useCiteShare();
    return React.createElement('button', {
      className:'amos-sc-btn share',
      onClick: () => openShare(typeof refFor === 'function' ? refFor() : refFor),
      title:'Share this page'
    },
      NetIcon('share', 14),
      !compact && React.createElement('span', null, label || 'Share')
    );
  }

  // Icon-only Share button for doc cards
  function ShareIconButton({ refFor }) {
    const { openShare } = useCiteShare();
    return React.createElement('button', {
      className:'amos-sc-card-icon',
      onClick: (e) => { e.stopPropagation(); openShare(typeof refFor === 'function' ? refFor() : refFor); },
      title:'Share',
      'aria-label':'Share'
    }, NetIcon('share', 13));
  }

  // ── Highlight-to-share floating pill ──────────────────
  // Attaches a selectionchange listener to a container element (ref via selector).
  // When there's a non-trivial selection inside that container, shows a pill.
  function HighlightSharePill({ container, shareRefBuilder }) {
    // container: CSS selector string; shareRefBuilder: (selectedText, chN?) => refPartial
    const { openShare, openCite } = useCiteShare();
    const [pill, setPill] = React.useState(null); // { x, y, text, chapter }

    React.useEffect(() => {
      const handler = () => {
        const sel = window.getSelection();
        if (!sel || sel.isCollapsed || !sel.rangeCount) { setPill(null); return; }
        const text = sel.toString().trim();
        if (text.length < 12) { setPill(null); return; }
        const range = sel.getRangeAt(0);
        const startNode = range.startContainer;
        const host = document.querySelector(container);
        if (!host) { setPill(null); return; }
        if (!host.contains(startNode.nodeType === 3 ? startNode.parentNode : startNode)) { setPill(null); return; }
        const rect = range.getBoundingClientRect();
        if (!rect.width && !rect.height) { setPill(null); return; }

        // Infer chapter from nearest [data-ch] ancestor
        let el = startNode.nodeType === 3 ? startNode.parentNode : startNode;
        let chapter = null;
        while (el && el !== host) {
          if (el.dataset && el.dataset.ch) { chapter = el.dataset.ch; break; }
          el = el.parentNode;
        }

        setPill({
          x: rect.left + rect.width / 2,
          y: rect.top,
          text, chapter
        });
      };
      document.addEventListener('selectionchange', handler);
      // Also hide on scroll (selection rects move; simplest: reposition)
      window.addEventListener('scroll', handler, true);
      return () => {
        document.removeEventListener('selectionchange', handler);
        window.removeEventListener('scroll', handler, true);
      };
    }, [container]);

    if (!pill) return null;

    const doShare = () => {
      const partial = shareRefBuilder(pill.text, pill.chapter);
      openShare(Object.assign({}, partial, { highlight: pill.text }));
      window.getSelection().removeAllRanges();
      setPill(null);
    };
    const doCite = () => {
      const partial = shareRefBuilder(pill.text, pill.chapter);
      openCite(Object.assign({}, partial, { highlight: pill.text }));
      window.getSelection().removeAllRanges();
      setPill(null);
    };
    const doCopy = () => {
      navigator.clipboard.writeText(pill.text).then(() => {
        window.getSelection().removeAllRanges();
        setPill(null);
      });
    };

    return React.createElement('div', {
      className:'amos-sc-highlight-pill',
      style:{ left: pill.x + 'px', top: pill.y + 'px' }
    },
      React.createElement('button', { className:'amos-sc-hpill-btn', onClick: doShare },
        NetIcon('share', 12), 'Share'
      ),
      React.createElement('span', { className:'amos-sc-hpill-sep' }),
      React.createElement('button', { className:'amos-sc-hpill-btn', onClick: doCite },
        NetIcon('cite', 12), 'Cite'
      ),
      React.createElement('span', { className:'amos-sc-hpill-sep' }),
      React.createElement('button', { className:'amos-sc-hpill-btn', onClick: doCopy },
        NetIcon('copy', 12), 'Copy'
      )
    );
  }

  // ── Provider + hook ───────────────────────────────────
  const CiteShareCtx = React.createContext(null);
  function useCiteShare() {
    const c = React.useContext(CiteShareCtx);
    if (!c) throw new Error('useCiteShare must be inside <CiteShareProvider>');
    return c;
  }
  function CiteShareProvider({ children }) {
    const [shareRef, setShareRef] = React.useState(null);
    const [citeRef,  setCiteRef]  = React.useState(null);
    const openShare = React.useCallback((r) => setShareRef(buildShareRef(r)), []);
    const openCite  = React.useCallback((r) => setCiteRef(buildShareRef(r)),  []);
    const closeAll  = React.useCallback(() => { setShareRef(null); setCiteRef(null); }, []);
    const value = { openShare, openCite, closeAll, sharing: !!shareRef, citing: !!citeRef };
    return React.createElement(CiteShareCtx.Provider, { value },
      children,
      React.createElement(ShareSheet, { open: !!shareRef, target: shareRef, onClose: () => setShareRef(null) }),
      React.createElement(CiteSheet,  { open: !!citeRef,  target: citeRef,  onClose: () => setCiteRef(null) })
    );
  }

  Object.assign(window, {
    buildShareRef,
    ShareSheet, CiteSheet,
    ShareButton, CiteButton, ShareIconButton,
    HighlightSharePill,
    CiteShareProvider, useCiteShare
  });
})();
