/* shared.jsx — data, router, nav, and small presentational atoms */

const SPECIES = [
  { id: 'eoani',   zh: '衡族',   en: 'Eoani',   hostZh: 'Ross 128 b',                 hostEn: 'Ross 128 b',                ly: 11.0, star: 'M4V', blurbZh: '红外-磁场感官、千年寿命、潮汐锁定晨昏带。',           blurbEn: 'Infrared + magnetoreception, millennial lifespan, tidally locked terminator.', color: '#e8821f', path: '/eoani'   },
  { id: 'ketoi',   zh: '鲸语族', en: 'Ketoi',   hostZh: '天仓 e (Tau Ceti e)',        hostEn: 'Tau Ceti e',                ly: 11.9, star: 'G8V', blurbZh: '声学原生、傅里叶本能、最早的望远镜指向下方。',       blurbEn: 'Acoustic-native, Fourier as instinct, earliest telescopes pointed down.',     color: '#2e86ab', path: '/ketoi'   },
  { id: 'huvari',  zh: '涣族',   en: 'Huvari',  hostZh: '82 G. Eridani',              hostEn: '82 G. Eridani',             ly: 19.7, star: 'G8V', blurbZh: '电感受、清洁工业、半导体先于燃烧。',                 blurbEn: 'Electroreception, clean industry, semiconductors before combustion.',         color: '#00d9ff', path: '/huvari'  },
  { id: 'thavari', zh: '震族',   en: 'Thavari', hostZh: '波江 ε (Epsilon Eridani) 冰卫星', hostEn: 'Epsilon Eridani · ice moon', ly: 10.5, star: 'K2V', blurbZh: '振动/张量感官、冰下黑暗海洋、八位环认知。',      blurbEn: 'Strain-tensor sense, dark sub-glacial ocean, eight-bodied cognition.',        color: '#00ffc8', path: '/thavari' },
  { id: 'human',   zh: '人类',   en: 'Human',   hostZh: '太阳 (Sol)',                 hostEn: 'Sol',                       ly:  0.0, star: 'G2V', blurbZh: '聚变时代、太阳系全域、2089 年才确知自己不孤独。',    blurbEn: 'Fusion era, Sol system-wide, only knew it was not alone in 2089.',           color: '#ff8c00', path: '/human'   },
];

/* ------------------ CONTACT MATRIX DATA ------------------ */
const CONTACT_EVENTS = [
  { a: 'huvari',  b: 'eoani',   year: 1791, label: { zh:'首次接触', en:'First Contact' },    sub: { zh:'无线电 (radio)', en:'radio' }, hot: true  },
  { a: 'huvari',  b: 'ketoi',   year: 2128, label: { zh:'贸易语确认', en:'Trade Lang Ack' },  sub: { zh:'慢船 + 声学翻译', en:'slow-ship + acoustic xlat' },  hot: false },
  { a: 'huvari',  b: 'human',   year: 2128, label: { zh:'首次贸易语', en:'First Trade Lang' }, sub: { zh:'无线电', en:'radio' },           hot: false },
  { a: 'huvari',  b: 'thavari', year: 2612, label: { zh:'断环事件', en:'Ring-Breaking' },    sub: { zh:'物理 / 危机', en:'physical / crisis' },      hot: false },
  { a: 'eoani',   b: 'ketoi',   year: 2204, label: { zh:'通讯握手', en:'Comms Handshake' },    sub: { zh:'三边中继', en:'three-party relay' },         hot: false },
  { a: 'eoani',   b: 'human',   year: 2156, label: { zh:'语言谱校准', en:'Lang-Spectrum Sync' },  sub: { zh:'无线电', en:'radio' },           hot: false },
  { a: 'eoani',   b: 'thavari', year: 2418, label: { zh:'环-同意对话', en:'Ring-Consent Dialog' }, sub: { zh:'冰下继电', en:'sub-ice relay' },         hot: false },
  { a: 'ketoi',   b: 'human',   year: 2188, label: { zh:'海洋脑会晤', en:'Ocean-Mind Encounter' },  sub: { zh:'原位探测器', en:'in-situ probe' },       hot: false },
  { a: 'ketoi',   b: 'thavari', year: 2470, label: { zh:'声学-振动互译', en:'Acoustic-Strain Xlat' }, sub: { zh:'低频共振', en:'low-freq resonance' },        hot: false },
  { a: 'human',   b: 'thavari', year: 2300, label: { zh:'首次接触', en:'First Contact' },    sub: { zh:'熔探 (Magellan Ⅰ)', en:'melt-probe (Magellan Ⅰ)' }, hot: true  },
];

const TIMELINE_EVENTS = [
  { year: 1712, who: 'huvari',  zh: { t:'涣族探测 Ross 128 异常',  d:'热异常，疑似人工废热签名。' }, en: { t:'Huvari detect Ross 128 anomaly', d:'Thermal anomaly suspected as artificial waste-heat signature.' } },
  { year: 1755, who: 'huvari',  zh: { t:'首次定向无线电发射',       d:'朝向 Ross 128 方向。' }, en: { t:'First directed radio transmission', d:'Aimed at Ross 128.' } },
  { year: 1791, who: 'huvari eoani', zh: { t:'涣-衡首次接触',       d:'无线电双向确认 · 五族史零点。' }, en: { t:'Huvari–Eoani First Contact', d:'Two-way radio handshake · Year Zero of five-species history.' }, pin: true },
  { year: 1880, who: 'huvari',  zh: { t:'首次核脉冲行星际任务',    d:'涣族母系外推。' }, en: { t:'First nuclear-pulse interplanetary mission', d:'Huvari extra-system outbound.' } },
  { year: 1950, who: 'huvari',  zh: { t:'天仓方向信号初识',        d:'涣族远程观测。' }, en: { t:'Tau Ceti signal first noticed', d:'Huvari remote observation.' } },
  { year: 2026, who: 'human',   zh: { t:'人类叙事零点',            d:'信息时代成熟期。' }, en: { t:'Human narrative zero', d:'Mature information age.' } },
  { year: 2089, who: 'human',   zh: { t:'月背阵列确认窄带调制',    d:'人类首次确知不孤独。' }, en: { t:'Lunar far-side array confirms narrowband modulation', d:'Humans first know they are not alone.' }, pin: true },
  { year: 2128, who: 'human huvari', zh: { t:'人类首次贸易语传输', d:'向涣族母星广播。' }, en: { t:'First human Trade-Language broadcast', d:'Beamed at the Huvari home star.' } },
  { year: 2170, who: 'human',   zh: { t:'首批 Starshot 级探测器', d:'0.2c 微型船队。' }, en: { t:'First Starshot-class probes', d:'0.2c micro-fleet.' } },
  { year: 2180, who: 'huvari eoani', zh: { t:'涣-衡首次物理会面',  d:'Ross 128 b 轨道。' }, en: { t:'Huvari–Eoani first physical meeting', d:'Ross 128 b orbit.' } },
  { year: 2210, who: 'eoani huvari', zh: { t:'潮衡融合开端',       d:'加涣衡系基因载体出生。' }, en: { t:'Tide-Balanced lineage begins', d:'First Aushrani carriers of Huvari electroreceptive genes.' } },
  { year: 2250, who: 'human',   zh: { t:'麦哲伦一号发射',          d:'聚变慢船 · 0.1c。' }, en: { t:'Magellan Ⅰ launches', d:'Fusion slow-ship · 0.1c.' } },
  { year: 2300, who: 'human thavari', zh: { t:'人-震首次接触',     d:'熔探穿透冰壳。' }, en: { t:'Human–Thavari First Contact', d:'Melt-probe penetrates the ice shell.' }, pin: true },
  { year: 2500, who: 'all',     zh: { t:'五方协议',                d:'首次书面相互承认。' }, en: { t:'The Five-Party Accord', d:'First written mutual recognition by all five species.' }, pin: true },
  { year: 2598, who: 'human ketoi', zh: { t:'声窃分裂开始',        d:'《天仓歌经》出版。' }, en: { t:'Song-Theft Schism opens', d:'Canticles of Tau Ceti is published.' } },
  { year: 2612, who: 'huvari thavari', zh: { t:'断环事件',          d:'涣族脉冲致震族八位环崩溃。' }, en: { t:'Ring-Breaking', d:'A Huvari EM pulse desynchronises a Thavari Octothrone.' } },
  { year: 2700, who: 'all',     zh: { t:'环-同意协议',             d:'制度支柱 I。' }, en: { t:'Ring-Consent Protocol', d:'Institutional pillar I.' } },
  { year: 2724, who: 'human ketoi', zh: { t:'无回响协议',          d:'感官产权法。' }, en: { t:'No-Echo Protocol', d:'First sense-property law.' } },
  { year: 2780, who: 'human huvari', zh: { t:'干扰战争开始',       d:'EM 干扰致 31 幼体死亡。' }, en: { t:'Jamming War begins', d:'EM jamming kills 31 Huvari juveniles.' } },
  { year: 2821, who: 'all',     zh: { t:'频率公域成立',            d:'制度支柱 II。' }, en: { t:'Frequency Commons established', d:'Institutional pillar II.' } },
  { year: 2850, who: 'eoani',   zh: { t:'纯衡起义',                d:'纯衡 vs 潮衡。' }, en: { t:'Pure-Caste Rising', d:'Pure-Eoani vs Aushrani.' } },
  { year: 2944, who: 'human eoani', zh: { t:'帐簿危机开始',        d:'禁运致 80,000 大衡过早死亡。' }, en: { t:'Ledger Crisis begins', d:'Embargo causes 80,000 Magni to die prematurely.' } },
  { year: 2990, who: 'all',     zh: { t:'未来年岁协约',            d:'制度支柱 IV。' }, en: { t:'Covenant of Years Yet to Come', d:'Institutional pillar IV.' } },
  { year: 3104, who: 'all',     zh: { t:'双炉协定',                d:'制度支柱 V。' }, en: { t:'Two-Hearth Accord', d:'Institutional pillar V.' } },
  { year: 4500, who: 'all',     zh: { t:'叙事当下',                d:'合作时代中期。' }, en: { t:'Narrative present', d:'Mid era of cooperation.' } },
];

/* ------------------ STORY ENGINES ------------------ */
const ENGINES = [
  { id: 1,  zh: '千年折现率',  en: 'Millennial Discount',    tags: { zh:['衡族','人类'], en:['Eoani','Human'] },           tZh: '衡族以 0.01%/年折现，人类以 5%/年折现。同一座桥的合同在两族账簿里相差四个数量级。', tEn: 'Eoani discount at 0.01%/yr; humans at 5%/yr. The same bridge sits four orders of magnitude apart on the two species\' books.' },
  { id: 2,  zh: '感官产权',    en: 'Sense-Ownership',        tags: { zh:['鲸语族','人类'], en:['Ketoi','Human'] },         tZh: '鲸语族的名字就是其频谱。人类唱片店里，每一张专辑都是身份盗窃的物证。', tEn: 'A Ketoi name is its spectrogram. Every album in a human record store is exhibit A in an identity-theft case.' },
  { id: 3,  zh: '潮衡血统',    en: 'Tide-Balanced Bloodline',tags: { zh:['衡族','涣族'], en:['Eoani','Huvari'] },           tZh: '潮衡携带涣族电感受基因。纯衡认为他们"不是衡族"；潮衡认为他们是"下一代衡族"。', tEn: 'The Aushrani carry Huvari electroreceptive genes. Pure-Eoani say they "aren\'t Eoani"; Aushrani say they\'re "the next Eoani".' },
  { id: 4,  zh: '八位人格',    en: 'Octothrone Personhood',  tags: { zh:['震族','人类'], en:['Thavari','Human'] },           tZh: '一个"震族"由八人协调而成。当其中一人死去，法律上是谋杀还是截肢？', tEn: 'A Thavari is eight bodies in synchrony. When one dies — is that murder, or amputation?' },
  { id: 5,  zh: '废热签名',    en: 'Waste-Heat Signature',   tags: { zh:['衡族','涣族'], en:['Eoani','Huvari'] },           tZh: '1712 年涣族看到的那缕红光，原来是衡族长寿工业的排气。每一代衡者都在发光。', tEn: 'The faint glow Huvari saw in 1712 was waste heat from Eoani longevity industry. Every Eoan generation radiates.' },
  { id: 6,  zh: '下视天文学',  en: 'Looking-Down Astronomy', tags: { zh:['鲸语族'], en:['Ketoi'] },                          tZh: '鲸语族第一架"望远镜"指向海床。他们用了六百年才意识到宇宙在反方向。', tEn: 'The first Ketoi telescope pointed at the seafloor. It took them six centuries to realize the universe was the other way.' },
  { id: 7,  zh: '光时外交',    en: 'Light-Lag Diplomacy',    tags: { zh:['全族'], en:['All'] },                              tZh: '任何两族之间的电报往返至少 20 年。长寿者能等；短命者不能。所有条约都偏袒老者。', tEn: 'A radio round-trip between any two species is ≥20 years. The long-lived can wait; the short-lived cannot. Every treaty favors the old.' },
  { id: 8,  zh: '推断的宇宙',  en: 'Inferred Cosmos',        tags: { zh:['震族'], en:['Thavari'] },                          tZh: '震族在冰壳下用应变张量推断出了整个太阳系——比任何望远镜都早。破冰之后，他们"亲见"的反而少了。', tEn: 'Thavari inferred their whole sub-system from strain tensors — earlier than any telescope. After the ice broke, they saw less.' },
  { id: 9,  zh: '清洁工业审判',en: 'Clean-Industry Verdict', tags: { zh:['涣族','人类'], en:['Huvari','Human'] },             tZh: '涣族从未烧过煤。他们不明白为什么人类的"工业遗产"值得保留。', tEn: 'Huvari have never burned coal. They cannot fathom why human "industrial heritage" deserves preservation.' },
  { id: 10, zh: '长寿脆弱性',  en: 'Longevity Fragility',    tags: { zh:['衡族'], en:['Eoani'] },                            tZh: '大衡的千年寿命靠一条冷链物流维持。一代人的禁运会抹去一整代祖先。', tEn: 'A Magni\'s millennial life depends on a cold-chain. One generation of embargo erases a generation of ancestors.' },
  { id: 'D',zh: '声窃分裂',    en: 'Song Theft Schism',      tags: { zh:['已解决','人类','鲸语族'], en:['resolved','Human','Ketoi'] }, tZh: '2598–2720 · 110 年沉默；无回响协议诞生。', tEn: '2598–2720 · 110 years of silence; the No-Echo Protocol emerges.' },
  { id: 'B',zh: '干扰战争',    en: 'Jamming War',            tags: { zh:['已解决','人类','涣族'], en:['resolved','Human','Huvari'] }, tZh: '2780–2820 · 频率公域诞生。', tEn: '2780–2820 · the Frequency Commons is born.' },
  { id: 'C',zh: '帐簿危机',    en: 'Ledger Crisis',          tags: { zh:['已解决','人类','衡族'], en:['resolved','Human','Eoani'] }, tZh: '2944–2990 · 未来年岁协约诞生。', tEn: '2944–2990 · the Covenant of Years Yet to Come is signed.' },
];

/* SN, CE provided by i18n.jsx */

/* ------------------ Router (hash-based) ------------------ */
function useRoute() {
  const [route, setRoute] = React.useState(() => window.location.hash.replace('#', '') || '/');
  React.useEffect(() => {
    const on = () => setRoute(window.location.hash.replace('#', '') || '/');
    window.addEventListener('hashchange', on);
    return () => window.removeEventListener('hashchange', on);
  }, []);
  const nav = React.useCallback(p => { window.location.hash = p; window.scrollTo(0, 0); }, []);
  return [route, nav];
}

/* ------------------ Global Nav ------------------ */
function GlobalNav({ route, nav, theme }) {
  const { lang, setLang } = useLang();
  return (
    <nav className="g-nav" style={{ color: theme?.fg, background: theme?.navBg, borderColor: theme?.rule }}>
      <div className="g-nav__brand">
        <span className="g-nav__brand-mark" />
        <span>{lang === 'zh' ? <>缓约 &middot; <span className="cjk-en">Slow Compact</span></> : <>Slow Compact &middot; <span style={{opacity:0.55, fontStyle:'italic'}}>缓约</span></>}</span>
      </div>
      <div className="g-nav__species">
        {SPECIES.map(s => (
          <button key={s.id}
                  onClick={() => nav(s.path)}
                  className={route === s.path ? 'is-active' : ''}
                  title={`${s.zh} (${s.en}) · ${lang==='zh'?s.hostZh:s.hostEn} · ${s.ly} ly`}>
            <span className="swatch" style={{ background: s.color }} />
            <span>{lang === 'zh' ? s.zh : s.en}</span>
          </button>
        ))}
      </div>
      <div className="g-nav__utility">
        <button onClick={() => nav('/')}        className={route === '/' ? 'is-active' : ''}><T zh="首页" en="Home" /></button>
        <button onClick={() => nav('/timeline')} className={route === '/timeline' ? 'is-active' : ''}><T zh="时间线" en="Timeline" /></button>
        <button onClick={() => nav('/contact')}  className={route === '/contact' ? 'is-active' : ''}><T zh="接触矩阵" en="Contact" /></button>
        <button onClick={() => nav('/about')}    className={route === '/about' ? 'is-active' : ''}><T zh="关于" en="About" /></button>
        <span style={{borderLeft:'1px solid currentColor', opacity:0.3, height:14}} />
        <button onClick={() => setLang(lang === 'zh' ? 'en' : 'zh')}
                style={{fontFamily:'var(--font-mono)', letterSpacing:'0.1em', opacity: 1}}>
          <span style={{opacity: lang === 'zh' ? 1 : 0.4}}>中</span>
          <span style={{margin:'0 6px', opacity:0.4}}>/</span>
          <span style={{opacity: lang === 'en' ? 1 : 0.4}}>EN</span>
        </button>
      </div>
    </nav>
  );
}

/* ------------------ Source citation ------------------ */
function Src({ n }) { return <sup className="src">[{n}]</sup>; }

/* ------------------ Fact row on species pages ------------------ */
function FactRow({ items }) {
  return (
    <div className="sp__fact-row">
      {items.map((it, i) => (
        <div key={i}>
          <span className="label">{it.label}</span>
          <div className="val">{it.val}{it.unit && <span className="unit">{it.unit}</span>}</div>
          {it.note && <div className="note">{it.note}</div>}
        </div>
      ))}
    </div>
  );
}

/* ------------------ Export to globals ------------------ */
Object.assign(window, {
  SPECIES, CONTACT_EVENTS, TIMELINE_EVENTS, ENGINES,
  useRoute, GlobalNav, Src, FactRow
});
