// views.jsx — AHome, ASearch, ADetail (+ tabs), ACollection.

// ─────────────────────────────────────────────────────────────
// Home — Field Guide
// ─────────────────────────────────────────────────────────────
function AHome({ species, facets, onOpen, onSearch, onBrowseWater, onDive }) {
  const total = species.length;
  const families = React.useMemo(() => new Set(species.map(f => f.family).filter(Boolean)).size, [species]);
  const habitatGroups = React.useMemo(() => {
    const m = new Map();
    for (const f of species) {
      const key = f.water || 'Unknown';
      if (!m.has(key)) m.set(key, []);
      m.get(key).push(f);
    }
    // Order: Saltwater, Freshwater, Brackish (or whatever exists)
    const order = ['Saltwater', 'Freshwater', 'Brackish'];
    return order.filter(k => m.has(k)).map(k => [k, m.get(k)]);
  }, [species]);
  const waters = habitatGroups.length;

  // In-Season picks: just take the first 6 common species with photos.
  const featured = React.useMemo(() => {
    const withPhoto = species.filter(f => f.coverImg);
    const common = withPhoto.filter(f => f.is_common);
    const pick = (common.length >= 6 ? common : withPhoto).slice(0, 6);
    return pick;
  }, [species]);

  // Recently catalogued: just last N by taxon_id descending order — illustrative
  const recent = React.useMemo(() => {
    return [...species]
      .filter(f => f.coverImg)
      .sort((a, b) => (b.taxon_id || 0) - (a.taxon_id || 0))
      .slice(0, 8);
  }, [species]);

  return (
    <div className="ctx-screen" style={{ minHeight: '100%', paddingBottom: 40 }}>
      {/* Masthead */}
      <div className="ctx-fadeUp" style={{ padding: '14px 20px 20px' }}>
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          marginBottom: 28,
        }}>
          <Wordmark size={9.5} />
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{
              fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
              letterSpacing: '0.14em', textTransform: 'uppercase',
            }}>Vol. 01 · MMXXVI</div>
            {/* Dive In — sole entry. */}
            <button className="ctx-btn" onClick={onDive} aria-label="Dive In" style={{
              position: 'relative', width: 34, height: 34, borderRadius: 99,
              background: `radial-gradient(circle at 50% 30%, ${VI.accent}33 0%, ${VI.accent}10 60%, transparent 100%)`,
              border: `0.5px solid ${VI.accent}`,
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              boxShadow: `0 0 12px ${VI.accent}44, inset 0 0 8px ${VI.accent}22`,
              overflow: 'hidden',
            }}>
              <span style={{
                position: 'absolute', inset: 0, borderRadius: 99,
                border: `1px solid ${VI.accent}`, opacity: 0,
                animation: `dv-icon-ripple 2.4s ${VI.ease} infinite`,
              }}/>
              <span style={{
                position: 'absolute', inset: 0, borderRadius: 99,
                border: `1px solid ${VI.accent}`, opacity: 0,
                animation: `dv-icon-ripple 2.4s ${VI.ease} 1.2s infinite`,
              }}/>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none"
                stroke={VI.accent} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
                style={{ position: 'relative', zIndex: 1 }}>
                <path d="M12 4 V16"/>
                <path d="M7 11 L12 16 L17 11"/>
                <path d="M5 20 Q8 18 12 20 T19 20" opacity="0.6"/>
              </svg>
              <style>{`
                @keyframes dv-icon-ripple {
                  0%   { transform: scale(0.6); opacity: 0.8; }
                  100% { transform: scale(1.6); opacity: 0; }
                }
              `}</style>
            </button>
          </div>
        </div>

        <div style={{
          fontFamily: VI.fontMono, fontSize: 9, color: VI.accent,
          letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 12,
        }}>The Field Guide</div>
        <h1 style={{
          fontFamily: VI.fontDisp, fontWeight: 300, fontSize: 44,
          letterSpacing: '-0.02em', lineHeight: 1.0, margin: 0,
          color: VI.text,
        }}>Every catch<br/><em style={{ fontWeight: 300 }}>tells a story.</em></h1>

        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)',
          gap: 1, marginTop: 24,
          background: VI.border,
          border: `0.5px solid ${VI.border}`,
        }}>
          {[
            [String(total).padStart(3, '0'), 'SPECIES'],
            [String(families).padStart(2, '0'), 'FAMILIES'],
            [String(waters), 'WATERS'],
          ].map(([n, l]) => (
            <div key={l} style={{
              background: VI.bg, padding: '12px 10px',
            }}>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 18, fontWeight: 500,
                color: VI.text, letterSpacing: '-0.01em',
              }}>{n}</div>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 8.5, color: VI.textMute,
                letterSpacing: '0.14em', marginTop: 2,
              }}>{l}</div>
            </div>
          ))}
        </div>
      </div>

      {/* Search bar */}
      <div className="ctx-fadeUp" style={{ padding: '4px 20px 24px', animationDelay: '60ms' }}>
        <button className="ctx-btn" onClick={onSearch} style={{
          width: '100%', display: 'flex', alignItems: 'center', gap: 10,
          padding: '12px 14px', background: VI.bgCard,
          border: `0.5px solid ${VI.border}`, borderRadius: 2,
          color: VI.textDim, textAlign: 'left',
        }}>
          <span style={{ color: VI.textMute }}>{Icon.search(16)}</span>
          <span style={{
            fontFamily: VI.fontBody, fontSize: 13, color: VI.textMute, flex: 1,
          }}>Search by name, latin, family…</span>
        </button>
      </div>

      {/* PLATE I — Featured */}
      {featured.length > 0 && (
        <>
          <ASectionHd num="I" subtitle="Plate" title="Common Species" />
          <div className="ctx-fadeUp" style={{
            display: 'grid', gridTemplateColumns: '1fr 1fr',
            gap: 12, padding: '0 20px 36px', animationDelay: '100ms',
          }}>
            {featured.map((f, i) => (
              <ASpecimenCard key={f.id} fish={f} n={i + 1} onClick={() => onOpen(f)} />
            ))}
          </div>
        </>
      )}

      {/* PLATE II — Browse by water */}
      {habitatGroups.length > 0 && (
        <>
          <ASectionHd num="II" subtitle="Index" title="By Habitat" />
          <div className="ctx-fadeUp" style={{ padding: '0 20px 36px', animationDelay: '160ms' }}>
            {habitatGroups.map(([k, list], i) => (
              <button key={k} className="ctx-btn" onClick={() => onBrowseWater(k)} style={{
                width: '100%', display: 'flex', alignItems: 'center',
                padding: '14px 0', borderTop: i === 0 ? `0.5px solid ${VI.border}` : 'none',
                borderBottom: `0.5px solid ${VI.border}`,
                textAlign: 'left',
              }}>
                <div style={{
                  width: 4, height: 32, marginRight: 14,
                  background: `linear-gradient(180deg, ${list[0].gradient[0]}, ${list[0].gradient[1]})`,
                }}/>
                <div style={{ flex: 1 }}>
                  <div style={{
                    fontFamily: VI.fontDisp, fontWeight: 400, fontSize: 18,
                    color: VI.text, lineHeight: 1.1,
                  }}>{k}</div>
                  <div style={{
                    fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
                    letterSpacing: '0.1em', marginTop: 4,
                  }}>{list.length} SPECIES · {[...new Set(list.map(f=>f.family).filter(Boolean))].length} FAMILIES</div>
                </div>
                <span style={{ color: VI.textMute }}>{Icon.chevronR(16)}</span>
              </button>
            ))}
          </div>
        </>
      )}

      {/* PLATE III — Recently catalogued */}
      {recent.length > 0 && (
        <>
          <ASectionHd num="III" subtitle="Plate" title="Recently Catalogued" />
          <div className="ctx-fadeUp" style={{
            display: 'flex', gap: 12, padding: '0 20px 32px', overflowX: 'auto',
            animationDelay: '220ms',
          }}>
            {recent.map((f, i) => (
              <div key={f.id} style={{ flex: '0 0 132px' }}>
                <ASpecimenCard fish={f} n={i + 21} onClick={() => onOpen(f)} />
              </div>
            ))}
          </div>
        </>
      )}

      {/* Colophon */}
      <div style={{ padding: '32px 20px 20px', textAlign: 'center' }}>
        <div style={{
          fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
          fontSize: 14, color: VI.textDim, marginBottom: 8,
        }}>"A world where every angler knows<br/>the name of every fish."</div>
        <div style={{
          fontFamily: VI.fontMono, fontSize: 8, color: VI.textFaint,
          letterSpacing: '0.18em', textTransform: 'uppercase',
        }}>School · Catches · Field Guide · Vol. 01</div>
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Search & Filter — Field Guide
// ─────────────────────────────────────────────────────────────
function ASearch({ species, facets, onClose, onOpen, initialWater }) {
  const [q, setQ] = React.useState('');
  const [active, setActive] = React.useState({
    Water: initialWater ? [initialWater] : [],
    Method: [],
    Region: [],
    Family: [],
  });
  const [commonOnly, setCommonOnly] = React.useState(false);
  const inputRef = React.useRef(null);
  React.useEffect(() => { inputRef.current?.focus(); }, []);

  const toggle = (cat, val) => setActive(a => ({
    ...a,
    [cat]: a[cat].includes(val) ? a[cat].filter(v => v !== val) : [...a[cat], val],
  }));

  const filtered = React.useMemo(() => {
    const Q = q.trim().toLowerCase();
    return species.filter(f => {
      if (Q) {
        const hay = [
          f.name, f.latin, f.family,
          ...(f.aliases || []), ...(f.en_aliases || []), ...(f.zh_aliases || []),
        ].filter(Boolean).join(' ').toLowerCase();
        if (!hay.includes(Q)) return false;
      }
      if (active.Water.length  && !active.Water.includes(f.water)) return false;
      if (active.Method.length && !f.methods.some(m => active.Method.includes(m))) return false;
      if (active.Region.length && !f.regions.some(r => active.Region.includes(r))) return false;
      if (active.Family.length && !active.Family.includes(f.family)) return false;
      if (commonOnly && !f.is_common) return false;
      return true;
    });
  }, [species, q, active, commonOnly]);

  const total = active.Water.length + active.Method.length + active.Region.length + active.Family.length + (commonOnly ? 1 : 0);
  const clearAll = () => { setActive({ Water: [], Method: [], Region: [], Family: [] }); setCommonOnly(false); };

  // Build chip list. Method/Region values shown by raw key but labeled.
  const chipGroups = [
    ['Water',  facets.Water.map(([k]) => [k, k])],
    ['Method', facets.Method.map(([k]) => [k, METHOD_LABEL[k] || k])],
    ['Region', facets.Region.map(([k]) => [k, REGION_LABEL[k] || k])],
  ];

  return (
    <div className="ctx-screen" style={{ minHeight: '100%', display: 'flex', flexDirection: 'column' }}>
      <div style={{
        padding: '12px 16px 14px',
        borderBottom: `0.5px solid ${VI.border}`,
        background: VI.bg, position: 'sticky', top: 0, zIndex: 5,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12 }}>
          <button className="ctx-btn" onClick={onClose} style={{ color: VI.textDim }} aria-label="Close search">
            {Icon.close(20)}
          </button>
          <div style={{
            flex: 1, display: 'flex', alignItems: 'center', gap: 8,
            padding: '9px 12px', background: VI.bgCard,
            border: `0.5px solid ${VI.border}`, borderRadius: 2,
          }}>
            <span style={{ color: VI.textMute }}>{Icon.search(15)}</span>
            <input
              ref={inputRef}
              value={q}
              onChange={e => setQ(e.target.value)}
              placeholder={`Search ${species.length} species…`}
              style={{
                flex: 1, background: 'transparent', border: 0, outline: 0,
                fontFamily: VI.fontBody, fontSize: 13, color: VI.text,
              }}
            />
            {q && (
              <button className="ctx-btn" onClick={() => setQ('')} style={{ color: VI.textMute }} aria-label="Clear">
                {Icon.close(14)}
              </button>
            )}
          </div>
        </div>

        {/* Chip groups */}
        <div style={{
          display: 'flex', gap: 6, overflowX: 'auto',
          margin: '0 -16px', padding: '0 16px',
        }}>
          <button className="ctx-btn" onClick={() => setCommonOnly(c => !c)} style={{
            flex: '0 0 auto', padding: '6px 10px', borderRadius: 999,
            fontFamily: VI.fontMono, fontSize: 9.5, letterSpacing: '0.06em',
            textTransform: 'uppercase',
            background: commonOnly ? VI.accentDim : VI.bgCard,
            color: commonOnly ? VI.accent : VI.textDim,
            border: `0.5px solid ${commonOnly ? VI.accent : VI.border}`,
          }}>Common</button>
          {chipGroups.flatMap(([cat, vals]) => vals.map(([k, label]) => {
            const on = active[cat]?.includes(k);
            return (
              <button key={cat + k} className="ctx-btn" onClick={() => toggle(cat, k)} style={{
                flex: '0 0 auto', padding: '6px 10px', borderRadius: 999,
                fontFamily: VI.fontMono, fontSize: 9.5, letterSpacing: '0.06em',
                textTransform: 'uppercase',
                background: on ? VI.accentDim : VI.bgCard,
                color: on ? VI.accent : VI.textDim,
                border: `0.5px solid ${on ? VI.accent : VI.border}`,
                transition: `all .18s ${VI.ease}`,
              }}>{label}</button>
            );
          }))}
        </div>
      </div>

      <div style={{
        padding: '14px 20px 8px',
        display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
      }}>
        <div style={{
          fontFamily: VI.fontMono, fontSize: 10, color: VI.textMute,
          letterSpacing: '0.14em', textTransform: 'uppercase',
        }}>{filtered.length} {filtered.length === 1 ? 'Result' : 'Results'}</div>
        {total > 0 && (
          <button className="ctx-btn" onClick={clearAll} style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.accent,
            letterSpacing: '0.12em', textTransform: 'uppercase',
          }}>Clear {total}</button>
        )}
      </div>

      <div style={{ flex: 1, padding: '0 20px 24px' }}>
        {filtered.map((f, i) => (
          <button key={f.id} className="ctx-btn" onClick={() => onOpen(f)} style={{
            width: '100%', display: 'flex', alignItems: 'center', gap: 12,
            padding: '12px 0', textAlign: 'left',
            borderBottom: `0.5px solid ${VI.border}`,
          }}>
            <div style={{ width: 56, flexShrink: 0 }}>
              <FishImage fish={f} height={42} radius={3}/>
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{
                fontFamily: VI.fontDisp, fontWeight: 500, fontSize: 14,
                color: VI.text, lineHeight: 1.2,
                whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
              }}>{f.name}</div>
              <div style={{
                fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
                fontSize: 11, color: VI.textDim, marginTop: 1,
                whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
              }}>{f.latin}</div>
            </div>
            <div style={{
              fontFamily: VI.fontMono, fontSize: 8.5, color: VI.textMute,
              letterSpacing: '0.08em', textAlign: 'right',
            }}>
              <div>{(f.water || '').toUpperCase()}</div>
              <div style={{ marginTop: 2, color: VI.textFaint }}>№{String(i+1).padStart(3,'0')}</div>
            </div>
          </button>
        ))}
        {filtered.length === 0 && (
          <div style={{
            padding: '40px 20px', textAlign: 'center',
            fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
            fontSize: 14, color: VI.textMute,
          }}>No specimens match your query.</div>
        )}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Detail page — strict-data variant. Loads /api/species/{id} for gallery + notes.
// Three tabs: Overview · Tactics · Similar.
// ─────────────────────────────────────────────────────────────
function ADetail({ fish: initialFish, species, onBack, onOpen }) {
  const [tab, setTab] = React.useState('overview');
  const [detail, setDetail] = React.useState(null); // { fish, images }
  const [error, setError] = React.useState(null);
  const fish = detail?.fish || initialFish;
  const images = detail?.images || [];
  const sv = useSave();
  const isSaved  = sv?.isSaved(fish.id);
  const isCaught = sv?.isCaught(fish.id);

  // Image gallery navigation (hero pager)
  const [activeImg, setActiveImg] = React.useState(0);

  React.useEffect(() => {
    let cancelled = false;
    setDetail(null);
    setError(null);
    setActiveImg(0);
    fetchSpeciesDetail(initialFish.id || initialFish.taxon_id)
      .then((d) => { if (!cancelled) setDetail(d); })
      .catch((e) => { if (!cancelled) setError(e.message); });
    return () => { cancelled = true; };
  }, [initialFish.id, initialFish.taxon_id]);

  const heroImage = images[activeImg];
  const heroSrc = heroImage ? heroImage.url : fish.coverImg;

  return (
    <div className="ctx-screen" style={{ minHeight: '100%', paddingBottom: 40 }}>
      {/* Hero */}
      <div style={{ position: 'relative' }}>
        {heroSrc ? (
          <div style={{ position: 'relative', height: 320, background: VI.bgCard, overflow: 'hidden' }}>
            <img
              src={heroSrc}
              alt={fish.name}
              style={{ width: '100%', height: '100%', objectFit: 'cover', display: 'block' }}
            />
            <div style={{
              position: 'absolute', inset: 0, pointerEvents: 'none',
              background: 'linear-gradient(180deg, rgba(8,8,10,0.45) 0%, transparent 30%, transparent 60%, rgba(8,8,10,0.55) 100%)',
            }}/>
          </div>
        ) : (
          <FishGradient fish={fish} height={320} radius={0} intensity={1.2}/>
        )}
        <div style={{
          position: 'absolute', top: 12, left: 0, right: 0,
          padding: '0 16px', display: 'flex', justifyContent: 'space-between',
        }}>
          <button className="ctx-btn" onClick={onBack} style={{
            width: 36, height: 36, borderRadius: 999,
            background: 'rgba(8,8,10,0.55)', backdropFilter: 'blur(12px)',
            display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: VI.text, border: `0.5px solid ${VI.borderHi}`,
          }} aria-label="Back">{Icon.back(18)}</button>
          <div style={{ display: 'flex', gap: 8 }}>
            {sv && (
              <>
                <ASaveButton size={36} active={isSaved} dark
                  onClick={() => sv.toggleSaved(fish.id)} icon={Icon.bookmark}
                  ariaLabel={isSaved ? 'Remove from saved' : 'Save'}/>
                <ASaveButton size={36} active={isCaught} dark
                  onClick={() => sv.toggleCaught(fish.id)} icon={Icon.hook}
                  ariaLabel={isCaught ? 'Mark as not caught' : 'Mark as caught'}/>
              </>
            )}
          </div>
        </div>
        {/* Plate label */}
        <div style={{
          position: 'absolute', bottom: 14, left: 20,
          fontFamily: VI.fontMono, fontSize: 10, color: 'rgba(255,255,255,0.92)',
          letterSpacing: '0.18em', textShadow: '0 1px 4px rgba(0,0,0,0.7)',
        }}>PLATE № {String(initialFish.taxon_id || '').slice(-3).padStart(3, '0')}{species ? ` / ${species.length}` : ''}</div>
        {/* Pager dots */}
        {images.length > 1 && (
          <div style={{
            position: 'absolute', bottom: 14, right: 20, display: 'flex', gap: 4,
          }}>
            {images.slice(0, Math.min(images.length, 8)).map((_, i) => (
              <button key={i} className="ctx-btn" onClick={() => setActiveImg(i)} aria-label={`Photo ${i+1}`} style={{
                width: i === activeImg ? 14 : 4, height: 4, borderRadius: 2, padding: 0,
                background: i === activeImg ? '#fff' : 'rgba(255,255,255,0.45)',
                transition: `all .22s ${VI.ease}`,
              }}/>
            ))}
          </div>
        )}
      </div>

      {/* Title */}
      <div style={{ padding: '22px 20px 16px' }}>
        <div style={{
          fontFamily: VI.fontMono, fontSize: 9.5, color: VI.accent,
          letterSpacing: '0.18em', textTransform: 'uppercase', marginBottom: 8,
        }}>{[fish.family, fish.water].filter(Boolean).join(' · ')}</div>
        <h1 style={{
          fontFamily: VI.fontDisp, fontWeight: 300, fontSize: 32,
          letterSpacing: '-0.01em', lineHeight: 1.05, margin: 0,
        }}>{fish.name}</h1>
        <div style={{
          fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
          fontSize: 16, color: VI.textDim, marginTop: 4,
        }}>{fish.latin}</div>

        {/* Aliases — real, not placeholders */}
        {(() => {
          const aliasList = [...(fish.en_aliases || []), ...(fish.aliases || []), ...(fish.zh_aliases || [])]
            .filter(Boolean);
          if (!aliasList.length) return null;
          return (
            <div style={{
              marginTop: 14, display: 'flex', flexWrap: 'wrap', gap: 6,
            }}>
              {aliasList.slice(0, 8).map(a => (
                <span key={a} style={{
                  fontFamily: VI.fontMono, fontSize: 9, padding: '4px 8px',
                  background: VI.bgCard, color: VI.textDim,
                  border: `0.5px solid ${VI.border}`, borderRadius: 99,
                  letterSpacing: '0.06em',
                }}>{a}</span>
              ))}
            </div>
          );
        })()}
      </div>

      {/* Tabs */}
      <div style={{
        display: 'flex', padding: '0 20px',
        borderBottom: `0.5px solid ${VI.border}`,
      }}>
        {['overview', 'tactics', 'similar'].map(t => (
          <button key={t} className="ctx-btn" onClick={() => setTab(t)} style={{
            padding: '10px 0', marginRight: 22,
            fontFamily: VI.fontMono, fontSize: 10, letterSpacing: '0.14em',
            textTransform: 'uppercase',
            color: tab === t ? VI.text : VI.textMute,
            borderBottom: `1px solid ${tab === t ? VI.accent : 'transparent'}`,
            transition: `all .18s ${VI.ease}`,
          }}>{t}</button>
        ))}
      </div>

      {error && (
        <div style={{
          padding: '20px', textAlign: 'center', fontFamily: VI.fontMono,
          fontSize: 11, color: VI.error,
        }}>Failed to load detail: {error}</div>
      )}

      {tab === 'overview' && <AOverview fish={fish} images={images}/>}
      {tab === 'tactics'  && <ATactics fish={fish}/>}
      {tab === 'similar'  && <ASimilar fish={fish} species={species} onOpen={onOpen}/>}
    </div>
  );
}

function AOverview({ fish, images }) {
  const facts = [
    fish.family && ['Family', fish.family],
    fish.water  && ['Habitat', fish.water],
    (fish.regions || []).length && ['Regions', fish.regions.map(r => REGION_LABEL[r] || r).join(', ')],
  ].filter(Boolean);

  return (
    <div className="ctx-fadeIn" style={{ padding: '20px 20px 0' }}>
      {facts.length > 0 && (
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)',
          border: `0.5px solid ${VI.border}`, gap: '0.5px',
          background: VI.border, marginBottom: 24,
        }}>
          {facts.map(([k, v]) => (
            <div key={k} style={{ background: VI.bg, padding: '12px 14px' }}>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 8.5, color: VI.textMute,
                letterSpacing: '0.14em', textTransform: 'uppercase',
              }}>{k}</div>
              <div style={{
                fontFamily: VI.fontDisp, fontSize: 16, fontWeight: 400,
                color: VI.text, marginTop: 4, lineHeight: 1.25,
              }}>{v}</div>
            </div>
          ))}
        </div>
      )}

      {fish.description && (
        <p style={{
          fontFamily: VI.fontBody, fontWeight: 300, fontSize: 14, lineHeight: 1.75,
          color: VI.textDim, margin: '0 0 22px',
        }}>{fish.description}</p>
      )}

      {fish.adult_id_notes && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
          }}>Adult — Identification</div>
          <p style={{
            fontFamily: VI.fontBody, fontWeight: 300, fontSize: 13, lineHeight: 1.7,
            color: VI.text, margin: 0,
          }}>{fish.adult_id_notes}</p>
        </div>
      )}

      {fish.juvenile_id_notes && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
          }}>Juvenile</div>
          <p style={{
            fontFamily: VI.fontBody, fontWeight: 300, fontSize: 13, lineHeight: 1.7,
            color: VI.text, margin: 0,
          }}>{fish.juvenile_id_notes}</p>
        </div>
      )}

      {fish.taxonomy && (() => {
        const ranks = ['family', 'genus', 'species'];
        const items = ranks.map(r => fish.taxonomy[r]).filter(t => t && t.sci);
        if (!items.length) return null;
        return (
          <div style={{ marginBottom: 22 }}>
            <div style={{
              fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
              letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
            }}>Taxonomy</div>
            <div style={{
              border: `0.5px solid ${VI.border}`,
            }}>
              {items.map((t, i) => (
                <div key={ranks[i]} style={{
                  display: 'flex', alignItems: 'baseline', gap: 12,
                  padding: '10px 12px',
                  borderTop: i ? `0.5px solid ${VI.border}` : 'none',
                }}>
                  <div style={{
                    width: 64,
                    fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
                    letterSpacing: '0.14em', textTransform: 'uppercase',
                  }}>{ranks[i]}</div>
                  <div style={{
                    flex: 1, fontFamily: VI.fontDisp, fontStyle: 'italic',
                    fontSize: 14, color: VI.text,
                  }}>{t.sci}</div>
                  {t.common && (
                    <div style={{
                      fontFamily: VI.fontBody, fontSize: 12, color: VI.textDim,
                    }}>{t.common}</div>
                  )}
                </div>
              ))}
            </div>
          </div>
        );
      })()}

      {/* Gallery — additional photos with attribution */}
      {images.length > 1 && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
            display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          }}>
            <span>Gallery</span>
            <span style={{ color: VI.textFaint, letterSpacing: '0.10em' }}>{images.length} PHOTOS</span>
          </div>
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 4,
          }}>
            {images.map((img) => (
              <div key={img.idx} style={{
                position: 'relative',
                aspectRatio: '1',
                background: VI.bgCard,
                border: `0.5px solid ${VI.border}`,
                overflow: 'hidden',
              }}>
                <img src={img.url} alt="" loading="lazy" style={{
                  width: '100%', height: '100%', objectFit: 'cover', display: 'block',
                }}/>
                {img.life_stage === 'juvenile' && (
                  <div style={{
                    position: 'absolute', top: 4, left: 4,
                    fontFamily: VI.fontMono, fontSize: 8, padding: '2px 5px',
                    background: 'rgba(8,8,10,0.7)', color: VI.accent,
                    letterSpacing: '0.08em', textTransform: 'uppercase',
                  }}>JUV</div>
                )}
              </div>
            ))}
          </div>
          {/* Attribution for the active hero image */}
          {(() => {
            // Show all unique attributions briefly
            const credits = images.map(i => i.attribution).filter(Boolean);
            const unique = [...new Set(credits)];
            if (!unique.length) return null;
            return (
              <div style={{
                marginTop: 10,
                fontFamily: VI.fontMono, fontSize: 9, color: VI.textFaint,
                lineHeight: 1.5, letterSpacing: '0.04em',
              }}>
                Photos: {unique.slice(0, 5).join(' · ')}{unique.length > 5 ? ' …' : ''}
              </div>
            );
          })()}
        </div>
      )}
    </div>
  );
}

function ATactics({ fish }) {
  const baits = (fish.recommended_baits || '').trim();
  const lures = (fish.recommended_lures || '').trim();
  const methods = fish.methods || [];
  const regions = fish.regions || [];
  const hasAny = methods.length || baits || lures || regions.length;

  if (!hasAny) {
    return (
      <div className="ctx-fadeIn" style={{
        padding: '40px 20px', textAlign: 'center',
        fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
        fontSize: 14, color: VI.textMute,
      }}>No fishing intel recorded for this species yet.</div>
    );
  }

  return (
    <div className="ctx-fadeIn" style={{ padding: '20px 20px 0' }}>
      {methods.length > 0 && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
            display: 'flex', alignItems: 'center', gap: 6,
          }}>{Icon.hook(12)} Methods</div>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {methods.map(m => (
              <div key={m} style={{
                padding: '8px 12px',
                background: VI.bgCard, border: `0.5px solid ${VI.border}`,
                borderRadius: 2, fontFamily: VI.fontBody, fontSize: 12,
                color: VI.text, fontWeight: 400,
              }}>{METHOD_LABEL[m] || m}</div>
            ))}
          </div>
        </div>
      )}

      {baits && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
            display: 'flex', alignItems: 'center', gap: 6,
          }}>{Icon.drop(12)} Baits</div>
          <p style={{
            fontFamily: VI.fontBody, fontSize: 13, color: VI.text, lineHeight: 1.6,
            margin: 0,
          }}>{baits}</p>
        </div>
      )}

      {lures && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
            display: 'flex', alignItems: 'center', gap: 6,
          }}>{Icon.sparkle(12)} Lures</div>
          <p style={{
            fontFamily: VI.fontBody, fontSize: 13, color: VI.text, lineHeight: 1.6,
            margin: 0,
          }}>{lures}</p>
        </div>
      )}

      {regions.length > 0 && (
        <div style={{ marginBottom: 22 }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
            letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 10,
          }}>Regions</div>
          {regions.map(r => (
            <div key={r} style={{
              display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0',
              borderBottom: `0.5px solid ${VI.border}`,
            }}>
              <span style={{
                width: 6, height: 6, borderRadius: 99, background: VI.accent,
              }}/>
              <div style={{ flex: 1, fontFamily: VI.fontBody, fontSize: 13, color: VI.text }}>
                {REGION_LABEL[r] || r}
              </div>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
                letterSpacing: '0.1em',
              }}>{r}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

function ASimilar({ fish, species, onOpen }) {
  const others = React.useMemo(() => {
    const sameFamily = (species || []).filter(f => f.family && f.family === fish.family && f.id !== fish.id);
    return sameFamily.slice(0, 6);
  }, [fish, species]);

  if (!others.length) {
    return (
      <div className="ctx-fadeIn" style={{
        padding: '40px 20px', textAlign: 'center',
        fontFamily: VI.fontDisp, fontStyle: 'italic', fontWeight: 300,
        fontSize: 14, color: VI.textMute,
      }}>No relatives in the field guide yet.</div>
    );
  }

  return (
    <div className="ctx-fadeIn" style={{ padding: '20px 20px 0' }}>
      <div style={{
        fontFamily: VI.fontMono, fontSize: 9.5, color: VI.textMute,
        letterSpacing: '0.16em', textTransform: 'uppercase', marginBottom: 12,
      }}>Same Family — {fish.family}</div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
        {others.map((f, i) => (
          <ASpecimenCard key={f.id} fish={f} n={i + 50} onClick={() => onOpen && onOpen(f)}/>
        ))}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Collection — saved + caught
// ─────────────────────────────────────────────────────────────
function ACollection({ species, onOpen, onBrowse }) {
  const sv = useSave();
  const [filter, setFilter] = React.useState('all');

  const savedFish  = React.useMemo(() => species.filter(f => sv.isSaved(f.id)),  [species, sv.saved]);
  const caughtFish = React.useMemo(() => species.filter(f => sv.isCaught(f.id)), [species, sv.caught]);
  const allFish = React.useMemo(() => {
    const seen = new Set(); const out = [];
    for (const f of caughtFish) if (!seen.has(f.id)) { seen.add(f.id); out.push(f); }
    for (const f of savedFish)  if (!seen.has(f.id)) { seen.add(f.id); out.push(f); }
    return out;
  }, [savedFish, caughtFish]);

  const counts = { all: allFish.length, saved: savedFish.length, caught: caughtFish.length };
  const isEmpty = counts.all === 0;
  const savedOnlyFish = savedFish.filter(f => !sv.isCaught(f.id));

  const renderGrid = (list) => (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr 1fr',
      gap: 12, padding: '0 20px 28px',
    }}>
      {list.map((fish) => {
        const n = species.indexOf(fish) + 1;
        return <ASpecimenCard key={fish.id} fish={fish} n={n} onClick={() => onOpen(fish)}/>;
      })}
    </div>
  );

  return (
    <div className="ctx-screen" style={{ minHeight: '100%', paddingBottom: 40 }}>
      <div className="ctx-fadeUp" style={{ padding: '14px 20px 18px' }}>
        <div style={{
          display: 'flex', alignItems: 'center', justifyContent: 'space-between',
          marginBottom: 22,
        }}>
          <div style={{
            fontFamily: VI.fontMono, fontSize: 9, color: VI.textMute,
            letterSpacing: '0.18em', textTransform: 'uppercase',
          }}>Personal Ledger · No. 01</div>
        </div>

        <h1 style={{
          fontFamily: VI.fontDisp, fontWeight: 300, fontSize: 38,
          letterSpacing: '-0.02em', lineHeight: 1.0, margin: 0,
          color: VI.text,
        }}>The Angler's<br/><em style={{ fontWeight: 300 }}>Compendium.</em></h1>
      </div>

      {/* Census strip */}
      <div className="ctx-fadeUp" style={{ padding: '0 20px 22px', animationDelay: '40ms' }}>
        <div style={{
          display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)',
          gap: 1, background: VI.border,
          border: `0.5px solid ${VI.border}`,
        }}>
          {[
            [String(counts.caught).padStart(2, '0'), 'CAUGHT'],
            [String(counts.saved).padStart(2, '0'), 'SAVED'],
          ].map(([n, l]) => (
            <div key={l} style={{ background: VI.bg, padding: '12px 10px' }}>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 18, fontWeight: 500,
                color: VI.text, letterSpacing: '-0.01em',
              }}>{n}</div>
              <div style={{
                fontFamily: VI.fontMono, fontSize: 8.5, color: VI.textMute,
                letterSpacing: '0.14em', marginTop: 2,
              }}>{l}</div>
            </div>
          ))}
        </div>
      </div>

      {!isEmpty && (
        <>
          <ASectionHd num="II" subtitle="Plate" title="Your Specimens"/>
          <div className="ctx-fadeUp" style={{ animationDelay: '60ms' }}>
            <AFilterChips
              value={filter}
              onChange={setFilter}
              options={[
                ['all',    'All',    counts.all],
                ['caught', 'Caught', counts.caught],
                ['saved',  'Saved',  counts.saved],
              ]}
            />
          </div>
        </>
      )}

      {isEmpty && <AEmptyState onBrowse={onBrowse}/>}

      {!isEmpty && filter === 'all' && (
        <div className="ctx-fadeIn">
          {caughtFish.length > 0 && (
            <>
              <AGroupLabel icon={Icon.hook} text="Caught" count={caughtFish.length}/>
              {renderGrid(caughtFish)}
            </>
          )}
          {savedOnlyFish.length > 0 && (
            <>
              <AGroupLabel icon={Icon.bookmark} text="Saved" count={savedOnlyFish.length}/>
              {renderGrid(savedOnlyFish)}
            </>
          )}
        </div>
      )}

      {!isEmpty && filter === 'caught' && (
        <div className="ctx-fadeIn">
          {caughtFish.length === 0
            ? <div style={{
                padding: '40px 20px', textAlign: 'center',
                fontFamily: VI.fontBody, fontSize: 13, color: VI.textMute,
              }}>No catches recorded yet.</div>
            : renderGrid(caughtFish)
          }
        </div>
      )}

      {!isEmpty && filter === 'saved' && (
        <div className="ctx-fadeIn">
          {savedFish.length === 0
            ? <div style={{
                padding: '40px 20px', textAlign: 'center',
                fontFamily: VI.fontBody, fontSize: 13, color: VI.textMute,
              }}>Nothing saved yet.</div>
            : renderGrid(savedFish)
          }
        </div>
      )}

      <div style={{
        padding: '4px 20px 28px',
        display: 'flex', justifyContent: 'space-between', alignItems: 'center',
        borderTop: `0.5px solid ${VI.border}`, marginTop: 8, paddingTop: 16,
      }}>
        <Wordmark size={8.5} prefix={true}/>
        <div style={{
          fontFamily: VI.fontMono, fontSize: 8, color: VI.textFaint,
          letterSpacing: '0.18em', textTransform: 'uppercase',
        }}>End of Ledger</div>
      </div>
    </div>
  );
}

Object.assign(window, { AHome, ASearch, ADetail, ACollection });
