// Shared UI atoms — icons, chrome, bits

// ─── Icons (all 24px line, 1.5 stroke) ───────────────────
const I = {
  home: (c="currentColor") => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-6h-6v6H4a1 1 0 01-1-1v-9z"/></svg>,
  compass: (c="currentColor") => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M15.5 8.5l-2 5.5-5 2 2-5.5 5-2z"/></svg>,
  book: (c="currentColor") => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M4 4h7a3 3 0 013 3v13a2 2 0 00-2-2H4V4zM20 4h-7a3 3 0 00-3 3v13a2 2 0 012-2h8V4z"/></svg>,
  badge: (c="currentColor") => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.3"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="6" strokeDasharray="2.2 2.2"/></svg>,
  user: (c="currentColor") => <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-6 8-6s8 2 8 6"/></svg>,
  back: (c="currentColor") => <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M15 18l-6-6 6-6"/></svg>,
  chev: (c="currentColor") => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M9 18l6-6-6-6"/></svg>,
  plus: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>,
  search: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="7"/><path d="M20 20l-3.5-3.5"/></svg>,
  filter: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M4 6h16M7 12h10M10 18h4"/></svg>,
  mountain: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"><path d="M3 20l6-10 4 6 3-4 5 8H3z"/></svg>,
  pin: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s7-7 7-12a7 7 0 10-14 0c0 5 7 12 7 12z"/><circle cx="12" cy="10" r="2.5"/></svg>,
  share: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="6" cy="12" r="2"/><circle cx="18" cy="6" r="2"/><circle cx="18" cy="18" r="2"/><path d="M8 11l8-4M8 13l8 4"/></svg>,
  heart: (c="currentColor", f="none") => <svg width="18" height="18" viewBox="0 0 24 24" fill={f} stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M12 20s-7-4.5-7-10a4 4 0 017-2.6A4 4 0 0119 10c0 5.5-7 10-7 10z"/></svg>,
  sun: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round"><circle cx="12" cy="12" r="3.5"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M5 5l1.5 1.5M17.5 17.5L19 19M5 19l1.5-1.5M17.5 6.5L19 5"/></svg>,
  drop: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3c-3 4-6 7.5-6 11a6 6 0 0012 0c0-3.5-3-7-6-11z"/></svg>,
  clock: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>,
  leaf: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M5 19c0-8 6-14 16-14-1 8-6 14-14 14-1 0-2 0-2 0zM5 19c2-4 5-7 10-10"/></svg>,
  check: (c="currentColor") => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6L9 17l-5-5"/></svg>,
  lock: (c="currentColor") => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 018 0v4"/></svg>,
  camera: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M3 8h3l2-3h8l2 3h3v11a1 1 0 01-1 1H4a1 1 0 01-1-1V8z"/><circle cx="12" cy="13.5" r="4"/></svg>,
  sparkle: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3l1.8 5.2L19 10l-5.2 1.8L12 17l-1.8-5.2L5 10l5.2-1.8L12 3z"/></svg>,
  tent: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><path d="M3 20l9-16 9 16H3z"/><path d="M12 4v16M9 20l3-4 3 4"/></svg>,
  dollar: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="M12 3v18M17 7H9.5a3 3 0 000 6h5a3 3 0 010 6H6"/></svg>,
  users: (c="currentColor") => <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="8" r="3.5"/><circle cx="17" cy="9" r="2.5"/><path d="M3 20c0-3 2.5-5 6-5s6 2 6 5M15 15c2.5 0 5 1.5 5 5"/></svg>,
  grid: (c="currentColor") => <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.4"><rect x="4" y="4" width="7" height="7" rx="1"/><rect x="13" y="4" width="7" height="7" rx="1"/><rect x="4" y="13" width="7" height="7" rx="1"/><rect x="13" y="13" width="7" height="7" rx="1"/></svg>,
};

// ─── Small caps label ────────────────────────────────────
function Caps({ children, s = 11, c, letter = 0.16, style = {} }) {
  return <span style={{
    fontFamily: 'JetBrains Mono, ui-monospace, monospace',
    fontSize: s, letterSpacing: letter + 'em',
    textTransform: 'uppercase', color: c || 'var(--ink-3)',
    fontWeight: 600, ...style
  }}>{children}</span>;
}

// ─── Progress bar (with optional label + ticks) ─────────
function ProgressBar({ pct = 0, label, right, showPct = true, height = 6, style = {} }) {
  const clamped = Math.max(0, Math.min(100, pct));
  return (
    <div style={style}>
      {(label || right || showPct) && (
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
          {label && <Caps s={9}>{label}</Caps>}
          {right ? <Caps s={9}>{right}</Caps> : (showPct && <span style={{
            fontFamily: 'Space Grotesk, sans-serif', fontWeight: 600, fontSize: 13, color: 'var(--ink)',
          }}>{Math.round(clamped)}%</span>)}
        </div>
      )}
      <div style={{ position: 'relative', height, background: 'var(--paper-2)', borderRadius: height/2, overflow: 'hidden' }}>
        <div style={{
          width: clamped + '%', height: '100%',
          background: 'var(--accent)', borderRadius: height/2,
          transition: 'width 420ms cubic-bezier(.2,.7,.2,1)',
        }}/>
      </div>
    </div>
  );
}

// ─── Divider rule ────────────────────────────────────────
function Rule({ dashed = false, style = {} }) {
  return <div style={{
    height: 1, width: '100%',
    background: dashed ? 'transparent' : 'var(--line)',
    borderTop: dashed ? '1px dashed var(--line)' : 'none',
    ...style,
  }}/>;
}

// ─── Fine frame corner marks (editorial) ─────────────────
function CornerMarks({ pad = 10, c, len = 12, w = 1 }) {
  const col = c || 'var(--ink-3)';
  const s = { position: 'absolute', width: len, height: len };
  return (<>
    <div style={{ ...s, top: pad, left: pad, borderTop: `${w}px solid ${col}`, borderLeft: `${w}px solid ${col}` }}/>
    <div style={{ ...s, top: pad, right: pad, borderTop: `${w}px solid ${col}`, borderRight: `${w}px solid ${col}` }}/>
    <div style={{ ...s, bottom: pad, left: pad, borderBottom: `${w}px solid ${col}`, borderLeft: `${w}px solid ${col}` }}/>
    <div style={{ ...s, bottom: pad, right: pad, borderBottom: `${w}px solid ${col}`, borderRight: `${w}px solid ${col}` }}/>
  </>);
}

// ─── Tab bar (bottom nav) ────────────────────────────────
function TabBar({ current, go }) {
  const tabs = [
    { k: 'home', label: 'Home', icon: I.home },
    { k: 'explore', label: 'Explore', icon: I.compass },
    { k: 'journal', label: 'Journal', icon: I.book },
    { k: 'badges', label: 'Badges', icon: I.badge },
    { k: 'profile', label: 'You', icon: I.user },
  ];
  return (
    <div style={{
      position: 'absolute', bottom: 0, left: 0, right: 0, zIndex: 40,
      paddingBottom: 22, paddingTop: 10,
      background: 'linear-gradient(to top, var(--bg) 60%, transparent)',
      display: 'flex', justifyContent: 'space-around',
      borderTop: '1px solid var(--line)',
    }}>
      {tabs.map(t => {
        const active = current === t.k;
        return (
          <button key={t.k} onClick={() => go(t.k)} style={{
            background: 'none', border: 'none', cursor: 'pointer', padding: 6,
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 4,
            color: active ? 'var(--accent)' : 'var(--ink-3)',
          }}>
            {t.icon(active ? 'var(--accent)' : 'var(--ink-3)')}
            <span style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.12em', textTransform: 'uppercase' }}>{t.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ─── Section title with mono eyebrow ─────────────────────
function SectionHead({ eyebrow, title, meta }) {
  return (
    <div style={{ padding: '0 22px', marginTop: 28, marginBottom: 14 }}>
      {eyebrow && <Caps s={10} style={{ display: 'block', marginBottom: 8, color: 'var(--accent)' }}>{eyebrow}</Caps>}
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 12 }}>
        <h2 style={{
          margin: 0, fontFamily: 'Space Grotesk, sans-serif',
          fontWeight: 700, fontSize: 26,
          lineHeight: 1.05, color: 'var(--ink)', letterSpacing: '-0.02em',
        }}>{title}</h2>
        {meta && <Caps s={10}>{meta}</Caps>}
      </div>
    </div>
  );
}

// ─── Chip ────────────────────────────────────────────────
function Chip({ children, active = false, onClick, icon }) {
  return (
    <button onClick={onClick} style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: '7px 13px', border: `1px solid ${active ? 'var(--ink)' : 'var(--line)'}`,
      borderRadius: 100, background: active ? 'var(--ink)' : 'transparent',
      color: active ? 'var(--bg)' : 'var(--ink-2)', cursor: 'pointer',
      fontFamily: 'DM Sans, sans-serif', fontSize: 12, fontWeight: 600,
      letterSpacing: '-0.01em', whiteSpace: 'nowrap',
    }}>{icon}{children}</button>
  );
}

// ─── Metric block (num + caps label) ────────────────────
function Metric({ n, l, align = 'left' }) {
  return (
    <div style={{ textAlign: align }}>
      <div style={{
        fontFamily: 'Space Grotesk, sans-serif',
        fontWeight: 600, fontSize: 26,
        lineHeight: 1, color: 'var(--ink)', letterSpacing: '-0.03em',
      }}>{n}</div>
      <Caps s={9} style={{ display: 'block', marginTop: 6 }}>{l}</Caps>
    </div>
  );
}

// ─── Textured paper overlay ─────────────────────────────
function PaperTexture({ opacity = 0.06 }) {
  return (
    <svg style={{ position: 'absolute', inset: 0, pointerEvents: 'none', opacity, mixBlendMode: 'multiply' }} width="100%" height="100%">
      <filter id="paper">
        <feTurbulence baseFrequency="0.9" numOctaves="2" seed="5"/>
        <feColorMatrix values="0 0 0 0 0.1  0 0 0 0 0.08  0 0 0 0 0.06  0 0 0 0.5 0"/>
      </filter>
      <rect width="100%" height="100%" filter="url(#paper)"/>
    </svg>
  );
}

// ─── Reading List (shared, session 29) ──────────────────────────────────
// Self-contained: fetches and manages its own state, so it can be dropped
// into any screen (Saved, Journal) without those screens needing to share
// state. Per Jay's direction (session 29): shown in both places.
function ReadingListSection() {
  const [reading, setReading] = React.useState([]);
  const [parkIndex, setParkIndex] = React.useState([]);
  const [rTitle, setRTitle] = React.useState('');
  const [rAuthor, setRAuthor] = React.useState('');
  const [rPark, setRPark] = React.useState('');
  const [rSaving, setRSaving] = React.useState(false);
  const [loaded, setLoaded] = React.useState(false);

  const load = React.useCallback(async () => {
    const [rl, idx] = await Promise.all([window.PH.listReadingList(), window.PH.getParkIndex()]);
    setReading(rl); setParkIndex(idx);
    setLoaded(true);
  }, []);
  React.useEffect(() => { load(); }, [load]);

  const byd = Object.fromEntries(parkIndex.map(p => [p.slug, p]));
  const addBook = async () => {
    if (!rTitle.trim()) return;
    setRSaving(true);
    try {
      await window.PH.addReadingItem({ title: rTitle.trim(), author: rAuthor.trim() || null, park_slug: rPark || null });
      setRTitle(''); setRAuthor('');
      setReading(await window.PH.listReadingList());
    } finally { setRSaving(false); }
  };
  const setStatus = async (id, status) => {
    await window.PH.updateReadingItem(id, { status });
    setReading(prev => prev.map(b => b.id === id ? { ...b, status } : b));
  };
  const remove = async (id) => {
    await window.PH.removeReadingItem(id);
    setReading(prev => prev.filter(b => b.id !== id));
  };

  if (!loaded) return null;

  return (
    <div>
      <div style={{ border: '1px solid var(--line)', borderRadius: 3, padding: 16, background: 'var(--paper)', marginBottom: 14 }}>
        <input value={rTitle} onChange={e => setRTitle(e.target.value)} placeholder="Book title" style={{ width: '100%', padding: '10px 12px', border: '1px solid var(--line)', borderRadius: 2, fontFamily: 'DM Sans, sans-serif', fontSize: 14, marginBottom: 8 }}/>
        <div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
          <input value={rAuthor} onChange={e => setRAuthor(e.target.value)} placeholder="Author (optional)" style={{ flex: 1, padding: '10px 12px', border: '1px solid var(--line)', borderRadius: 2, fontFamily: 'DM Sans, sans-serif', fontSize: 13 }}/>
          <select value={rPark} onChange={e => setRPark(e.target.value)} style={{ flex: 1, padding: '10px 12px', border: '1px solid var(--line)', borderRadius: 2, fontFamily: 'DM Sans, sans-serif', fontSize: 13 }}>
            <option value="">No park (general)</option>
            {parkIndex.map(p => <option key={p.slug} value={p.slug}>{p.name}</option>)}
          </select>
        </div>
        <button disabled={rSaving || !rTitle.trim()} onClick={addBook} style={{ padding: '9px 16px', background: 'var(--ink)', color: 'var(--bg)', border: 'none', borderRadius: 100, cursor: rSaving ? 'default' : 'pointer', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', opacity: (rSaving || !rTitle.trim()) ? 0.5 : 1 }}>Add to List</button>
      </div>

      {reading.length === 0 && (
        <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontStyle: 'italic', color: 'var(--ink-3)', padding: '4px 0 20px' }}>No books yet. Add the ones you want to read before, during, or after the trip.</div>
      )}
      {reading.map(b => {
        const p = b.park_slug ? byd[b.park_slug] : null;
        return (
          <div key={b.id} style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 0', borderBottom: '1px solid var(--line)', flexWrap: 'wrap' }}>
            <div style={{ flex: 1, minWidth: 160 }}>
              <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontSize: 15, color: 'var(--ink)' }}>{b.title}</div>
              <Caps s={9} style={{ display: 'block', marginTop: 2, textTransform: 'none', letterSpacing: 0 }}>{[b.author, p ? p.name : null].filter(Boolean).join(' \u00b7 ')}</Caps>
            </div>
            <div style={{ display: 'flex', gap: 6 }}>
              {['to_read', 'reading', 'finished'].map(s => (
                <button key={s} onClick={() => setStatus(b.id, s)} style={{
                  padding: '5px 10px', borderRadius: 100, border: '1px solid ' + (b.status === s ? 'var(--ink)' : 'var(--line)'),
                  background: b.status === s ? 'var(--ink)' : 'transparent', color: b.status === s ? 'var(--bg)' : 'var(--ink-3)',
                  fontFamily: 'JetBrains Mono, monospace', fontSize: 9, letterSpacing: '0.06em', textTransform: 'uppercase', cursor: 'pointer',
                }}>{s === 'to_read' ? 'To Read' : s === 'reading' ? 'Reading' : 'Finished'}</button>
              ))}
            </div>
            <button onClick={() => remove(b.id)} style={{ border: 'none', background: 'none', cursor: 'pointer', color: 'var(--ink-3)' }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
            </button>
          </div>
        );
      })}
    </div>
  );
}

/* ─── PassportMap — shared visited-parks map (spec §2.3). Self-contained:
   fetches its own map asset + visits, same independent-instance pattern as
   ReadingListSection. mode="card" = Home's compact tappable glance;
   mode="full" = the Passport screen's full-bleed picture. ─── */
function PassportMap({ mode = 'card', onOpen }) {
  const [loading, setLoading] = React.useState(true);
  const [asset, setAsset] = React.useState(null);
  const [visited, setVisited] = React.useState(new Set());
  const [failed, setFailed] = React.useState(false);

  React.useEffect(() => {
    (async () => {
      try {
        const [a, visits] = await Promise.all([window.PH.getMapAsset(), window.PH.listVisits()]);
        setAsset(a);
        setVisited(new Set(visits.map(v => v.park_slug)));
      } catch (e) {
        setFailed(true);
      } finally { setLoading(false); }
    })();
  }, []);

  const count = visited.size;

  if (loading) {
    return (
      <div style={{ height: mode === 'card' ? 200 : 260, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--ink-3)', fontFamily: 'JetBrains Mono, monospace', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase' }}>Loading map…</div>
    );
  }

  // Graceful fallback: never a blank box, even if the fetch failed.
  if (failed || !asset) {
    return (
      <div style={{ position: 'relative', borderRadius: 4, overflow: 'hidden', height: mode === 'card' ? 200 : 260, background: 'var(--ink)', display: 'flex', alignItems: 'flex-end', padding: 18 }}>
        <CornerMarks c="rgba(var(--bg-rgb),0.5)" pad={12} len={14}/>
        <div style={{ color: 'var(--bg)' }}>
          <Caps s={9} c="rgba(var(--bg-rgb),0.7)">Your Passport</Caps>
          <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontSize: 30, lineHeight: 1, marginTop: 4 }}>
            {count === 0 ? "No parks stamped yet." : `${count} park${count === 1 ? '' : 's'} collected.`}
          </div>
        </div>
      </div>
    );
  }

  const svg = (
    <svg viewBox={asset.viewBox} style={{ width: '100%', height: '100%', display: 'block' }}>
      <rect x="0" y="0" width="975" height="610" fill="var(--paper-2)" opacity="0.5"/>
      {asset.pins.map(p => {
        const isVisited = visited.has(p.slug);
        if (isVisited) {
          return (
            <g key={p.slug}>
              <circle cx={p.x} cy={p.y} r="7" fill="none" stroke="var(--accent)" strokeWidth="1.6"/>
              <circle cx={p.x} cy={p.y} r="3.2" fill="var(--accent)"/>
            </g>
          );
        }
        return <circle key={p.slug} cx={p.x} cy={p.y} r="3" fill="none" stroke="var(--ink-3)" strokeWidth="1" opacity="0.55"/>;
      })}
    </svg>
  );

  if (mode === 'full') {
    return (
      <div style={{ padding: '0 22px' }}>
        <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 14 }}>
          <div>
            <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontWeight: 700, fontSize: 44, lineHeight: 1, color: 'var(--ink)' }}>{count} <span style={{ fontSize: 24, color: 'var(--ink-3)' }}>/ 63</span></div>
            <Caps s={9} style={{ display: 'block', marginTop: 4 }}>Parks stamped</Caps>
          </div>
        </div>
        <div style={{ position: 'relative', borderRadius: 4, overflow: 'hidden', background: 'var(--paper)', border: '1px solid var(--line)', aspectRatio: '975/610' }}>
          {svg}
        </div>
        <div style={{ marginTop: 14 }}>
          <ProgressBar pct={Math.round(count / 63 * 100)} label={`${count} of 63 stamped`} right={`${Math.round(count / 63 * 100)}%`} showPct={false} height={6}/>
        </div>
      </div>
    );
  }

  // mode === 'card'
  return (
    <button onClick={onOpen} style={{ width: '100%', padding: 0, border: 'none', cursor: 'pointer', textAlign: 'left', position: 'relative', borderRadius: 4, overflow: 'hidden', height: 200, background: 'var(--paper-2)' }}>
      {svg}
      <div style={{ position: 'absolute', inset: 0, background: 'linear-gradient(to top, rgba(var(--ink-rgb),0.6), transparent 55%)' }}/>
      <div style={{ position: 'absolute', left: 18, bottom: 16, color: 'var(--bg)' }}>
        <Caps s={9} c="rgba(var(--bg-rgb),0.75)">Your Passport</Caps>
        <div style={{ fontFamily: 'Space Grotesk, sans-serif', fontSize: 26, lineHeight: 1.05, marginTop: 4 }}>
          {count === 0 ? "No parks stamped yet." : `${count} of 63 stamped.`}
        </div>
      </div>
    </button>
  );
}

Object.assign(window, { I, Caps, Rule, CornerMarks, TabBar, SectionHead, Chip, Metric, ProgressBar, PaperTexture, ReadingListSection, PassportMap });
