// gvd-shell.jsx — shared design system + page chrome.
//
// Tokens, header (announcement strip + centered nav with active state),
// footer, and a handful of small primitives used across every page in the
// GVD site. Anything page-specific (hero copy, body sections) lives in
// each page's own jsx file. Anything reused twice or more lives here.
//
// Globals exported (window.):
//   GVD                — design tokens (color/font/etc)
//   GVDHeader          — announcement strip + centered nav. Pass `active`
//                        with the nav label of the current page.
//   GVDFooter          — full footer (visit / contact / quick links)
//   GVDPageHero        — small hero: title + italic tagline + photo
//   Eyebrow            — small-caps kicker
//   SectionTitle       — centered eyebrow + serif h2
//   AccentRule         — 36x2 brick rule
//   PrimaryButton      — primary serif button
//   GhostButton        — outlined button
//   PrimaryLink        — text link with bottom rule + → arrow
//   TextField, Select,
//   Checkbox, Radio,
//   FormLabel,
//   FormHelp           — form chrome (used on Join and Volunteer pages)

const GVD = {
  bg: '#f5efe4',
  paper: '#fbf7ee',
  paperAlt: '#efe8d9',
  ink: '#0e2a47',
  ink2: '#3a4a5e',
  ink3: '#7a8493',
  rule: '#d9d1bf',
  accent: '#a93636', // brick — use sparingly
  font: {
    serif: '"Source Serif 4", Georgia, serif',
    sans: '"Public Sans", system-ui, sans-serif',
    mono: '"IBM Plex Mono", ui-monospace, monospace',
  },
};

const GVD_NAV = [
  { label: 'GV Dems', href: 'index.html' },
  { label: 'Election', href: 'vote.html' },
  { label: 'Membership', href: 'join.html' },
  { label: 'Volunteer', href: 'volunteer.html' },
  { label: 'Resources', href: 'resources.html' },
  { label: "Gov't Contacts", href: 'contacts.html' },
];

function GVDHeader({ active = 'GV Dems', announcement }) {
  return (
    <header style={{ background: GVD.paper, borderBottom: `1px solid ${GVD.rule}` }}>
      <div style={{ background: GVD.ink, color: GVD.paper, fontFamily: GVD.font.sans, fontSize: 12, letterSpacing: 0.6, textTransform: 'uppercase' }}>
        <div style={{ maxWidth: 1120, margin: '0 auto', padding: '9px 32px', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <span>{announcement || 'Monthly Programs · 2nd & 4th Saturdays · 3 p.m.'}</span>
          <span style={{ opacity: 0.75 }}>Pima County, Arizona</span>
        </div>
      </div>
      <nav style={{ borderBottom: `1px solid ${GVD.rule}` }}>
        <div style={{ maxWidth: 1120, margin: '0 auto', padding: '0 32px', display: 'flex', justifyContent: 'center', gap: 36 }}>
          {GVD_NAV.map(({ label, href }) => (
            <a key={label} href={href} style={{
              fontFamily: GVD.font.sans, fontSize: 13.5, fontWeight: 500, color: GVD.ink, textDecoration: 'none',
              padding: '14px 4px', letterSpacing: 0.3,
              borderBottom: label === active ? `2px solid ${GVD.accent}` : '2px solid transparent',
            }}>{label}</a>
          ))}
        </div>
      </nav>
    </header>
  );
}

function GVDPageHero({ title, tagline, photoLabel, photoTone = 'desert', photoHeight = 360, imageSrc, imageAlt, overlayText = false, overlayOffsetTop = 90 }) {
  const photo = imageSrc
    ? <img src={imageSrc} alt={imageAlt || ''} style={{ width: '100%', height: photoHeight, objectFit: 'cover', display: 'block' }} />
    : photoLabel ? <Photo label={photoLabel} tone={photoTone} height={photoHeight} /> : null;

  if (overlayText && photo) {
    return (
      <section style={{ background: GVD.paper }}>
        <div style={{ maxWidth: 1120, margin: '0 auto', padding: '56px 32px 40px' }}>
          <div style={{ position: 'relative' }}>
            {photo}
            <div style={{ position: 'absolute', inset: 0, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-start', paddingTop: overlayOffsetTop, textAlign: 'center', padding: `${overlayOffsetTop}px 80px 0` }}>
              <h1 style={{ fontFamily: GVD.font.serif, fontSize: 56, fontWeight: 700, color: '#fff', lineHeight: 1.05, margin: 0, letterSpacing: -1, textShadow: '0 2px 12px rgba(0,0,0,0.5), 0 1px 3px rgba(0,0,0,0.4)' }}>
                {title}
              </h1>
              {tagline && (
                <p style={{ fontFamily: GVD.font.serif, fontStyle: 'italic', fontSize: 24, color: 'rgba(255,255,255,0.92)', lineHeight: 1.4, margin: '14px 0 0', fontWeight: 400, textShadow: '0 1px 8px rgba(0,0,0,0.5), 0 1px 2px rgba(0,0,0,0.3)' }}>
                  {tagline}
                </p>
              )}
            </div>
          </div>
        </div>
      </section>
    );
  }

  return (
    <section style={{ background: GVD.paper }}>
      <div style={{ maxWidth: 1120, margin: '0 auto', padding: '56px 32px 40px' }}>
        <div style={{ textAlign: 'center', padding: '0 80px 36px' }}>
          <h1 style={{ fontFamily: GVD.font.serif, fontSize: 56, fontWeight: 700, color: GVD.ink, lineHeight: 1.05, margin: 0, letterSpacing: -1 }}>
            {title}
          </h1>
          {tagline && (
            <p style={{ fontFamily: GVD.font.serif, fontStyle: 'italic', fontSize: 22, color: GVD.ink2, lineHeight: 1.4, margin: '14px 0 0', fontWeight: 400 }}>
              {tagline}
            </p>
          )}
        </div>
        {photo}
      </div>
    </section>
  );
}

function Eyebrow({ children, accent = false, style = {} }) {
  return (
    <div style={{
      fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 3, textTransform: 'uppercase',
      color: accent ? GVD.accent : GVD.ink2, marginBottom: 12,
      ...style,
    }}>
      {accent ? <span style={{ borderBottom: `1px solid ${GVD.accent}`, paddingBottom: 4 }}>{children}</span> : children}
    </div>
  );
}

function SectionTitle({ eyebrow, children, align = 'center', size = 40 }) {
  return (
    <div style={{ textAlign: align, marginBottom: 36 }}>
      {eyebrow && <Eyebrow style={{ marginBottom: 12 }}>{eyebrow}</Eyebrow>}
      <h2 style={{ fontFamily: GVD.font.serif, fontSize: size, fontWeight: 700, color: GVD.ink, margin: 0, letterSpacing: -0.6, lineHeight: 1.1 }}>
        {children}
      </h2>
    </div>
  );
}

function AccentRule({ width = 36, style = {} }) {
  return <div style={{ width, height: 2, background: GVD.accent, ...style }} />;
}

function PrimaryButton({ children, style = {}, ...rest }) {
  return (
    <button style={{
      fontFamily: GVD.font.sans, fontSize: 14, fontWeight: 600, letterSpacing: 0.3,
      color: GVD.paper, background: GVD.ink, border: 'none', padding: '14px 22px',
      cursor: 'pointer', borderRadius: 0,
      ...style,
    }} {...rest}>{children}</button>
  );
}

function GhostButton({ children, style = {}, ...rest }) {
  return (
    <button style={{
      fontFamily: GVD.font.sans, fontSize: 14, fontWeight: 600, letterSpacing: 0.3,
      color: GVD.ink, background: 'transparent', border: `1.5px solid ${GVD.ink}`, padding: '12.5px 20px',
      cursor: 'pointer', borderRadius: 0,
      ...style,
    }} {...rest}>{children}</button>
  );
}

function PrimaryLink({ children, href = '#', style = {} }) {
  return (
    <a href={href} style={{
      fontFamily: GVD.font.sans, fontSize: 13, fontWeight: 600, color: GVD.ink, textDecoration: 'none',
      letterSpacing: 0.3, borderBottom: `1.5px solid ${GVD.ink}`, paddingBottom: 2, display: 'inline-block',
      ...style,
    }}>{children} →</a>
  );
}

function FormLabel({ children, required = false, htmlFor }) {
  return (
    <label htmlFor={htmlFor} style={{
      display: 'block', fontFamily: GVD.font.sans, fontSize: 12, letterSpacing: 1.4,
      textTransform: 'uppercase', color: GVD.ink2, fontWeight: 600, marginBottom: 8,
    }}>
      {children}
      {required && <span style={{ color: GVD.accent, marginLeft: 4 }}>*</span>}
    </label>
  );
}

function FormHelp({ children }) {
  return <div style={{ fontFamily: GVD.font.sans, fontSize: 12, color: GVD.ink3, marginTop: 6, lineHeight: 1.5 }}>{children}</div>;
}

const fieldBase = {
  width: '100%', boxSizing: 'border-box',
  fontFamily: GVD.font.serif, fontSize: 16, color: GVD.ink,
  padding: '12px 14px', background: GVD.paper,
  border: `1px solid ${GVD.rule}`, borderRadius: 0, outline: 'none',
};

function TextField({ style = {}, ...rest }) {
  return <input style={{ ...fieldBase, ...style }} {...rest} />;
}

function Select({ children, style = {}, ...rest }) {
  return (
    <select style={{ ...fieldBase, appearance: 'none', backgroundImage: 'linear-gradient(45deg, transparent 50%, ' + GVD.ink + ' 50%), linear-gradient(135deg, ' + GVD.ink + ' 50%, transparent 50%)', backgroundPosition: 'calc(100% - 16px) 50%, calc(100% - 11px) 50%', backgroundSize: '5px 5px, 5px 5px', backgroundRepeat: 'no-repeat', paddingRight: 36, ...style }} {...rest}>{children}</select>
  );
}

function Checkbox({ label, sub, name, value, defaultChecked }) {
  return (
    <label style={{ display: 'grid', gridTemplateColumns: '20px 1fr', gap: 12, alignItems: 'start', padding: '10px 0', cursor: 'pointer' }}>
      <input type="checkbox" name={name} value={value} defaultChecked={defaultChecked} style={{ width: 18, height: 18, marginTop: 2, accentColor: GVD.accent }} />
      <div>
        <div style={{ fontFamily: GVD.font.sans, fontSize: 14.5, color: GVD.ink, fontWeight: 500 }}>{label}</div>
        {sub && <div style={{ fontFamily: GVD.font.sans, fontSize: 13, color: GVD.ink3, marginTop: 2, lineHeight: 1.4 }}>{sub}</div>}
      </div>
    </label>
  );
}

function Radio({ label, sub, name, value, defaultChecked }) {
  return (
    <label style={{ display: 'grid', gridTemplateColumns: '20px 1fr', gap: 12, alignItems: 'start', padding: '10px 0', cursor: 'pointer' }}>
      <input type="radio" name={name} value={value} defaultChecked={defaultChecked} style={{ width: 18, height: 18, marginTop: 2, accentColor: GVD.accent }} />
      <div>
        <div style={{ fontFamily: GVD.font.sans, fontSize: 14.5, color: GVD.ink, fontWeight: 500 }}>{label}</div>
        {sub && <div style={{ fontFamily: GVD.font.sans, fontSize: 13, color: GVD.ink3, marginTop: 2, lineHeight: 1.4 }}>{sub}</div>}
      </div>
    </label>
  );
}

function Callout({ variant = 'info', kicker, title, children, action }) {
  const stripe = variant === 'urgent' ? GVD.accent : variant === 'success' ? '#3a6b46' : GVD.ink;
  return (
    <div style={{ background: GVD.paper, border: `1px solid ${GVD.rule}`, borderLeft: `4px solid ${stripe}`, padding: '18px 22px', display: 'grid', gridTemplateColumns: action ? '1fr auto' : '1fr', gap: 24, alignItems: 'center' }}>
      <div>
        {kicker && <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: stripe, fontWeight: 700, marginBottom: 6 }}>{kicker}</div>}
        {title && <div style={{ fontFamily: GVD.font.serif, fontSize: 19, fontWeight: 600, color: GVD.ink, marginBottom: children ? 4 : 0, lineHeight: 1.3 }}>{title}</div>}
        {children && <div style={{ fontFamily: GVD.font.sans, fontSize: 14, color: GVD.ink2, lineHeight: 1.55 }}>{children}</div>}
      </div>
      {action}
    </div>
  );
}

function Stat({ value, label, sub, accent = false, dark = false }) {
  const fg = dark ? GVD.paper : GVD.ink;
  const muted = dark ? 'rgba(255,255,255,0.7)' : GVD.ink3;
  const num = accent ? GVD.accent : fg;
  return (
    <div style={{ borderTop: `2px solid ${accent ? GVD.accent : fg}`, paddingTop: 12 }}>
      <div style={{ fontFamily: GVD.font.serif, fontSize: 48, fontWeight: 700, color: num, lineHeight: 1, letterSpacing: -1, marginBottom: 8 }}>{value}</div>
      <div style={{ fontFamily: GVD.font.sans, fontSize: 13, color: dark ? muted : GVD.ink2, fontWeight: 500, lineHeight: 1.4 }}>{label}</div>
      {sub && <div style={{ fontFamily: GVD.font.sans, fontSize: 12, color: muted, marginTop: 4 }}>{sub}</div>}
    </div>
  );
}

function PullQuote({ children, attribution, dark = false }) {
  const fg = dark ? GVD.paper : GVD.ink;
  const muted = dark ? 'rgba(255,255,255,0.7)' : GVD.ink2;
  return (
    <figure style={{ margin: 0, textAlign: 'center', padding: '8px 0' }}>
      <div style={{ fontFamily: GVD.font.serif, fontSize: 56, color: GVD.accent, lineHeight: 0.6, marginBottom: 12 }}>“</div>
      <blockquote style={{ fontFamily: GVD.font.serif, fontSize: 28, lineHeight: 1.35, color: fg, fontWeight: 400, margin: '0 0 18px', letterSpacing: -0.3 }}>{children}</blockquote>
      {attribution && <figcaption style={{ fontFamily: GVD.font.sans, fontSize: 12, letterSpacing: 1.6, textTransform: 'uppercase', color: muted, fontWeight: 600 }}>{attribution}</figcaption>}
    </figure>
  );
}

function EventCard({ month, day, title, when, where, body, rsvp = true }) {
  return (
    <article style={{ display: 'grid', gridTemplateColumns: '88px 1fr', gap: 22, padding: '20px 0', borderTop: `1px solid ${GVD.rule}` }}>
      <div style={{ textAlign: 'center', borderRight: `1px solid ${GVD.rule}`, paddingRight: 22 }}>
        <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: GVD.accent, fontWeight: 700, marginBottom: 4 }}>{month}</div>
        <div style={{ fontFamily: GVD.font.serif, fontSize: 44, fontWeight: 700, color: GVD.ink, lineHeight: 1, letterSpacing: -1 }}>{day}</div>
      </div>
      <div>
        <h3 style={{ fontFamily: GVD.font.serif, fontSize: 22, fontWeight: 600, color: GVD.ink, margin: '0 0 6px', letterSpacing: -0.2, lineHeight: 1.25 }}>{title}</h3>
        <div style={{ fontFamily: GVD.font.sans, fontSize: 13, color: GVD.ink2, marginBottom: 8 }}>{when} · {where}</div>
        {body && <p style={{ fontFamily: GVD.font.sans, fontSize: 14, color: GVD.ink2, lineHeight: 1.55, margin: '0 0 10px' }}>{body}</p>}
        {rsvp && <PrimaryLink>RSVP</PrimaryLink>}
      </div>
    </article>
  );
}

function ArticleCard({ kicker, title, dek, meta, photoLabel, photoTone = 'cool' }) {
  return (
    <article>
      {photoLabel && <div style={{ marginBottom: 16 }}><Photo label={photoLabel} tone={photoTone} height={200} /></div>}
      {kicker && <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: GVD.accent, fontWeight: 700, marginBottom: 8 }}>{kicker}</div>}
      <h3 style={{ fontFamily: GVD.font.serif, fontSize: 22, fontWeight: 600, color: GVD.ink, margin: '0 0 8px', letterSpacing: -0.2, lineHeight: 1.25 }}>{title}</h3>
      {dek && <p style={{ fontFamily: GVD.font.sans, fontSize: 14, color: GVD.ink2, lineHeight: 1.6, margin: '0 0 10px' }}>{dek}</p>}
      {meta && <div style={{ fontFamily: GVD.font.sans, fontSize: 12, color: GVD.ink3, letterSpacing: 0.4 }}>{meta}</div>}
    </article>
  );
}

function Tag({ children, variant = 'default' }) {
  const styles = {
    default: { bg: 'transparent', fg: GVD.ink2, border: GVD.rule },
    accent: { bg: GVD.accent, fg: GVD.paper, border: GVD.accent },
    solid: { bg: GVD.ink, fg: GVD.paper, border: GVD.ink },
  }[variant] || {};
  return (
    <span style={{
      display: 'inline-block', fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 1.4, textTransform: 'uppercase', fontWeight: 600,
      padding: '4px 10px', border: `1px solid ${styles.border}`, background: styles.bg, color: styles.fg,
    }}>{children}</span>
  );
}

function Breadcrumbs({ items = [] }) {
  return (
    <nav style={{ fontFamily: GVD.font.sans, fontSize: 12, letterSpacing: 0.4, color: GVD.ink3 }}>
      {items.map((it, i) => (
        <span key={i}>
          {i > 0 && <span style={{ margin: '0 8px', color: GVD.rule }}>/</span>}
          {it.href
            ? <a href={it.href} style={{ color: GVD.ink2, textDecoration: 'none', borderBottom: `1px solid ${GVD.rule}` }}>{it.label}</a>
            : <span style={{ color: GVD.ink, fontWeight: 600 }}>{it.label}</span>}
        </span>
      ))}
    </nav>
  );
}

function DefinitionList({ items = [] }) {
  return (
    <dl style={{ margin: 0 }}>
      {items.map(([term, def], i) => (
        <div key={i} style={{ display: 'grid', gridTemplateColumns: '160px 1fr', gap: 24, padding: '14px 0', borderTop: `1px solid ${GVD.rule}` }}>
          <dt style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 1.6, textTransform: 'uppercase', color: GVD.ink2, fontWeight: 600 }}>{term}</dt>
          <dd style={{ margin: 0, fontFamily: GVD.font.serif, fontSize: 16, color: GVD.ink, lineHeight: 1.5 }}>{def}</dd>
        </div>
      ))}
    </dl>
  );
}

function Divider({ label }) {
  if (!label) return <div style={{ height: 1, background: GVD.rule, width: '100%' }} />;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
      <div style={{ flex: 1, height: 1, background: GVD.rule }} />
      <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2.4, textTransform: 'uppercase', color: GVD.ink3, fontWeight: 600 }}>{label}</div>
      <div style={{ flex: 1, height: 1, background: GVD.rule }} />
    </div>
  );
}

function Accordion({ items = [], defaultOpen = -1 }) {
  return (
    <div>
      {items.map((it, i) => (
        <details key={i} open={i === defaultOpen} style={{ borderTop: `1px solid ${GVD.rule}`, padding: '20px 0' }}>
          <summary style={{ fontFamily: GVD.font.serif, fontSize: 19, fontWeight: 600, color: GVD.ink, cursor: 'pointer', listStyle: 'none', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span>{it.q}</span>
            <span style={{ color: GVD.accent, fontFamily: GVD.font.sans, fontWeight: 700, fontSize: 22, marginLeft: 16 }}>+</span>
          </summary>
          <div style={{ fontFamily: GVD.font.sans, fontSize: 14.5, lineHeight: 1.65, color: GVD.ink2, margin: '12px 0 0' }}>{it.a}</div>
        </details>
      ))}
    </div>
  );
}

function PersonCard({ name, role, bio, photoLabel, photoTone = 'warm', email, phone, tags = [] }) {
  return (
    <article style={{ background: GVD.paper, border: `1px solid ${GVD.rule}`, padding: '20px 22px 22px' }}>
      {photoLabel && <div style={{ marginBottom: 16 }}><Photo label={photoLabel} tone={photoTone} height={180} /></div>}
      <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: GVD.accent, fontWeight: 700, marginBottom: 6 }}>{role}</div>
      <h3 style={{ fontFamily: GVD.font.serif, fontSize: 22, fontWeight: 600, color: GVD.ink, margin: '0 0 10px', letterSpacing: -0.2, lineHeight: 1.2 }}>{name}</h3>
      {bio && <p style={{ fontFamily: GVD.font.sans, fontSize: 13.5, lineHeight: 1.6, color: GVD.ink2, margin: '0 0 14px' }}>{bio}</p>}
      {(email || phone) && (
        <div style={{ borderTop: `1px solid ${GVD.rule}`, paddingTop: 12, fontFamily: GVD.font.mono, fontSize: 12, color: GVD.ink2, lineHeight: 1.7 }}>
          {email && <div>{email}</div>}
          {phone && <div>{phone}</div>}
        </div>
      )}
      {tags.length > 0 && <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 12 }}>{tags.map((t) => <Tag key={t}>{t}</Tag>)}</div>}
    </article>
  );
}

function CTABanner({ eyebrow, title, body, primary, secondary, dark = true }) {
  const fg = dark ? GVD.paper : GVD.ink;
  const muted = dark ? 'rgba(255,255,255,0.78)' : GVD.ink2;
  return (
    <section style={{ background: dark ? GVD.ink : GVD.bg, color: fg, padding: '56px 0', borderTop: dark ? 'none' : `1px solid ${GVD.rule}`, borderBottom: dark ? 'none' : `1px solid ${GVD.rule}` }}>
      <div style={{ maxWidth: 1120, margin: '0 auto', padding: '0 32px', display: 'grid', gridTemplateColumns: '1.6fr 1fr', gap: 48, alignItems: 'center' }}>
        <div>
          {eyebrow && <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 3, textTransform: 'uppercase', color: muted, marginBottom: 12 }}>{eyebrow}</div>}
          <h2 style={{ fontFamily: GVD.font.serif, fontSize: 36, fontWeight: 700, margin: 0, letterSpacing: -0.5, lineHeight: 1.1 }}>{title}</h2>
          {body && <p style={{ fontFamily: GVD.font.sans, fontSize: 15, lineHeight: 1.6, color: muted, margin: '14px 0 0', maxWidth: 640 }}>{body}</p>}
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {primary && <PrimaryButton style={dark ? { background: GVD.paper, color: GVD.ink } : {}}>{primary}</PrimaryButton>}
          {secondary && <GhostButton style={dark ? { borderColor: GVD.paper, color: GVD.paper } : {}}>{secondary}</GhostButton>}
        </div>
      </div>
    </section>
  );
}

function DownloadCard({ title, meta, format = 'PDF', size, href = '#' }) {
  return (
    <a href={href} style={{ textDecoration: 'none', display: 'grid', gridTemplateColumns: '64px 1fr auto', gap: 18, alignItems: 'center', padding: '18px 22px', background: GVD.paper, border: `1px solid ${GVD.rule}`, color: GVD.ink }}>
      <div style={{ width: 64, height: 64, border: `1.5px solid ${GVD.ink}`, display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: GVD.font.mono, fontSize: 13, fontWeight: 700, color: GVD.ink, letterSpacing: 0.5 }}>{format}</div>
      <div>
        <div style={{ fontFamily: GVD.font.serif, fontSize: 19, fontWeight: 600, lineHeight: 1.3, marginBottom: 4 }}>{title}</div>
        <div style={{ fontFamily: GVD.font.mono, fontSize: 12, color: GVD.ink3 }}>{meta}{size ? ` · ${size}` : ''}</div>
      </div>
      <div style={{ fontFamily: GVD.font.sans, fontSize: 13, fontWeight: 600, color: GVD.ink, letterSpacing: 0.3, borderBottom: `1.5px solid ${GVD.ink}`, paddingBottom: 2 }}>Download ↓</div>
    </a>
  );
}

function DataTable({ columns = [], rows = [], caption }) {
  return (
    <div>
      {caption && <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', color: GVD.ink2, fontWeight: 600, marginBottom: 10 }}>{caption}</div>}
      <table style={{ width: '100%', borderCollapse: 'collapse', fontFamily: GVD.font.sans }}>
        <thead>
          <tr>
            {columns.map((c, i) => (
              <th key={i} style={{ textAlign: c.align || 'left', fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 1.6, textTransform: 'uppercase', color: GVD.ink2, fontWeight: 600, padding: '12px 14px 12px 0', borderBottom: `2px solid ${GVD.ink}` }}>{c.label}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.map((r, i) => (
            <tr key={i}>
              {columns.map((c, j) => {
                const val = r[c.key];
                const isFirst = j === 0;
                return (
                  <td key={j} style={{
                    textAlign: c.align || 'left',
                    fontFamily: isFirst ? GVD.font.serif : GVD.font.sans,
                    fontSize: isFirst ? 16 : 14,
                    color: isFirst ? GVD.ink : GVD.ink2,
                    fontWeight: isFirst ? 600 : 400,
                    padding: '14px 14px 14px 0',
                    borderBottom: `1px solid ${GVD.rule}`,
                    verticalAlign: 'top',
                  }}>{val}</td>
                );
              })}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function Figure({ photoLabel, photoTone = 'cool', height = 280, caption, credit }) {
  return (
    <figure style={{ margin: 0 }}>
      <Photo label={photoLabel} tone={photoTone} height={height} />
      {(caption || credit) && (
        <figcaption style={{ borderTop: `1px solid ${GVD.rule}`, paddingTop: 10, marginTop: 12, display: 'flex', justifyContent: 'space-between', gap: 24, fontFamily: GVD.font.sans, fontSize: 12.5, color: GVD.ink2, lineHeight: 1.5 }}>
          <span style={{ fontStyle: 'italic', fontFamily: GVD.font.serif, fontSize: 14 }}>{caption}</span>
          {credit && <span style={{ fontFamily: GVD.font.mono, fontSize: 11, color: GVD.ink3, whiteSpace: 'nowrap' }}>{credit}</span>}
        </figcaption>
      )}
    </figure>
  );
}

function SiteAlert({ kicker = 'Alert', title, action, onDismiss }) {
  return (
    <div style={{ background: GVD.accent, color: GVD.paper, fontFamily: GVD.font.sans }}>
      <div style={{ maxWidth: 1120, margin: '0 auto', padding: '12px 32px', display: 'flex', alignItems: 'center', gap: 16 }}>
        <span style={{ fontSize: 11, letterSpacing: 2, textTransform: 'uppercase', fontWeight: 700, padding: '3px 8px', border: '1px solid rgba(255,255,255,0.55)' }}>{kicker}</span>
        <span style={{ fontSize: 14, fontWeight: 500, flex: 1 }}>{title}</span>
        {action && <a href="#" style={{ fontSize: 13, fontWeight: 600, color: GVD.paper, textDecoration: 'none', borderBottom: `1.5px solid ${GVD.paper}`, paddingBottom: 1, letterSpacing: 0.3 }}>{action} →</a>}
        {onDismiss && <button onClick={onDismiss} style={{ background: 'transparent', border: 'none', color: GVD.paper, cursor: 'pointer', fontSize: 18, padding: '0 0 0 8px', lineHeight: 1 }} aria-label="Dismiss">×</button>}
      </div>
    </div>
  );
}

function PageTOC({ items = [], active }) {
  return (
    <nav style={{ fontFamily: GVD.font.sans, position: 'sticky', top: 24 }}>
      <div style={{ fontSize: 11, letterSpacing: 2.4, textTransform: 'uppercase', color: GVD.ink2, fontWeight: 600, marginBottom: 12, paddingBottom: 8, borderBottom: `1px solid ${GVD.rule}` }}>On this page</div>
      <ol style={{ listStyle: 'none', margin: 0, padding: 0 }}>
        {items.map((it, i) => {
          const isActive = it.id === active;
          return (
            <li key={i}>
              <a href={'#' + it.id} style={{
                display: 'flex', gap: 12, padding: '8px 0',
                textDecoration: 'none',
                fontFamily: GVD.font.sans, fontSize: 13.5,
                color: isActive ? GVD.ink : GVD.ink2,
                fontWeight: isActive ? 600 : 400,
                borderLeft: isActive ? `2px solid ${GVD.accent}` : '2px solid transparent',
                paddingLeft: 12, marginLeft: -14,
                lineHeight: 1.4,
              }}>
                <span style={{ fontFamily: GVD.font.mono, fontSize: 11, color: GVD.ink3, minWidth: 22 }}>{String(i + 1).padStart(2, '0')}</span>
                <span>{it.label}</span>
              </a>
            </li>
          );
        })}
      </ol>
    </nav>
  );
}

// SplitSection — 1:2 column layout: intro panel on the left
// (eyebrow + title + lede + optional link), scannable list on the right.
// Use for upcoming events, recent posts, FAQ blocks, contact directories,
// anywhere the page needs a "section about X + items in X" rhythm.
function SplitSection({ eyebrow, title, lede, link, linkHref = '#', children, background, ratio = '1fr 2fr', gap = 64, divider = true, padding = 72 }) {
  const bg = background || GVD.bg;
  return (
    <section style={{ background: bg, borderTop: divider ? `1px solid ${GVD.rule}` : 'none', padding: `${padding}px 0` }}>
      <div style={{ maxWidth: 1120, margin: '0 auto', padding: '0 32px', display: 'grid', gridTemplateColumns: ratio, gap }}>
        <div>
          {eyebrow ? <Eyebrow style={{ marginBottom: 12 }}>{eyebrow}</Eyebrow> : null}
          {title ? <h2 style={{ fontFamily: GVD.font.serif, fontSize: 36, fontWeight: 700, color: GVD.ink, margin: '0 0 16px', letterSpacing: -0.5, lineHeight: 1.1 }}>{title}</h2> : null}
          {lede ? <p style={{ fontFamily: GVD.font.sans, fontSize: 14, lineHeight: 1.6, color: GVD.ink2, margin: '0 0 18px' }}>{lede}</p> : null}
          {link ? <PrimaryLink href={linkHref}>{link}</PrimaryLink> : null}
        </div>
        <div>{children}</div>
      </div>
    </section>
  );
}

function GVDFooter() {
  return (
    <footer style={{ background: GVD.ink, color: '#dfe6ee', padding: '64px 0 28px' }}>
      <div style={{ maxWidth: 1120, margin: '0 auto', padding: '0 32px' }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.4fr 1fr 1fr 1fr', gap: 48, paddingBottom: 48, borderBottom: '1px solid rgba(255,255,255,0.15)' }}>
          <div>
            <div style={{ fontFamily: GVD.font.serif, fontSize: 22, fontWeight: 700, color: '#fff', marginBottom: 14 }}>Green Valley Democrats</div>
            <p style={{ fontFamily: GVD.font.sans, fontSize: 13.5, lineHeight: 1.6, color: '#aebac8', margin: '0 0 18px' }}>
              The Democratic club of Green Valley, Sahuarita, Tubac and surrounding communities in Legislative District 21.
            </p>
            <div style={{ display: 'flex', gap: 10 }}>
              {[
                { label: 'fb', href: 'https://www.facebook.com/Greenvalleydemocrats/' },
                { label: 'bs', href: 'https://bsky.app/profile/greenvalleydems.bsky.social' },
              ].map(({ label, href }) => (
                <a key={label} href={href} target="_blank" rel="noopener noreferrer" style={{ width: 32, height: 32, borderRadius: 16, border: '1px solid rgba(255,255,255,0.25)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontFamily: GVD.font.sans, fontSize: 11, color: '#aebac8', textDecoration: 'none' }}>{label}</a>
              ))}
            </div>
          </div>
          {[
            ['Visit', ['Continental Shopping Plaza, Suite 208', '190 W. Continental Road', 'Green Valley, AZ 85622', 'Office hours: M–F, 10 a.m.–2 p.m.']],
            ['Contact', ['(520) 838-0590', 'GreenValleyDemocrats@gmail.com', 'Mailing: PO Box 131, GV AZ 85622']],
            ['Quick Links', [
              { label: 'Become a Member', href: 'join.html' },
              { label: 'Volunteer', href: 'volunteer.html' },
              { label: 'Donate', href: 'https://secure.actblue.com/donate/green-valley-democrats-1' },
              { label: 'About Us', href: 'about.html' },
              { label: 'Resources', href: 'resources.html' },
            ]],
          ].map(([title, items]) => (
            <div key={title}>
              <div style={{ fontFamily: GVD.font.sans, fontSize: 11, letterSpacing: 2.5, textTransform: 'uppercase', color: '#fff', marginBottom: 14 }}>{title}</div>
              {items.map((x) => {
                const label = typeof x === 'string' ? x : x.label;
                const href = typeof x === 'string' ? null : x.href;
                return href
                  ? <a key={label} href={href} style={{ display: 'block', fontFamily: GVD.font.sans, fontSize: 13.5, color: '#aebac8', lineHeight: 1.9, textDecoration: 'none' }}>{label}</a>
                  : <div key={label} style={{ fontFamily: GVD.font.sans, fontSize: 13.5, color: '#aebac8', lineHeight: 1.9 }}>{label}</div>;
              })}
            </div>
          ))}
        </div>
        <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: 24, fontFamily: GVD.font.sans, fontSize: 12, color: '#7e8d9d' }}>
          <div>© 2026 Green Valley Democratic Club · Paid for by Green Valley Democrats. Not authorized by any candidate or candidate’s committee.</div>
          <div><a href="pdfs/privacy-policy.pdf" style={{ color: '#7e8d9d', textDecoration: 'none' }}>Privacy Policy</a></div>
        </div>
      </div>
    </footer>
  );
}

Object.assign(window, {
  GVD, GVD_NAV,
  GVDHeader, GVDFooter, GVDPageHero,
  Eyebrow, SectionTitle, AccentRule,
  PrimaryButton, GhostButton, PrimaryLink,
  FormLabel, FormHelp, TextField, Select, Checkbox, Radio,
  Callout, Stat, PullQuote, EventCard, ArticleCard, Tag, Breadcrumbs, DefinitionList, Divider,
  Accordion, PersonCard, CTABanner, DownloadCard, DataTable, Figure, SiteAlert, PageTOC, SplitSection,
});
