// data.jsx — Episode catalog & topic taxonomy + per-episode thumbnail SVGs
// Pencil + watercolor register: graphite ink + at most one wash per thumbnail.

// Data is loaded from data/episodes.json + data/taxonomy.json.

// Each thumbnail is a 96-square SVG. Two-tone ceiling: graphite ink + one wash.
const WASH = {
  pine:      "rgba(93,122,90,0.42)",
  sandstone: "rgba(168,127,58,0.34)",
  willow:    "rgba(201,182,110,0.46)",
  river:     "rgba(74,95,116,0.38)",
};
const INK = "#1f2a35";
const SHADOW = "#6b5d44";

// Deterministic per-episode marks. `seed` is a small int from the slug;
// callers without a seed get the un-rotated, un-decorated base drawing so
// the design language stays cohesive within a series.
const MARK_SLOTS = [
  { x: 10, y: 12 }, { x: 86, y: 12 }, { x: 10, y: 86 }, { x: 86, y: 86 },
  { x: 48,  y: 9 }, { x: 9,  y: 48 }, { x: 87, y: 48 }, { x: 48, y: 88 },
];
const MARK_SHAPES = [
  (k, x, y) => <circle key={k} cx={x} cy={y} r="1.1" fill={INK} opacity="0.55" />,
  (k, x, y) => <line key={k} x1={x-2.5} y1={y} x2={x+2.5} y2={y} stroke={INK} strokeWidth="0.7" opacity="0.5" />,
  (k, x, y) => <g key={k} stroke={INK} strokeWidth="0.6" opacity="0.55">
                 <line x1={x-2} y1={y} x2={x+2} y2={y} />
                 <line x1={x} y1={y-2} x2={x} y2={y+2} />
               </g>,
  (k, x, y) => <g key={k} stroke={INK} strokeWidth="0.5" opacity="0.5">
                 <line x1={x-2} y1={y-2} x2={x+2} y2={y+2} />
                 <line x1={x-2} y1={y+2} x2={x+2} y2={y-2} />
                 <line x1={x-2.5} y1={y} x2={x+2.5} y2={y} />
               </g>,
  (k, x, y) => <circle key={k} cx={x} cy={y} r="1.8" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.5" />,
];

function Thumb({ glyph, wash, seed = 0 }) {
  const w = WASH[wash] || WASH.pine;
  // Deterministic micro-variation from the seed.
  const rot   = ((seed % 11) - 5) * 0.7;            // ±3.5° glyph tilt
  const hatchRot = 30 + ((seed >> 3) % 13);          // 30–42° hatch angle
  const markCount  = 1 + ((seed >> 5) % 3);          // 1–3 accent marks
  const slotStart  = (seed >> 7) % MARK_SLOTS.length;
  const shapeIdx   = (seed >> 4) % MARK_SHAPES.length;
  const marks = Array.from({ length: markCount }, (_, i) => {
    const slot = MARK_SLOTS[(slotStart + i * 3) % MARK_SLOTS.length];
    return MARK_SHAPES[(shapeIdx + i) % MARK_SHAPES.length](i, slot.x, slot.y);
  });

  // common page background — paper tone & a small frame line
  const Frame = () => (
    <rect x="0" y="0" width="96" height="96" fill="#ebe1cc" />
  );
  // pencil cross-hatch shading helper
  const HATCH = (
    <defs>
      <pattern id={`h-${glyph}-${wash}`} width="4" height="4" patternUnits="userSpaceOnUse" patternTransform={`rotate(${hatchRot})`}>
        <line x1="0" y1="0" x2="0" y2="4" stroke={INK} strokeWidth="0.5" opacity="0.35" />
      </pattern>
    </defs>
  );
  const G = {
    // Roman arch
    arch: (<g>
      <path d="M14 78 L14 50 Q14 26 48 26 Q82 26 82 50 L82 78 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      <path d="M14 78 L82 78" stroke={INK} strokeWidth="1.2" />
      <path d="M14 50 Q14 26 48 26 Q82 26 82 50"
            fill="none" stroke={INK} strokeWidth="1.4" />
      <path d="M22 50 L22 78 M74 50 L74 78" stroke={INK} strokeWidth="0.6" opacity="0.6" />
      <path d="M30 64 q4 -3 8 0 t8 0 t8 0 t8 0" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.4" />
    </g>),
    // Pneumatic tube — a brass pipe & valve
    tube: (<g>
      <path d="M10 60 L74 60 L74 46 L86 46 L86 78 L74 78 L74 64 L10 64 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      <circle cx="22" cy="62" r="3" fill="none" stroke={INK} strokeWidth="0.8" />
      <circle cx="42" cy="62" r="3" fill="none" stroke={INK} strokeWidth="0.8" />
      <circle cx="62" cy="62" r="3" fill="none" stroke={INK} strokeWidth="0.8" />
      <path d="M80 30 L80 46 M76 34 L84 34" stroke={INK} strokeWidth="1" />
      <text x="14" y="52" fontFamily="serif" fontSize="7" fill={SHADOW} fontStyle="italic">poste</text>
    </g>),
    // Bridle path on a hill
    path: (<g>
      <path d="M0 80 Q24 60 40 64 T96 36 L96 96 L0 96 Z" fill={w} />
      <path d="M0 80 Q24 60 40 64 T96 36" fill="none" stroke={INK} strokeWidth="1.1" />
      <path d="M6 84 Q26 66 42 70 T96 42" fill="none" stroke={INK} strokeWidth="0.6" strokeDasharray="2 3" opacity="0.7" />
      <path d="M28 56 l3 -8 l3 8 z" fill={INK} opacity="0.6" />
      <path d="M62 40 l3 -10 l3 10 z" fill={INK} opacity="0.6" />
    </g>),
    // Voyager record
    disc: (<g>
      <circle cx="48" cy="48" r="32" fill={w} stroke={INK} strokeWidth="1.1" />
      <circle cx="48" cy="48" r="26" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.7" />
      <circle cx="48" cy="48" r="20" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.6" />
      <circle cx="48" cy="48" r="14" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <circle cx="48" cy="48" r="3"  fill={INK} />
      <line x1="48" y1="14" x2="48" y2="22" stroke={INK} strokeWidth="0.8" />
    </g>),
    // Venetian ship
    ship: (<g>
      <path d="M14 70 Q48 84 82 70 L78 78 Q48 88 18 78 Z" fill={w} stroke={INK} strokeWidth="1.1" />
      <line x1="48" y1="20" x2="48" y2="70" stroke={INK} strokeWidth="1.1" />
      <path d="M48 26 L70 50 L48 50 Z" fill="none" stroke={INK} strokeWidth="1" />
      <path d="M48 32 L28 56 L48 56 Z" fill="none" stroke={INK} strokeWidth="1" />
      <path d="M30 70 L66 70" stroke={INK} strokeWidth="0.5" opacity="0.5" />
    </g>),
    // Cathedral spire
    spire: (<g>
      <path d="M44 18 L52 18 L56 36 L40 36 Z" fill={w} stroke={INK} strokeWidth="1" />
      <rect x="36" y="36" width="24" height="42" fill={w} stroke={INK} strokeWidth="1" />
      <path d="M48 8 L48 18" stroke={INK} strokeWidth="0.8" />
      <rect x="44" y="46" width="8" height="14" fill={INK} opacity="0.65" />
      <line x1="20" y1="78" x2="76" y2="78" stroke={INK} strokeWidth="1" />
      <line x1="36" y1="50" x2="60" y2="50" stroke={INK} strokeWidth="0.4" opacity="0.5" />
      <line x1="36" y1="62" x2="60" y2="62" stroke={INK} strokeWidth="0.4" opacity="0.5" />
    </g>),
    // Octopus
    octopus: (<g>
      <path d="M30 32 Q48 16 66 32 Q70 50 60 56 Q60 70 50 78 Q40 70 40 60 Q44 56 38 50 Q26 44 30 32 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      <path d="M36 56 Q28 64 22 76 M44 60 Q42 72 36 82 M54 60 Q56 74 60 82 M60 56 Q70 62 76 74"
            fill="none" stroke={INK} strokeWidth="0.9" strokeLinecap="round" />
      <circle cx="42" cy="36" r="1.6" fill={INK} />
      <circle cx="54" cy="36" r="1.6" fill={INK} />
    </g>),
    // Chimney with smoke
    chimney: (<g>
      <rect x="24" y="46" width="14" height="32" fill={w} stroke={INK} strokeWidth="1" />
      <rect x="20" y="42" width="22" height="6"  fill={w} stroke={INK} strokeWidth="1" />
      <rect x="44" y="62" width="36" height="16" fill={w} stroke={INK} strokeWidth="1" opacity="0.6" />
      <path d="M30 42 q-6 -8 0 -16 t6 -16" fill="none" stroke={INK} strokeWidth="0.9" opacity="0.7" />
      <path d="M34 30 q-4 -6 2 -12" fill="none" stroke={INK} strokeWidth="0.6" opacity="0.5" />
    </g>),
    // Pendulum clock
    clock: (<g>
      <rect x="32" y="14" width="32" height="46" rx="2" fill={w} stroke={INK} strokeWidth="1.1" />
      <circle cx="48" cy="32" r="10" fill="none" stroke={INK} strokeWidth="1" />
      <line x1="48" y1="32" x2="48" y2="24" stroke={INK} strokeWidth="1" />
      <line x1="48" y1="32" x2="54" y2="34" stroke={INK} strokeWidth="1" />
      <line x1="48" y1="42" x2="48" y2="76" stroke={INK} strokeWidth="0.8" />
      <circle cx="48" cy="78" r="5" fill={INK} />
    </g>),
    // Lichen patches
    lichen: (<g>
      <path d="M16 60 Q14 46 28 44 Q42 36 50 48 Q66 42 70 56 Q84 62 76 76 Q60 84 46 76 Q30 80 22 72 Q10 70 16 60 Z"
            fill={w} stroke={INK} strokeWidth="1" />
      <circle cx="34" cy="58" r="2" fill={INK} opacity="0.5" />
      <circle cx="50" cy="62" r="3" fill={INK} opacity="0.5" />
      <circle cx="62" cy="58" r="2" fill={INK} opacity="0.5" />
      <circle cx="44" cy="50" r="1.4" fill={INK} opacity="0.4" />
      <circle cx="58" cy="70" r="1.6" fill={INK} opacity="0.4" />
    </g>),
    // Cuneiform tablet
    tablet: (<g>
      <path d="M20 22 Q22 18 28 18 L66 18 Q72 18 74 22 L72 76 Q70 80 64 80 L30 80 Q24 80 22 76 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      {[...Array(5)].map((_, i) => (
        <g key={i} transform={`translate(28 ${28 + i*9})`}>
          <path d="M0 2 l4 -2 l4 2 l-4 2 z" fill={INK} opacity="0.7" />
          <path d="M14 2 l4 -2 l4 2 l-4 2 z" fill={INK} opacity="0.7" />
          <path d="M28 2 l4 -2 l4 2 l-4 2 z" fill={INK} opacity="0.7" />
        </g>
      ))}
    </g>),
    // Fern frond
    fern: (<g>
      <path d="M48 84 Q40 60 30 36 Q24 22 16 14" fill="none" stroke={INK} strokeWidth="1.2" />
      {[...Array(7)].map((_, i) => {
        const t = i / 6;
        const x = 48 - 32*t;
        const y = 84 - 70*t;
        return (
          <g key={i} transform={`translate(${x} ${y}) rotate(${-30 - t*20})`}>
            <path d={`M0 0 q${10 - t*4} -${4 + t*3} ${18 - t*6} 0`} fill={w} stroke={INK} strokeWidth="0.8" />
            <path d={`M0 0 q-${10 - t*4} -${4 + t*3} -${18 - t*6} 0`} fill={w} stroke={INK} strokeWidth="0.8" />
          </g>
        );
      })}
    </g>),
    // Tide wave
    wave: (<g>
      <path d="M0 60 Q12 48 24 60 T48 60 T72 60 T96 60 L96 96 L0 96 Z" fill={w} />
      <path d="M0 60 Q12 48 24 60 T48 60 T72 60 T96 60" fill="none" stroke={INK} strokeWidth="1" />
      <path d="M0 70 Q12 60 24 70 T48 70 T72 70 T96 70" fill="none" stroke={INK} strokeWidth="0.6" opacity="0.7" />
      <path d="M0 80 Q12 72 24 80 T48 80 T72 80 T96 80" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <circle cx="20" cy="32" r="6" fill="none" stroke={INK} strokeWidth="0.8" />
    </g>),
    // Sun (eclipse)
    sun: (<g>
      <circle cx="48" cy="48" r="22" fill={w} stroke={INK} strokeWidth="1.1" />
      <circle cx="42" cy="44" r="20" fill={INK} />
      {[...Array(12)].map((_, i) => {
        const a = i * 30 * Math.PI / 180;
        const r1 = 26, r2 = 32;
        return <line key={i} x1={48 + Math.cos(a)*r1} y1={48 + Math.sin(a)*r1}
                            x2={48 + Math.cos(a)*r2} y2={48 + Math.sin(a)*r2}
                            stroke={INK} strokeWidth="0.9" opacity="0.7" />;
      })}
    </g>),
    // Loaf of bread
    loaf: (<g>
      <path d="M14 56 Q14 38 30 36 Q42 28 56 36 Q78 36 80 56 Q82 70 70 74 Q48 80 26 74 Q14 70 14 56 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      <path d="M22 50 q10 -6 22 0 t22 0" fill="none" stroke={INK} strokeWidth="0.6" opacity="0.6" />
      <path d="M22 60 q10 -6 22 0 t22 0" fill="none" stroke={INK} strokeWidth="0.6" opacity="0.5" />
      <line x1="20" y1="78" x2="76" y2="78" stroke={INK} strokeWidth="0.5" opacity="0.4" />
    </g>),
    // Ice / frost
    ice: (<g>
      <rect x="6" y="58" width="84" height="22" fill={w} stroke={INK} strokeWidth="1" />
      <path d="M6 58 L20 58 L26 50 L40 58 L52 50 L66 58 L78 50 L90 58" fill="none" stroke={INK} strokeWidth="1" />
      <line x1="22" y1="62" x2="22" y2="76" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <line x1="42" y1="62" x2="42" y2="76" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <line x1="62" y1="62" x2="62" y2="76" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <line x1="78" y1="62" x2="78" y2="76" stroke={INK} strokeWidth="0.5" opacity="0.5" />
      <g transform="translate(72 26)">
        <line x1="-8" y1="0" x2="8" y2="0" stroke={INK} strokeWidth="0.8" />
        <line x1="0" y1="-8" x2="0" y2="8" stroke={INK} strokeWidth="0.8" />
        <line x1="-6" y1="-6" x2="6" y2="6" stroke={INK} strokeWidth="0.8" />
        <line x1="-6" y1="6" x2="6" y2="-6" stroke={INK} strokeWidth="0.8" />
      </g>
    </g>),
    // Bell
    bell: (<g>
      <path d="M28 28 L68 28 L68 36 Q78 50 78 70 L18 70 Q18 50 28 36 Z"
            fill={w} stroke={INK} strokeWidth="1.1" />
      <line x1="18" y1="70" x2="78" y2="70" stroke={INK} strokeWidth="1.4" />
      <rect x="44" y="20" width="8" height="10" fill={w} stroke={INK} strokeWidth="1" />
      <circle cx="48" cy="78" r="4" fill={INK} />
      <line x1="48" y1="70" x2="48" y2="74" stroke={INK} strokeWidth="0.8" />
      <path d="M30 56 q18 -6 36 0" fill="none" stroke={INK} strokeWidth="0.5" opacity="0.5" />
    </g>),
    // Open book with margin marks
    book: (<g>
      <path d="M14 24 L46 28 L46 78 L14 74 Z" fill={w} stroke={INK} strokeWidth="1.1" />
      <path d="M82 24 L50 28 L50 78 L82 74 Z" fill={w} stroke={INK} strokeWidth="1.1" />
      <line x1="48" y1="28" x2="48" y2="78" stroke={INK} strokeWidth="0.8" />
      {[...Array(5)].map((_, i) => (
        <line key={i} x1="20" y1={36 + i*8} x2="42" y2={36 + i*8 + 1} stroke={INK} strokeWidth="0.4" opacity="0.5" />
      ))}
      {[...Array(5)].map((_, i) => (
        <line key={i} x1="54" y1={36 + i*8 + 1} x2="76" y2={36 + i*8} stroke={INK} strokeWidth="0.4" opacity="0.5" />
      ))}
      <path d="M40 50 q-2 -3 0 -6" fill="none" stroke={SHADOW} strokeWidth="0.8" />
      <path d="M40 60 q-2 -3 0 -6" fill="none" stroke={SHADOW} strokeWidth="0.8" />
    </g>),
  };
  return (
    <svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
      <Frame />
      {HATCH}
      <g transform={`rotate(${rot} 48 48)`}>
        {G[glyph] || G.book}
      </g>
      {marks}
    </svg>
  );
}

// Loader: fetches real episodes.json + taxonomy.json. Returns a Promise.
async function loadCatalog() {
  const [eps, tax] = await Promise.all([
    fetch("data/episodes.json").then(r => r.json()),
    fetch("data/taxonomy.json").then(r => r.json()),
  ]);
  const topicMap = Object.fromEntries(tax.topics.map(t => [t.id, t]));
  const seriesMap = {};
  for (const t of tax.topics) for (const s of t.series) {
    seriesMap[t.id + "/" + s.id] = { ...s, topic: t.id, topic_label: t.label };
  }
  eps.forEach(e => {
    e.topic_label  = e.topic_label  || topicMap[e.topic]?.label   || e.topic;
    e.series_label = e.series_label || seriesMap[e.topic + "/" + e.series]?.label || e.series;
  });
  eps.sort((a, b) => b.date.localeCompare(a.date) || a.slug.localeCompare(b.slug));
  eps.forEach((e, i) => { e.number = eps.length - i; });
  return { EPISODES: eps, TAXONOMY: tax, topicMap, seriesMap };
}

window.IPData = {
  FEED: "https://amongst-other-things.com/feed.xml",
  Thumb,
  loadCatalog,
};
