// Article / publication card used on list views
const ArticleCard = ({ kind, title, titleItalic, date, length, onClick, onInk = false }) => (
  <article
    onClick={onClick}
    style={{
      background: onInk ? 'var(--ink-700)' : 'var(--paper)',
      padding: '28px 28px 24px',
      cursor: onClick ? 'pointer' : 'default',
      display: 'flex', flexDirection: 'column', gap: 16,
      minHeight: 240, justifyContent: 'space-between',
      transition: 'outline-color 140ms cubic-bezier(0.2,0.7,0.2,1)',
      outline: '1px solid transparent',
      outlineOffset: -1,
    }}
    onMouseEnter={e => e.currentTarget.style.outlineColor = 'var(--accent)'}
    onMouseLeave={e => e.currentTarget.style.outlineColor = 'transparent'}
  >
    <div style={{
      fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
      textTransform: 'uppercase', color: onInk ? 'var(--accent-soft)' : 'var(--ink-soft)',
    }}>{kind}</div>
    <div style={{
      fontFamily: 'var(--serif)', fontSize: 26, lineHeight: 1.15,
      letterSpacing: '-0.01em', fontWeight: 400,
      color: onInk ? 'var(--paper)' : 'var(--ink)',
    }}>
      {title}{titleItalic && <> <em style={{ fontStyle: 'italic', color: onInk ? 'var(--accent-soft)' : 'var(--ink-soft)' }}>{titleItalic}</em></>}
    </div>
    <div style={{
      fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.08em',
      textTransform: 'uppercase', color: onInk ? 'var(--paper-200)' : 'var(--ink-soft)',
      display: 'flex', justifyContent: 'space-between',
      paddingTop: 12, borderTop: `1px solid ${onInk ? 'rgba(245,241,234,.15)' : 'var(--rule)'}`,
    }}>
      <span>{date}</span>
      <span>{length}</span>
    </div>
  </article>
);

// Larger hero/feature card with image
const FeatureCard = ({ kind, title, titleItalic, description, imgLabel, onClick, aspect = '4/3' }) => (
  <article onClick={onClick}
    style={{
      cursor: onClick ? 'pointer' : 'default',
      display: 'flex', flexDirection: 'column', gap: 20,
      background: 'var(--paper)',
      transition: 'outline-color 140ms cubic-bezier(0.2,0.7,0.2,1)',
      outline: '1px solid transparent', outlineOffset: -1,
    }}
    onMouseEnter={e => e.currentTarget.style.outlineColor = 'var(--accent)'}
    onMouseLeave={e => e.currentTarget.style.outlineColor = 'transparent'}
  >
    <ImgSlot label={imgLabel} aspect={aspect} />
    <div style={{ padding: '0 4px 20px' }}>
      <div style={{
        fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
        textTransform: 'uppercase', color: 'var(--ink-soft)', marginBottom: 10,
      }}>{kind}</div>
      <div style={{
        fontFamily: 'var(--serif)', fontSize: 26, lineHeight: 1.15,
        letterSpacing: '-0.01em', fontWeight: 400, color: 'var(--ink)',
      }}>
        {title}{titleItalic && <> <em style={{ fontStyle: 'italic', color: 'var(--ink-soft)' }}>{titleItalic}</em></>}
      </div>
      {description && <p style={{ marginTop: 12, fontSize: 14, color: 'var(--ink-700)', lineHeight: 1.55 }}>{description}</p>}
    </div>
  </article>
);

// Person card — used on About/Team
const PersonCard = ({ name, title, bio, imgLabel = 'Portrait · natural light' }) => (
  <div>
    <ImgSlot label={imgLabel} aspect="4/5" />
    <div style={{ marginTop: 16, fontFamily: 'var(--serif)', fontSize: 22, fontWeight: 400, letterSpacing: '-0.005em' }}>{name}</div>
    <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--ink-soft)', marginTop: 6 }}>{title}</div>
    {bio && <p style={{ marginTop: 12, fontSize: 13, lineHeight: 1.55, color: 'var(--ink-700)' }}>{bio}</p>}
  </div>
);

// Stat block — large number with caption
const Stat = ({ value, label, sub, onInk }) => (
  <div>
    <div style={{
      fontFamily: 'var(--serif)', fontWeight: 300,
      fontSize: 72, lineHeight: 1, letterSpacing: '-0.03em',
      color: onInk ? 'var(--paper)' : 'var(--ink)',
    }}>
      {value}
    </div>
    <div style={{
      marginTop: 14, paddingTop: 14,
      borderTop: `1px solid ${onInk ? 'rgba(245,241,234,0.15)' : 'var(--rule)'}`,
      fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
      textTransform: 'uppercase', color: onInk ? 'var(--accent-soft)' : 'var(--ink-soft)',
    }}>
      {label}
    </div>
    {sub && <div style={{ marginTop: 8, fontSize: 13, lineHeight: 1.55, color: onInk ? 'var(--paper-200)' : 'var(--ink-700)' }}>{sub}</div>}
  </div>
);

// Grid that creates the "cells share a 1px rule" look
const RuleGrid = ({ cols = 3, children, onInk, style }) => (
  <div style={{
    display: 'grid', gridTemplateColumns: `repeat(${cols},1fr)`,
    gap: 1, background: onInk ? 'var(--rule-inverse)' : 'var(--rule)',
    border: `1px solid ${onInk ? 'var(--rule-inverse)' : 'var(--rule)'}`,
    ...style,
  }}>
    {children}
  </div>
);

// Nexus diagram — full version with labels
const NexusDiagram = ({ size = 460, onInk = false }) => {
  const stroke = onInk ? '#f5f1ea' : '#12203a';
  const labelFill = onInk ? '#e0b280' : '#4a5877';
  const nodeFill = onInk ? '#f5f1ea' : '#12203a';
  return (
    <svg width={size} height={size} viewBox="-180 -40 960 700">
      <g fill="none" stroke={stroke} strokeWidth="1.6">
        <line x1="300" y1="60" x2="60" y2="300"/>
        <line x1="300" y1="60" x2="540" y2="300"/>
        <line x1="60" y1="300" x2="540" y2="300"/>
        <line x1="60" y1="300" x2="300" y2="540"/>
        <line x1="540" y1="300" x2="300" y2="540"/>
        <line x1="300" y1="60" x2="300" y2="540"/>
      </g>
      <g fill={nodeFill}>
        <circle cx="300" cy="60" r="12"/>
        <circle cx="60" cy="300" r="12"/>
        <circle cx="540" cy="300" r="12"/>
        <circle cx="300" cy="540" r="12"/>
      </g>
      <circle cx="300" cy="300" r="22" fill="#b3703a"/>
      <text x="300" y="32" textAnchor="middle" fontFamily="IBM Plex Mono" fontSize="15" letterSpacing="2" fill={labelFill} style={{ textTransform: 'uppercase' }}>Researchers</text>
      <text x="40" y="305" textAnchor="end" fontFamily="IBM Plex Mono" fontSize="15" letterSpacing="2" fill={labelFill} style={{ textTransform: 'uppercase' }}>Builders</text>
      <text x="560" y="305" textAnchor="start" fontFamily="IBM Plex Mono" fontSize="15" letterSpacing="2" fill={labelFill} style={{ textTransform: 'uppercase' }}>Governments</text>
      <text x="300" y="580" textAnchor="middle" fontFamily="IBM Plex Mono" fontSize="15" letterSpacing="2" fill={labelFill} style={{ textTransform: 'uppercase' }}>Civil society</text>
      <text x="300" y="282" textAnchor="middle" fontFamily="Newsreader" fontStyle="italic" fontSize="20" fill="#f5f1ea">responsible</text>
      <text x="300" y="340" textAnchor="middle" fontFamily="IBM Plex Mono" fontSize="10" letterSpacing="2" fill="#f5f1ea" style={{ textTransform: 'uppercase' }}>the public</text>
    </svg>
  );
};

// Quote / pull-quote (house voice)
const PullQuote = ({ children, attribution, onInk }) => (
  <div style={{
    padding: '32px 0 32px 28px',
    borderLeft: '2px solid var(--accent)',
    fontFamily: 'var(--serif)', fontSize: 28, fontStyle: 'italic',
    fontWeight: 300, lineHeight: 1.35, color: onInk ? 'var(--paper)' : 'var(--ink)',
    maxWidth: 780,
  }}>
    "{children}"
    {attribution && <div style={{
      marginTop: 18, fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em',
      textTransform: 'uppercase', fontStyle: 'normal',
      color: onInk ? 'var(--accent-soft)' : 'var(--ink-soft)',
    }}>— {attribution}</div>}
  </div>
);

// Simple event / timeline row
const EventRow = ({ date, kind, title, location, status, onClick }) => (
  <div onClick={onClick} style={{
    display: 'grid', gridTemplateColumns: '140px 140px 1fr 180px 100px',
    gap: 24, alignItems: 'baseline',
    padding: '28px 0', borderTop: '1px solid var(--rule)',
    cursor: onClick ? 'pointer' : 'default',
    transition: 'background 120ms',
  }}
    onMouseEnter={e => e.currentTarget.style.background = 'var(--paper-200)'}
    onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
  >
    <div style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--ink)' }}>{date}</div>
    <div style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.14em', textTransform: 'uppercase', color: 'var(--accent)' }}>{kind}</div>
    <div style={{ fontFamily: 'var(--serif)', fontSize: 22, lineHeight: 1.25, letterSpacing: '-0.005em' }}>{title}</div>
    <div style={{ fontFamily: 'var(--sans)', fontSize: 13, color: 'var(--ink-soft)' }}>{location}</div>
    <div>
      {status && <Tag tone={status === 'Open' ? 'ember' : status === 'Past' ? 'ink' : 'sage'}>{status}</Tag>}
    </div>
  </div>
);

// Partner logo plate (placeholder — uses mono caps)
const PartnerPlate = ({ name, type }) => (
  <div style={{
    background: 'var(--paper)', padding: '36px 20px',
    display: 'flex', flexDirection: 'column',
    alignItems: 'center', justifyContent: 'center', minHeight: 140, gap: 8,
  }}>
    <div style={{
      fontFamily: 'var(--serif)', fontSize: 19, fontWeight: 400,
      textAlign: 'center', lineHeight: 1.2, color: 'var(--ink)',
    }}>{name}</div>
    {type && <div style={{
      fontFamily: 'var(--mono)', fontSize: 9, letterSpacing: '0.14em',
      textTransform: 'uppercase', color: 'var(--ink-soft)',
    }}>{type}</div>}
  </div>
);

// Accordion (used in FAQ)
const Accordion = ({ items }) => {
  const [open, setOpen] = React.useState(0);
  return (
    <div>
      {items.map((it, i) => (
        <div key={i} style={{ borderTop: '1px solid var(--rule)', ...(i === items.length - 1 ? { borderBottom: '1px solid var(--rule)' } : {}) }}>
          <button onClick={() => setOpen(open === i ? -1 : i)} style={{
            width: '100%', display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
            padding: '24px 0', background: 'none', border: 0, cursor: 'pointer',
            fontFamily: 'var(--serif)', fontSize: 22, lineHeight: 1.3, letterSpacing: '-0.005em',
            textAlign: 'left', color: 'var(--ink)',
          }}>
            <span>{it.q}</span>
            <span style={{
              fontFamily: 'var(--mono)', fontSize: 14, color: 'var(--accent)',
              transition: 'transform 200ms', transform: open === i ? 'rotate(45deg)' : 'rotate(0)',
            }}>+</span>
          </button>
          {open === i && (
            <div style={{
              paddingBottom: 28, fontFamily: 'var(--sans)', fontSize: 15,
              lineHeight: 1.65, color: 'var(--ink-700)', maxWidth: 720,
            }}>
              {it.a}
            </div>
          )}
        </div>
      ))}
    </div>
  );
};

Object.assign(window, {
  ArticleCard, FeatureCard, PersonCard, Stat, RuleGrid,
  NexusDiagram, PullQuote, EventRow, PartnerPlate, Accordion,
});
