// Shared primitives used by all three variations of the honeymoon registry.
// Each variation imports these globals from window.

const WEDDING_DATE = new Date('2026-06-13T13:00:00');

// Monzo.Me link for the joint account. The h= and account_type=joint params
// must be preserved exactly — they're what tells Monzo to pay into the joint pot.
const MONZO_URL_TEMPLATE = 'https://monzo.me/jimbobhofton?h=XD7frY&account_type=joint';

function buildMonzoUrl(amount, gift, from, note) {
  const url = new URL(MONZO_URL_TEMPLATE);
  url.pathname = `${url.pathname}/${encodeURIComponent(amount)}`;
  let desc = gift.title;
  if (from) desc += ` — from ${from}`;
  if (note) desc += ` — "${note}"`;
  url.searchParams.set('d', desc);
  return url.toString();
}

// ─── Gift list ───
const GIFTS = [
  { id: 'coffee',   title: 'Coffee for two',           price: 5,    blurb: 'Fuel us up for a morning coastal walk — two proper flat whites.', mark: 'coffee' },
  { id: 'guinness', title: 'A pint of the black stuff', price: 7,    blurb: 'You can\u2019t go to Ireland and not have one. Go on, buy us one.', mark: 'pint' },
  { id: 'lunch',    title: 'Harbour lunch',            price: 20,   blurb: 'Fish &amp; chips on the pier, a bowl of chowder, or a pub lunch with a view.', mark: 'bowl' },
  { id: 'kayak',    title: 'Kayak on a lough',         price: 35,   blurb: 'An hour on the water somewhere impossibly still and green.', mark: 'paddle' },
  { id: 'campsite', title: 'A night at a pitch',       price: 40,   blurb: 'Somewhere with a sea view, maybe a campfire, definitely stars.', mark: 'tent' },
  { id: 'cliffs',   title: 'Cliffs of Moher day',      price: 45,   blurb: 'Entry, coffee, a windswept walk and slightly too many photos.', mark: 'cliff' },
  { id: 'dinner',   title: 'Proper dinner out',        price: 50,   blurb: 'A sit-down somewhere special to actually celebrate being married.', mark: 'fork' },
  { id: 'spa',      title: 'Spa day recovery',         price: 80,   blurb: 'After the hiking and driving, help us properly switch off.', mark: 'steam' },
  { id: 'diesel',   title: 'A tank of diesel',         price: 100,  blurb: 'The Sprinter is thirsty. Keep us moving up the Wild Atlantic Way.', mark: 'fuel' },
  { id: 'ferry',    title: 'Ferry to the islands',     price: 120,  blurb: 'Crossing to the Aran Islands \u2014 stone walls, seals, and no WiFi.', mark: 'ferry' },
  { id: 'custom',   title: 'You pick the amount',      price: null, blurb: 'Whatever feels right. Every little bit becomes part of the trip.', mark: 'heart' },
];

// ─── Countdown hook ───
function useCountdown(target) {
  const [now, setNow] = React.useState(() => new Date());
  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  const diff = Math.max(0, target - now);
  const days    = Math.floor(diff / 86400000);
  const hours   = Math.floor((diff % 86400000) / 3600000);
  const minutes = Math.floor((diff % 3600000) / 60000);
  const seconds = Math.floor((diff % 60000) / 1000);
  return { days, hours, minutes, seconds, done: diff === 0 };
}

// ─── Guestbook storage (shared via /api/guestbook) ───
// `storageKey` arg is unused now (kept for call-site compatibility); the
// guestbook is global, not per-page.
function useGuestbook(_storageKey) {
  const [entries, setEntries] = React.useState([]);

  React.useEffect(() => {
    let cancelled = false;
    fetch('/api/guestbook')
      .then(r => r.ok ? r.json() : [])
      .then(data => { if (!cancelled && Array.isArray(data)) setEntries(data); })
      .catch(() => {});
    return () => { cancelled = true; };
  }, []);

  const add = async (name, msg) => {
    const entry = {
      name: name.trim(),
      msg: msg.trim(),
      when: new Date().toLocaleDateString('en-GB', { month: 'short', day: 'numeric' }),
    };
    setEntries(prev => [entry, ...prev].slice(0, 200));
    try {
      const res = await fetch('/api/guestbook', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: entry.name, msg: entry.msg, hp: '' }),
      });
      if (!res.ok) throw new Error(`status ${res.status}`);
      const list = await res.json();
      if (Array.isArray(list)) setEntries(list);
    } catch (err) {
      setEntries(prev => prev.filter(x => !(x.name === entry.name && x.msg === entry.msg && x.when === entry.when)));
      if (typeof window !== 'undefined') window.alert("Couldn't post your note — please try again in a moment.");
    }
  };

  return [entries, add];
}

// ─── Gift modal (mocked payment flow) ───
function GiftModal({ gift, onClose, accent = '#7a8a6b' }) {
  const [step, setStep] = React.useState('form');
  const [amount, setAmount] = React.useState(gift?.price || 25);
  const [from, setFrom] = React.useState('');
  const [note, setNote] = React.useState('');

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

  if (!gift) return null;

  const submit = (e) => {
    e.preventDefault();
    const amt = Math.max(1, Math.floor(Number(amount) || 0));
    if (!amt) return;
    const url = buildMonzoUrl(amt, gift, from, note);
    const win = window.open(url, '_blank', 'noopener,noreferrer');
    if (!win) {
      // popup blocked — fall back to same-tab navigation
      window.location.href = url;
      return;
    }
    setStep('thanks');
  };

  return (
    <div style={{
      position: 'fixed', inset: 0, background: 'rgba(30,25,20,0.55)',
      backdropFilter: 'blur(4px)', zIndex: 1000,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '20px', animation: 'fadeIn .2s ease'
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        background: '#fbf6ec', borderRadius: 8, maxWidth: 440, width: '100%',
        padding: '32px 28px', boxShadow: '0 30px 80px rgba(0,0,0,0.3)',
        border: `1px solid ${accent}33`, fontFamily: 'inherit',
        animation: 'slideUp .25s cubic-bezier(.2,.8,.3,1)'
      }}>
        {step === 'form' && (
          <>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.18em', color: accent, textTransform: 'uppercase', marginBottom: 12 }}>
              Gift &middot; {gift.id}
            </div>
            <h3 style={{ fontFamily: 'var(--serif)', fontSize: 28, lineHeight: 1.1, margin: '0 0 6px', color: '#2a2620' }}>{gift.title}</h3>
            <p style={{ fontSize: 14, color: '#6b6357', lineHeight: 1.5, margin: '0 0 20px' }} dangerouslySetInnerHTML={{__html: gift.blurb}} />
            <form onSubmit={submit}>
              <label style={{ display: 'block', fontSize: 11, letterSpacing: '.12em', textTransform: 'uppercase', color: '#6b6357', marginBottom: 6, fontFamily: 'JetBrains Mono, monospace' }}>Amount (£)</label>
              <input type="number" min="1" value={amount} onChange={e => setAmount(e.target.value)} style={{
                width: '100%', padding: '10px 12px', fontSize: 18, fontFamily: 'var(--serif)',
                border: `1px solid ${accent}55`, background: '#fff', borderRadius: 4, marginBottom: 14, color: '#2a2620'
              }} />
              <label style={{ display: 'block', fontSize: 11, letterSpacing: '.12em', textTransform: 'uppercase', color: '#6b6357', marginBottom: 6, fontFamily: 'JetBrains Mono, monospace' }}>Your name</label>
              <input type="text" value={from} onChange={e => setFrom(e.target.value)} placeholder="so we can thank you" required style={{
                width: '100%', padding: '10px 12px', fontSize: 15, fontFamily: 'inherit',
                border: `1px solid ${accent}55`, background: '#fff', borderRadius: 4, marginBottom: 14, color: '#2a2620'
              }} />
              <label style={{ display: 'block', fontSize: 11, letterSpacing: '.12em', textTransform: 'uppercase', color: '#6b6357', marginBottom: 6, fontFamily: 'JetBrains Mono, monospace' }}>Note (optional)</label>
              <textarea value={note} onChange={e => setNote(e.target.value)} rows="2" placeholder="a wish, a joke, a threat" style={{
                width: '100%', padding: '10px 12px', fontSize: 14, fontFamily: 'inherit', resize: 'vertical',
                border: `1px solid ${accent}55`, background: '#fff', borderRadius: 4, marginBottom: 20, color: '#2a2620'
              }} />
              <div style={{ display: 'flex', gap: 10 }}>
                <button type="button" onClick={onClose} style={{ flex: 1, padding: '12px 16px', background: 'transparent', border: `1px solid ${accent}66`, borderRadius: 4, fontFamily: 'inherit', fontSize: 14, cursor: 'pointer', color: '#2a2620' }}>Cancel</button>
                <button type="submit" style={{ flex: 2, padding: '12px 16px', background: accent, color: '#fbf6ec', border: 'none', borderRadius: 4, fontFamily: 'inherit', fontSize: 14, fontWeight: 600, cursor: 'pointer', letterSpacing: '.02em' }}>Send £{amount} via Monzo →</button>
              </div>
              <div style={{ fontSize: 11, color: '#9a9286', textAlign: 'center', marginTop: 12, fontFamily: 'JetBrains Mono, monospace', letterSpacing: '.08em' }}>
                Opens in a new tab. Pay by Monzo or any UK card.
              </div>
            </form>
          </>
        )}
        {step === 'thanks' && (
          <div style={{ textAlign: 'center', padding: '20px 0' }}>
            <div style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '.2em', color: accent, textTransform: 'uppercase', marginBottom: 14 }}>↗ Opened Monzo</div>
            <h3 style={{ fontFamily: 'var(--serif)', fontSize: 32, lineHeight: 1.1, margin: '0 0 10px', color: '#2a2620' }}>Thank you, {from || 'you'}.</h3>
            <p style={{ fontSize: 15, color: '#6b6357', lineHeight: 1.55, margin: '0 0 24px', maxWidth: 320, marginLeft: 'auto', marginRight: 'auto' }}>
              £{amount} towards <em>{gift.title.toLowerCase()}</em> in a new tab. Tap send in Monzo and it lands in our feed straight away \u2014 we\u2019ll raise a glass to you somewhere on the west coast.
            </p>
            <p style={{ fontSize: 11, color: '#9a9286', lineHeight: 1.55, margin: '0 0 22px', maxWidth: 280, marginLeft: 'auto', marginRight: 'auto', fontFamily: 'JetBrains Mono, monospace', letterSpacing: '.05em' }}>
              {"Tab didn’t open? "}
              <a href="#" onClick={(e) => { e.preventDefault(); window.location.href = buildMonzoUrl(Math.max(1, Math.floor(Number(amount) || 0)), gift, from, note); }} style={{ color: accent, textDecoration: 'underline' }}>Open Monzo here</a>.
            </p>
            <button onClick={onClose} style={{ padding: '12px 28px', background: accent, color: '#fbf6ec', border: 'none', borderRadius: 4, fontFamily: 'inherit', fontSize: 14, fontWeight: 600, cursor: 'pointer', letterSpacing: '.02em' }}>Close</button>
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Tiny hand-drawn-feel SVG glyphs for gift marks ───
function GiftMark({ kind, size = 40, stroke = '#4a4338' }) {
  const s = { width: size, height: size, fill: 'none', stroke, strokeWidth: 1.4, strokeLinecap: 'round', strokeLinejoin: 'round' };
  switch (kind) {
    case 'coffee':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M8 14 L30 14 L28 30 Q28 33 25 33 L13 33 Q10 33 10 30 Z"/><path d="M30 18 Q36 18 36 23 Q36 27 30 27"/><path d="M14 6 Q14 10 16 10 M20 6 Q20 10 22 10"/></svg>);
    case 'pint':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M12 10 L28 10 L26 34 Q26 36 24 36 L16 36 Q14 36 14 34 Z"/><path d="M13 18 Q20 15 27 18" /><circle cx="16" cy="14" r="1" fill={stroke}/><circle cx="22" cy="13" r="1" fill={stroke}/></svg>);
    case 'bowl':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M6 18 Q6 30 20 30 Q34 30 34 18 Z"/><path d="M12 14 Q12 10 16 12 M22 12 Q22 8 26 10"/></svg>);
    case 'paddle':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M6 32 L34 32"/><path d="M10 32 Q20 26 30 32"/><path d="M18 26 L24 8 L26 8 L22 26"/></svg>);
    case 'tent':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M6 32 L20 8 L34 32 Z"/><path d="M20 8 L20 32"/><path d="M16 32 L20 24 L24 32"/></svg>);
    case 'cliff':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M4 30 L12 18 L18 24 L26 10 L36 30 Z"/><circle cx="30" cy="12" r="3"/></svg>);
    case 'fork':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M14 6 L14 16 Q14 20 18 20 L18 34"/><path d="M10 6 L10 14 M18 6 L18 14"/><path d="M26 6 Q30 6 30 14 L28 22 L28 34"/></svg>);
    case 'steam':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M12 20 Q12 14 16 14 Q20 14 20 10 M22 22 Q22 16 26 16 Q30 16 30 12"/><path d="M6 30 Q20 34 34 30"/></svg>);
    case 'fuel':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M8 8 L24 8 L24 34 L8 34 Z"/><path d="M12 12 L20 12 L20 20 L12 20 Z"/><path d="M24 16 L30 16 L30 30 Q30 32 32 32"/><path d="M28 10 L32 14"/></svg>);
    case 'ferry':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M6 26 L34 26 L30 32 L10 32 Z"/><path d="M10 26 L10 16 L30 16 L30 26"/><path d="M14 16 L14 10 L22 10 L22 16"/><path d="M4 34 Q10 36 16 34 Q22 32 28 34 Q34 36 38 34"/></svg>);
    case 'heart':
      return (<svg viewBox="0 0 40 40" style={s}><path d="M20 32 Q8 24 8 16 Q8 10 14 10 Q18 10 20 14 Q22 10 26 10 Q32 10 32 16 Q32 24 20 32 Z"/></svg>);
    default: return null;
  }
}

// ─── Topographic contour background ───
// SVG that tiles as a subtle paper-map texture
function TopoBackground({ color = 'rgba(90,80,65,0.09)', opacity = 1 }) {
  return (
    <svg style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', pointerEvents: 'none', opacity }} aria-hidden>
      <defs>
        <pattern id="topo" x="0" y="0" width="400" height="300" patternUnits="userSpaceOnUse">
          <path d="M-20 120 Q 80 80 180 110 T 400 90" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M-20 150 Q 90 115 190 145 T 420 130" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M-20 180 Q 100 145 200 175 T 420 160" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M-20 210 Q 110 180 210 205 T 420 195" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M-20 240 Q 120 215 220 240 T 420 230" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M40 60 Q 140 30 240 60 T 460 50" fill="none" stroke={color} strokeWidth="1"/>
          <path d="M60 20 Q 160 -5 260 20" fill="none" stroke={color} strokeWidth="1"/>
        </pattern>
      </defs>
      <rect width="100%" height="100%" fill="url(#topo)"/>
    </svg>
  );
}

// ─── Rough hand-drawn Ireland silhouette with route line + labels ───
function IrelandRoute({ stroke = '#5a4a2a', accent = '#c97a3a', width = 260, labels = false }) {
  // Stops along the route, with labels. Positions are approximate on the silhouette.
  const stops = [
    { x: 155, y: 48,  name: "Giant's Causeway", side: 'right' },
    { x: 78,  y: 80,  name: 'Donegal',          side: 'left'  },
    { x: 54,  y: 142, name: 'Connemara',        side: 'left'  },
    { x: 58,  y: 196, name: 'Cliffs of Moher',  side: 'left'  },
    { x: 78,  y: 252, name: 'Dingle',           side: 'left'  },
    { x: 120, y: 268, name: 'Kerry',            side: 'right' },
    { x: 162, y: 240, name: 'Cork',             side: 'right' },
    { x: 174, y: 168, name: 'Rosslare',         side: 'right' },
    { x: 166, y: 120, name: 'Dublin',           side: 'right' },
  ];
  return (
    <svg viewBox="0 0 240 320" style={{ width, height: 'auto', overflow: 'visible' }}>
      <path d="M110 20 Q 130 18 145 28 Q 165 36 172 54 Q 185 66 190 84 Q 198 100 195 120 Q 205 140 198 162 Q 204 184 188 208 Q 180 232 160 250 Q 148 272 130 282 Q 110 298 88 288 Q 62 284 48 266 Q 32 250 38 226 Q 28 208 36 186 Q 30 162 42 142 Q 38 122 52 104 Q 58 82 78 68 Q 88 46 110 20 Z"
        fill="#e9dfcb" stroke={stroke} strokeWidth="1.5" strokeLinejoin="round"/>
      {/* route dashed — winds through the stops in order */}
      <path d="M155 48 Q 110 60 78 80 Q 58 110 54 142 Q 50 170 58 196 Q 64 228 78 252 Q 100 266 120 268 Q 148 260 162 240 Q 178 208 174 168 Q 170 140 166 120"
        fill="none" stroke={accent} strokeWidth="2" strokeDasharray="4 4" strokeLinecap="round"/>
      {/* stops */}
      {stops.map((s, i) => (
        <g key={i}>
          <circle cx={s.x} cy={s.y} r="3.5" fill={accent}/>
          <circle cx={s.x} cy={s.y} r="6" fill="none" stroke={accent} strokeWidth="0.8" opacity="0.5"/>
          {labels && (
            <text
              x={s.side === 'right' ? s.x + 10 : s.x - 10}
              y={s.y + 3}
              textAnchor={s.side === 'right' ? 'start' : 'end'}
              fontFamily="'JetBrains Mono', monospace"
              fontSize="8"
              letterSpacing="0.12em"
              fill={stroke}
              style={{ textTransform: 'uppercase' }}
            >{s.name.toUpperCase()}</text>
          )}
        </g>
      ))}
    </svg>
  );
}

// ─── Side-view line drawing of the overlanded Sprinter ───
function VanDivider({ stroke = '#2e2a22', accent = '#b8894a', width = 340, fill = 'none' }) {
  const sw = 1.8;
  return (
    <svg viewBox="0 0 340 150" style={{ width, height: 'auto' }} aria-hidden>
      {/* ground */}
      <line x1="0" y1="138" x2="340" y2="138" stroke={stroke} strokeWidth="1" strokeDasharray="4 6" opacity="0.4"/>

      {/* ── ROOF RACK PLATFORM ── */}
      {/* rack side rails */}
      <path d="M42 26 L302 26" stroke={stroke} strokeWidth={sw} strokeLinecap="round" fill="none"/>
      <path d="M44 22 L300 22" stroke={stroke} strokeWidth="1.2" strokeLinecap="round" fill="none"/>
      {/* rack crossbars / detail */}
      {[60, 90, 120, 150, 180, 210, 240, 270].map(x => (
        <line key={x} x1={x} y1="22" x2={x} y2="26" stroke={stroke} strokeWidth="1"/>
      ))}
      {/* LED light bar on front of rack */}
      <rect x="52" y="14" width="80" height="6" rx="1" fill={accent} stroke={stroke} strokeWidth="1.2"/>
      <line x1="58" y1="17" x2="126" y2="17" stroke={stroke} strokeWidth="0.5" opacity="0.6"/>
      {/* rack mounting feet */}
      <line x1="56" y1="26" x2="56" y2="34" stroke={stroke} strokeWidth="1"/>
      <line x1="168" y1="26" x2="168" y2="32" stroke={stroke} strokeWidth="1"/>
      <line x1="290" y1="26" x2="290" y2="32" stroke={stroke} strokeWidth="1"/>
      {/* antenna */}
      <line x1="240" y1="22" x2="244" y2="8" stroke={stroke} strokeWidth="1"/>
      <circle cx="244" cy="8" r="1.2" fill={stroke}/>

      {/* ── MAIN BODY (high-top, boxy) ── */}
      {/* roofline */}
      <path d={`
        M 40 34
        Q 40 30 44 30
        L 298 30
        Q 302 30 302 34
        L 302 112
        Q 302 116 298 116
        L 292 116
      `} fill={fill === 'none' ? 'white' : fill} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      {/* front cab slope (distinctive Sprinter nose) */}
      <path d="M 40 34 L 40 70 L 28 80 L 22 96 L 22 112 L 34 112" fill={fill === 'none' ? 'white' : fill} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      {/* bonnet line */}
      <line x1="22" y1="96" x2="40" y2="96" stroke={stroke} strokeWidth="1"/>
      {/* cab pillar */}
      <line x1="68" y1="34" x2="68" y2="70" stroke={stroke} strokeWidth="1.2"/>

      {/* windscreen */}
      <path d="M 42 70 L 42 36 L 66 36 L 66 70 Z" fill={accent} opacity="0.15" stroke={stroke} strokeWidth="1.2"/>
      {/* cab door window */}
      <rect x="70" y="38" width="24" height="28" fill={accent} opacity="0.15" stroke={stroke} strokeWidth="1.2"/>
      {/* cab door handle + line */}
      <line x1="68" y1="74" x2="96" y2="74" stroke={stroke} strokeWidth="0.8"/>
      <rect x="86" y="76" width="5" height="2" fill={stroke}/>
      <line x1="96" y1="34" x2="96" y2="112" stroke={stroke} strokeWidth="1"/>

      {/* sliding door panel */}
      <line x1="98" y1="34" x2="98" y2="112" stroke={stroke} strokeWidth="0.8" opacity="0.5"/>
      <line x1="178" y1="34" x2="178" y2="112" stroke={stroke} strokeWidth="0.8" opacity="0.5"/>
      {/* slider track */}
      <line x1="100" y1="70" x2="178" y2="70" stroke={stroke} strokeWidth="0.6" opacity="0.4"/>
      {/* slider window (tinted) */}
      <rect x="110" y="44" width="56" height="24" fill={stroke} opacity="0.7" stroke={stroke} strokeWidth="1"/>
      {/* slider door handle */}
      <rect x="166" y="78" width="6" height="2.5" fill={stroke}/>

      {/* rear quarter window (tinted, small) */}
      <rect x="220" y="44" width="56" height="24" fill={stroke} opacity="0.7" stroke={stroke} strokeWidth="1"/>
      {/* rear door seam */}
      <line x1="288" y1="34" x2="288" y2="112" stroke={stroke} strokeWidth="0.8" opacity="0.5"/>

      {/* rocker panel (darker lower strip) */}
      <rect x="22" y="106" width="280" height="8" fill={stroke} opacity="0.85"/>

      {/* side awning bracket */}
      <rect x="180" y="30" width="108" height="4" fill={stroke} opacity="0.7"/>

      {/* badge / grill hint */}
      <circle cx="28" cy="88" r="3" fill="none" stroke={stroke} strokeWidth="0.8"/>
      <line x1="26" y1="88" x2="30" y2="88" stroke={stroke} strokeWidth="0.6"/>
      <line x1="28" y1="86" x2="28" y2="90" stroke={stroke} strokeWidth="0.6"/>
      {/* headlight */}
      <path d="M 24 82 L 32 82 L 34 86 L 24 86 Z" fill={accent} stroke={stroke} strokeWidth="0.8"/>

      {/* tail light */}
      <rect x="295" y="80" width="5" height="14" fill={stroke} opacity="0.5" stroke={stroke} strokeWidth="0.6"/>

      {/* ── WHEELS (beefy off-road) ── */}
      {/* arch cutouts */}
      <path d="M 48 112 Q 48 96 70 96 Q 92 96 92 112" fill={fill === 'none' ? 'white' : fill} stroke={stroke} strokeWidth={sw}/>
      <path d="M 232 112 Q 232 96 254 96 Q 276 96 276 112" fill={fill === 'none' ? 'white' : fill} stroke={stroke} strokeWidth={sw}/>

      {/* front wheel — chunky tyre + alloy */}
      <circle cx="70" cy="116" r="20" fill={stroke}/>
      <circle cx="70" cy="116" r="14" fill="none" stroke={accent} strokeWidth="0.8"/>
      <circle cx="70" cy="116" r="10" fill="white" stroke={stroke} strokeWidth="1"/>
      <circle cx="70" cy="116" r="3" fill={stroke}/>
      {/* 5-spoke alloy */}
      {[0, 72, 144, 216, 288].map(a => {
        const rad = (a * Math.PI) / 180;
        return <line key={a} x1={70} y1={116} x2={70 + Math.cos(rad) * 9} y2={116 + Math.sin(rad) * 9} stroke={stroke} strokeWidth="1.4"/>;
      })}
      {/* tyre tread marks */}
      {[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map(a => {
        const rad = (a * Math.PI) / 180;
        return <line key={a} x1={70 + Math.cos(rad) * 16} y1={116 + Math.sin(rad) * 16} x2={70 + Math.cos(rad) * 19} y2={116 + Math.sin(rad) * 19} stroke="white" strokeWidth="1.4"/>;
      })}

      {/* rear wheel */}
      <circle cx="254" cy="116" r="20" fill={stroke}/>
      <circle cx="254" cy="116" r="14" fill="none" stroke={accent} strokeWidth="0.8"/>
      <circle cx="254" cy="116" r="10" fill="white" stroke={stroke} strokeWidth="1"/>
      <circle cx="254" cy="116" r="3" fill={stroke}/>
      {[0, 72, 144, 216, 288].map(a => {
        const rad = (a * Math.PI) / 180;
        return <line key={a} x1={254} y1={116} x2={254 + Math.cos(rad) * 9} y2={116 + Math.sin(rad) * 9} stroke={stroke} strokeWidth="1.4"/>;
      })}
      {[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map(a => {
        const rad = (a * Math.PI) / 180;
        return <line key={`r${a}`} x1={254 + Math.cos(rad) * 16} y1={116 + Math.sin(rad) * 16} x2={254 + Math.cos(rad) * 19} y2={116 + Math.sin(rad) * 19} stroke="white" strokeWidth="1.4"/>;
      })}

      {/* number plate */}
      <rect x="6" y="102" width="16" height="6" fill="white" stroke={stroke} strokeWidth="0.6"/>
      <text x="14" y="107" fontFamily="monospace" fontSize="4.5" textAnchor="middle" fill={stroke}>JB09 DNB</text>

      {/* mud flaps */}
      <path d="M 48 118 L 48 128 L 54 128" stroke={stroke} strokeWidth="1.4" fill="none"/>
      <path d="M 276 118 L 276 128 L 282 128" stroke={stroke} strokeWidth="1.4" fill="none"/>

      {/* motion lines */}
      <line x1="312" y1="70" x2="334" y2="70" stroke={stroke} strokeWidth="1" opacity="0.35"/>
      <line x1="316" y1="82" x2="334" y2="82" stroke={stroke} strokeWidth="1" opacity="0.35"/>
      <line x1="312" y1="94" x2="334" y2="94" stroke={stroke} strokeWidth="1" opacity="0.35"/>
    </svg>
  );
}

// ─── Subtle paper grain overlay ───
function PaperGrain({ opacity = 0.5 }) {
  return (
    <svg style={{ position:'fixed', inset:0, width:'100%', height:'100%', pointerEvents:'none', zIndex:99, mixBlendMode:'multiply', opacity }} aria-hidden>
      <filter id="grainFilter">
        <feTurbulence type="fractalNoise" baseFrequency="0.85" numOctaves="2" stitchTiles="stitch"/>
        <feColorMatrix values="0 0 0 0 0.25  0 0 0 0 0.2  0 0 0 0 0.13  0 0 0 0.08 0"/>
      </filter>
      <rect width="100%" height="100%" filter="url(#grainFilter)"/>
    </svg>
  );
}

Object.assign(window, { GIFTS, WEDDING_DATE, useCountdown, useGuestbook, GiftModal, GiftMark, TopoBackground, IrelandRoute, VanDivider, PaperGrain });
