// ViG Command Center — Military Academy (Academy levels 41–45)
// Data transcribed from "Academy 41-45.xlsx" (TOTAL BUFFS sheet; costs: Smoken / building RSS: Theria)
const { useState: useStateAC, useMemo: useMemoAC, useEffect: useEffectAC } = React;

/* [name, stat, v41, v42, v43, v44, v45] — % stored as fraction, flat values as numbers */
const AC_ATK = [
  ['Advanced Instructor', 'Training Speed', 0.12, 0.3, 0.5, 0.5, 0.5],
  ['Master Trainer', 'Training Capacity', 0.15, 0.15, 0.6, 0.6, 0.6],
  ['Master Hunter', 'Attack Against Monsters', 0, 0, 0.36, 0.6, 0.6],
  ['Master Tracker', 'March Speed to Monster', 0, 0, 0.48, 0.8, 0.8],
  ['Junior Officer', 'March Size', 12000, 12000, 50000, 50000, 50000],
  ['Intermediate Officer', 'March Size', 0, 12000, 29500, 50000, 50000],
  ['Senior Officer', 'March Size', 0, 0, 0, 59000, 100000],
  ['Advanced Covenant', 'Rally Capacity', 96000, 96000, 400000, 400000, 400000],
  ['Super Covenant', 'Rally Capacity', 0, 0, 0, 354000, 600000],
  ['Assault Ground Troop Sharpening', 'Attacking Ground Atk', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ground Troop Armor Quenching', 'Attacking Ground Def', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ground Troop Vitality', 'Attacking Ground HP', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ranged Troop Sharpening', 'Attacking Ranged Atk', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ranged Troop Armor Quenching', 'Attacking Ranged Def', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ranged Troop Vitality', 'Attacking Ranged HP', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Mounted Troop Sharpening', 'Attacking Mounted Atk', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Mounted Troop Armor Quenching', 'Attacking Mounted Def', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Mounted Troop Vitality', 'Attacking Mounted HP', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Siege Machine Sharpening', 'Attacking Siege Atk', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Siege Machine Iron Wall', 'Attacking Siege Def', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Siege Machine Steel Forging', 'Attacking Siege HP', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ground Troop Armor Corrosion', 'Debuff Ground Def (Attacking)', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ranged Troop Armor Corrosion', 'Debuff Ranged Def (Attacking)', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Mounted Troop Armor Corrosion', 'Debuff Mounted Def (Attacking)', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Siege Machine Armor Corrosion', 'Debuff Siege Def (Attacking)', 0.13, 0.13, 0.5, 0.5, 0.5],
  ['Assault Ground Troop Shatter', 'Debuff Ground HP (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Assault Ground Troop Disarm', 'Debuff Ground Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Assault Ranged Troop Shatter', 'Debuff Ranged HP (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Assault Ranged Troop Disarm', 'Debuff Ranged Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Assault Mounted Troop Shatter', 'Debuff Mounted HP (Attacking)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Assault Mounted Troop Disarm', 'Debuff Mounted Atk (Attacking)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Assault Siege Machine Shatter', 'Debuff Siege HP (Attacking)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Assault Siege Machine Disarm', 'Debuff Siege Atk (Attacking)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Ground Troop Disarm', 'Debuff Ground Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Mounted Troop Disarm', 'Debuff Mounted Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Ranged Troop Disarm', 'Debuff Ranged Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Siege Machine Disarm', 'Debuff Siege Atk (Attacking)', 0, 0, 0.29, 0.5, 0.5],
  ['Ground Troop Sharpening', 'Single Ground Atk', 0, 0, 0.29, 0.5, 0.5],
  ['Mounted Troop Sharpening', 'Single Mounted Atk', 0, 0, 0.29, 0.5, 0.5],
  ['Ranged Troop Sharpening', 'Single Ranged Atk', 0, 0, 0.29, 0.5, 0.5],
  ['Siege Machine Sharpening', 'Single Siege Atk', 0, 0, 0.29, 0.5, 0.5],
  ['Prototype Crossbow', 'Single Ranged Atk (flat)', 120, 120, 500, 500, 500],
  ['Frontline Siege Machine Sharpening', 'Siege Atk on Battlefield (flat)', 0, 0, 295, 500, 500],
  ['Heavy Ballista', 'Ranged Atk in Rally (flat)', 0, 0, 0, 295, 500],
  ['Joint Ground Troop Sharpening', 'Ground Atk in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Ground Troop Armor Quenching', 'Ground Def in Rally', 0, 0, 0.25, 0.57, 1],
  ['Joint Ground Troop Vitality', 'Ground HP in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Ranged Troop Sharpening', 'Ranged Atk in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Ranged Troop Armor Quenching', 'Ranged Def in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Ranged Troop Vitality', 'Ranged HP in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Mounted Troop Sharpening', 'Mounted Atk in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Mounted Troop Armor Quenching', 'Mounted Def in Rally', 0, 0, 0.25, 0.57, 1],
  ['Joint Mounted Troop Vitality', 'Mounted HP in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Siege Machine Sharpening', 'Siege Atk in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Siege Machine Iron Wall', 'Siege Def in Rally', 0, 0, 0, 0.57, 1],
  ['Joint Siege Machine Steel Forging', 'Siege HP in Rally', 0, 0, 0, 0.57, 1],
];
const AC_DEF = [
  ['Fortified Walls', 'Wall HP', 0.24, 0.59, 1, 1, 1],
  ['Poisoned Traps', 'Trap Attack', 0.24, 0.59, 1, 1, 1],
  ['Trap Formation', 'Trap Capacity', 0, 24000, 59000, 100000, 100000],
  ['Junior Archer Tower Reinforcement', 'Archer Tower HP', 0.15, 0.36, 0.6, 0.6, 0.6],
  ['Advanced Archer Tower Reinforcement', 'Archer Tower HP', 0, 0, 0, 0.59, 1],
  ['Rapid Fire Archer Tower', 'Archer Tower Atk', 0, 0, 0.54, 0.9, 0.9],
  ['Diplomatic Envoy', 'Reinforcement Capacity', 96000, 236000, 400000, 400000, 400000],
  ['Diplomatic Expert', 'Reinforcement Capacity', 0, 0, 0, 354000, 600000],
  ['Glory of National War', 'Troop Revival Power in SVS', 0, 0.24, 0.59, 1, 1],
  ['Rapid Recovery', 'Healing Speed', 0, 0, 0, 0.18, 0.3],
  ['Defending Ground Troop Sharpening', 'Defending Ground Atk', 0.25, 0.57, 1, 1, 1],
  ['Defending Ground Troop Armor Quenching', 'Defending Ground Def', 0.25, 0.57, 1, 1, 1],
  ['Defending Ground Troop Vitality', 'Defending Ground HP', 0.25, 0.57, 1, 1, 1],
  ['Defending Ranged Troop Sharpening', 'Defending Ranged Atk', 0.25, 0.57, 1, 1, 1],
  ['Defending Ranged Troop Armor Quenching', 'Defending Ranged Def', 0.25, 0.57, 1, 1, 1],
  ['Defending Ranged Troop Vitality', 'Defending Ranged HP', 0.25, 0.57, 1, 1, 1],
  ['Defending Mounted Troop Sharpening', 'Defending Mounted Atk', 0.25, 0.57, 1, 1, 1],
  ['Defending Mounted Troop Armor Quenching', 'Defending Mounted Def', 0.25, 0.57, 1, 1, 1],
  ['Defending Mounted Troop Vitality', 'Defending Mounted HP', 0.25, 0.57, 1, 1, 1],
  ['Defending Siege Machine Sharpening', 'Defending Siege Atk', 0.25, 0.57, 1, 1, 1],
  ['Defending Siege Machine Iron Wall', 'Defending Siege Def', 0.25, 0.57, 1, 1, 1],
  ['Defending Siege Maching Steel Forging', 'Defending Siege HP', 0.25, 0.57, 1, 1, 1],
  ['Defending Ground Troop Armor Corrosion', 'Debuff Ground Def (Defending)', 0.13, 0.29, 0.5, 0.5, 0.5],
  ['Defending Ranged Troop Armor Corrosion', 'Debuff Ranged Def (Defending)', 0.13, 0.29, 0.5, 0.5, 0.5],
  ['Defending Mounted Troop Armor Corrosion', 'Debuff Mounted Def (Defending)', 0.13, 0.29, 0.5, 0.5, 0.5],
  ['Defending Siege Machine Armor Corrosion', 'Debuff Siege Def (Defending)', 0.13, 0.29, 0.5, 0.5, 0.5],
  ['Defending Ground Troop Shatter', 'Debuff Ground HP (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Ground Troop Disarm', 'Debuff Ground Atk (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Ranged Troop Shatter', 'Debuff Ranged HP (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Ranged Troop Disarm', 'Debuff Ranged Atk (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Mounted Troop Shatter', 'Debuff Mounted HP (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Mounted Troop Disarm', 'Debuff Mounted Atk (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Siege Machine Shatter', 'Debuff Siege HP (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Defending Siege Machine Disarm', 'Debuff Siege Atk (Defending)', 0, 0.13, 0.29, 0.5, 0.5],
  ['Ground Troop Armor Quenching', 'Single Ground Def', 0, 0, 0.29, 0.5, 0.5],
  ['Ground Troop Vitality', 'Single Ground HP', 0, 0, 0.29, 0.5, 0.5],
  ['Ranged Troop Armor Quenching', 'Single Ranged Def', 0, 0, 0.29, 0.5, 0.5],
  ['Ranged Troop Vitality', 'Single Ranged HP', 0, 0, 0.29, 0.5, 0.5],
  ['Mounted Troop Armor Quenching', 'Single Mounted Def', 0, 0, 0.29, 0.5, 0.5],
  ['Mounted Troop Vitality', 'Single Mounted HP', 0, 0, 0.29, 0.5, 0.5],
  ['Siege Machine Iron Wall', 'Single Siege Def', 0, 0, 0.29, 0.5, 0.5],
  ['Siege Machine Steel Forging', 'Single Siege HP', 0, 0, 0.29, 0.5, 0.5],
  ['Prototype Lance', 'Single Mounted Atk (flat)', 144, 354, 600, 600, 600],
  ['Advanced Lance', 'Single Mounted Atk (flat)', 0, 0, 590, 1000, 1000],
  ['In City Ground Troop Sharpening', 'Ground Atk in City', 0, 0, 0, 0.29, 0.5],
  ['In City Ground Troop Armor Quenching', 'Ground Def in City', 0, 0, 0.13, 0.29, 0.5],
  ['In City Ground Troop Vitality', 'Ground HP in City', 0, 0, 0, 0.29, 0.5],
  ['In City Ranged Troop Sharpening', 'Ranged Atk in City', 0, 0, 0, 0.29, 0.5],
  ['In City Ranged Troop Armor Quenching', 'Ranged Def in City', 0, 0, 0, 0.29, 0.5],
  ['In City Ranged Troop Vitality', 'Ranged HP in City', 0, 0, 0, 0.29, 0.5],
  ['In City Mounted Troop Sharpening', 'Mounted Atk in City', 0, 0, 0, 0.29, 0.5],
  ['In City Mounted Troop Armor Quenching', 'Mounted Def in City', 0, 0, 0.13, 0.29, 0.5],
  ['In City Mounted Troop Vitality', 'Mounted HP in City', 0, 0, 0, 0.29, 0.5],
  ['In City Siege Machine Sharpening', 'Siege Atk in City', 0, 0, 0, 0.29, 0.5],
  ['In City Siege Machine Iron Wall', 'Siege Def in City', 0, 0, 0, 0.29, 0.5],
  ['In City Siege Machine Steel Forging', 'Siege HP in City', 0, 0, 0, 0.29, 0.5],
];
/* per-tree research cost per level 41–45 (data: Smoken) */
const AC_COST_DEF = {
  ATK: { stones: [8164, 47883, 159645, 261138, 238432], gold: [459, 2694, 8980, 14689, 13411], speed: [1108, 6495, 21653, 35418, 32337] },
  DEF: { stones: [11447, 49542, 145472, 172940, 162345], gold: [644, 2787, 8182, 9727, 9132], speed: [1552, 6719, 19730, 23455, 22019] },
};
/* Academy building upgrade RSS per level 41–45, in billions (data: Theria) */
const AC_BUILD_DEF = { Food: [23.4, 25.3, 27.2, 29.1, 31.0], Wood: [29.7, 32.1, 34.6, 37.0, 39.4], Stone: [30.6, 33.1, 35.6, 38.1, 40.6], Ore: [29.7, 32.1, 34.5, 36.9, 39.4] };

const AC_TROOPS = ['Ground', 'Ranged', 'Mounted', 'Siege'];
const AC_TROOP_COLOR = { Ground: '#2563eb', Ranged: '#16a34a', Mounted: '#dc2626', Siege: '#9333ea', Other: '#71717a' };
const AC_TROOP_IMG = { Ground: 'vig/assets/icons/infantry.png', Ranged: 'vig/assets/icons/ranged.png', Mounted: 'vig/assets/icons/cavalry.png', Siege: 'vig/assets/icons/siege.png' };
const AC_KINDS = ['Battle', 'Debuff', 'Rally', 'In City', 'Single', 'Utility'];
const AC_KIND_ICON = { Battle: 'target', Debuff: 'scale', Rally: 'layers', 'In City': 'shield', Single: 'star', Utility: 'bolt' };

function acTroop(stat) { return AC_TROOPS.find(t => stat.includes(t)) || 'Other'; }
function acKind(stat) {
  if (stat.includes('Debuff')) return 'Debuff';
  if (stat.includes('in Rally')) return 'Rally';
  if (stat.includes('in City')) return 'In City';
  if (stat.startsWith('Single')) return 'Single';
  if (stat.includes('Attacking') || stat.includes('Defending')) return 'Battle';
  return 'Utility';
}
const acIsFlat = vals => Math.max(...vals) > 5;
const acFmtVal = (v, flat) => flat ? Math.round(v).toLocaleString() : (Math.round(v * 1000) / 10).toLocaleString() + '%';
const acFmtB = n => n.toFixed(1) + 'B';

/* ---- Research Speed checklist (shared by Academy & Military Academy) ---- */
const RS_ITEMS = [
  'Monarch Gear – Intellect Crown',
  'Civilization Treasure – Code of Hammurabi',
  'Activate Celtic Dragon Talent',
  'Victory Column upgrades',
  'Kings Title – Scholar',
  'Monarch Talent',
  'Super Academy Duty Officer 40% (you can put your top General as MA duty officer)',
  'Academy Duty Officer – Mundeok or Hammurabi',
  'Military Academy Duty Officer 40%',
  'Military Academy Duty Officer – Justinian',
  'Academy / Military Academy Duty Officer 3rd and 4th specialty',
  'Academy Officer Staff, refined for research speed',
  'Change culture – American',
  'Switch out American Subs',
  'Use to activate keeps: Fort Frost, Daybreak Vale, Twilight, Rain Forest, Solemn Hill',
  'Own to activate keeps: Godzilla, Ancient Capital, Colossus, Castle Dracula, Azure Capital, Silver Wonder, Harvest Winery, Egg Garden',
  'Academy research – Development',
  'Glory monthly card',
  'Alliance Science',
  'Stephen Research Factory Officer',
  'Sub City Spectacles',
  'VIP level',
  'Alliance Castle – Loulan, Atlantis (Oracle only)',
];
function ResearchSpeedChecklist() {
  const [done, setDone] = useStateAC(() => LS.get('vig2_rs_check', []));
  useEffectAC(() => { LS.set('vig2_rs_check', done); }, [done]);
  const toggle = i => setDone(d => d.includes(i) ? d.filter(x => x !== i) : [...d, i]);
  const pct = Math.round(done.length / RS_ITEMS.length * 100);
  return (
    <Card className="overflow-hidden">
      <div className="flex flex-wrap items-center gap-x-3 gap-y-1.5 border-b border-zinc-100 px-4 py-3 dark:border-zinc-800">
        <Icon name="bolt" size={16} className="text-brand" />
        <div className="min-w-0">
          <div className="text-[13px] font-bold uppercase tracking-wide text-zinc-900 dark:text-white">Research Speed</div>
          <div className="text-[11px] text-zinc-400">Checklist to boost research speed — tick what you already have</div>
        </div>
        <div className="ml-auto flex items-center gap-2.5">
          <div className="h-1.5 w-28 overflow-hidden rounded-full bg-zinc-100 dark:bg-zinc-800"><div className="h-full rounded-full bg-brand transition-all" style={{ width: pct + '%' }}></div></div>
          <span className="text-[12px] font-bold tabular-nums text-brand">{done.length}/{RS_ITEMS.length}</span>
          {done.length > 0 && <button onClick={() => setDone([])} className="text-[11px] font-medium text-zinc-400 hover:text-brand">Clear</button>}
        </div>
      </div>
      <div className="grid grid-cols-1 gap-x-6 md:grid-cols-2">
        {RS_ITEMS.map((it, i) => {
          const on = done.includes(i);
          return (
            <button key={i} onClick={() => toggle(i)} className="flex items-start gap-2.5 border-b border-zinc-50 px-4 py-2 text-left transition-colors hover:bg-zinc-50/70 dark:border-zinc-800/50 dark:hover:bg-zinc-800/40">
              <span className={`mt-0.5 flex h-4.5 w-4.5 min-h-[18px] min-w-[18px] items-center justify-center rounded border transition-colors ${on ? 'border-emerald-500 bg-emerald-500 text-white' : 'border-zinc-300 dark:border-zinc-600'}`}>{on && <Icon name="check" size={12} stroke={3} />}</span>
              <span className={`text-[12.5px] leading-snug ${on ? 'text-zinc-400 line-through decoration-zinc-300 dark:decoration-zinc-600' : 'text-zinc-700 dark:text-zinc-200'}`}><b className="mr-1 tabular-nums text-zinc-400">{i + 1}.</b>{it}</span>
            </button>
          );
        })}
      </div>
    </Card>
  );
}
window.ResearchSpeedChecklist = ResearchSpeedChecklist;

function AcademyPage() {
  const [tree, setTree] = useStateAC(() => LS.get('vig2_ac_tree', 'ATK'));
  const [level, setLevel] = useStateAC(() => LS.get('vig2_ac_level', 45));
  const [view, setView] = useStateAC(() => LS.get('vig2_ac_view', 'total'));
  const [troop, setTroop] = useStateAC('All');
  const [kind, setKind] = useStateAC('All');
  const [q, setQ] = useStateAC('');
  useEffectAC(() => { LS.set('vig2_ac_tree', tree); }, [tree]);
  useEffectAC(() => { LS.set('vig2_ac_level', level); }, [level]);
  useEffectAC(() => { LS.set('vig2_ac_view', view); }, [view]);

  const li = level - 41;
  const acData = useOverride('academy_costs', { COST: AC_COST_DEF, BUILD: AC_BUILD_DEF });
  const AC_COST = acData.COST, AC_BUILD = acData.BUILD;
  const [io, setIo] = useStateAC(false);
  const data = tree === 'ATK' ? AC_ATK : AC_DEF;
  const rows = useMemoAC(() => data.map(r => {
    const vals = r.slice(2);
    const flat = acIsFlat(vals);
    const total = vals[li];
    const gain = li === 0 ? vals[0] : vals[li] - vals[li - 1];
    return { name: r[0], stat: r[1], vals, flat, total, gain, troop: acTroop(r[1]), kind: acKind(r[1]) };
  }), [data, li]);

  const filtered = rows.filter(r =>
    (troop === 'All' || r.troop === troop) &&
    (kind === 'All' || r.kind === kind) &&
    (!q || (r.name + ' ' + r.stat).toLowerCase().includes(q.toLowerCase()))
  );
  const grouped = AC_KINDS.map(k => [k, filtered.filter(r => r.kind === k)]).filter(g => g[1].length);
  const active = rows.filter(r => r.total > 0).length;
  const cost = AC_COST[tree];

  const chip = (on, label, color, onClick, key) => (
    <button key={key || label} onClick={onClick} className={`rounded-lg border px-2.5 py-1.5 text-[12px] font-semibold transition-colors ${on ? 'border-brand bg-brand/10 text-brand' : 'border-zinc-200 text-zinc-500 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-400 dark:hover:bg-zinc-800'}`} style={on && color ? { borderColor: color, color, background: color + '14' } : null}>{label}</button>
  );

  return (
    <div className="space-y-4">
      {/* controls */}
      <Card className="space-y-3.5 p-4">
        <div className="flex flex-wrap items-center gap-x-6 gap-y-3">
          <div>
            <label className="mb-1.5 block text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Research tree</label>
            <Segmented options={[{ value: 'ATK', label: '⚔️ Attack' }, { value: 'DEF', label: '🛡️ Defense' }]} value={tree} onChange={setTree} />
          </div>
          <div className="ml-auto self-start"><DataIOButton onClick={() => setIo(true)} edited={DataIO.has('academy_costs')} /></div>
          <div>
            <label className="mb-1.5 block text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Academy level</label>
            <Segmented options={[41, 42, 43, 44, 45].map(l => ({ value: l, label: String(l) }))} value={level} onChange={setLevel} />
          </div>
          <div>
            <label className="mb-1.5 block text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Show</label>
            <Segmented options={[{ value: 'total', label: 'Total at level' }, { value: 'gain', label: 'Gain this level' }]} value={view} onChange={setView} />
          </div>
        </div>
        <div className="flex flex-wrap items-center gap-1.5">
          {chip(troop === 'All', 'All troops', null, () => setTroop('All'), 'tAll')}
          {AC_TROOPS.map(t => chip(troop === t, t, AC_TROOP_COLOR[t], () => setTroop(troop === t ? 'All' : t), t))}
          {chip(troop === 'Other', 'Other', null, () => setTroop(troop === 'Other' ? 'All' : 'Other'), 'tOther')}
          <span className="mx-1 h-5 w-px bg-zinc-200 dark:bg-zinc-700"></span>
          {chip(kind === 'All', 'All buffs', null, () => setKind('All'), 'kAll')}
          {AC_KINDS.map(k => chip(kind === k, k, null, () => setKind(kind === k ? 'All' : k), 'k' + k))}
          <div className="relative ml-auto">
            <Icon name="search" size={14} className="absolute left-2.5 top-1/2 -translate-y-1/2 text-zinc-400" />
            <input value={q} onChange={e => setQ(e.target.value)} placeholder="Search research…" className="h-9 w-48 rounded-lg border border-zinc-200 bg-white pl-8 pr-2.5 text-[12.5px] outline-none focus:border-brand dark:border-zinc-700 dark:bg-zinc-900" />
          </div>
        </div>
      </Card>

      {/* cost summary */}
      <div className="grid grid-cols-2 gap-3 lg:grid-cols-5">
        <Card className="p-4">
          <div className="text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Researches active</div>
          <div className="mt-1 text-[22px] font-bold tabular-nums text-brand">{active}<span className="text-[13px] font-medium text-zinc-400"> / {rows.length}</span></div>
          <div className="mt-0.5 text-[11px] text-zinc-400">{tree === 'ATK' ? 'Attack' : 'Defense'} tree · level {level}</div>
        </Card>
        <Card className="p-4">
          <div className="text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Research stones</div>
          <div className="mt-1 text-[22px] font-bold tabular-nums text-zinc-900 dark:text-white">{cost.stones[li].toLocaleString()}</div>
          <div className="mt-0.5 text-[11px] text-zinc-400">to research level {level}</div>
        </Card>
        <Card className="p-4">
          <div className="text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Gold</div>
          <div className="mt-1 text-[22px] font-bold tabular-nums" style={{ color: '#ca8a04' }}>{cost.gold[li].toLocaleString()}<span className="text-[13px] font-medium text-zinc-400">M</span></div>
          <div className="mt-0.5 text-[11px] text-zinc-400">research gold cost</div>
        </Card>
        <Card className="p-4">
          <div className="text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Speedups</div>
          <div className="mt-1 text-[22px] font-bold tabular-nums text-zinc-900 dark:text-white">{cost.speed[li].toLocaleString()}<span className="text-[13px] font-medium text-zinc-400">d</span></div>
          <div className="mt-0.5 text-[11px] text-zinc-400">days at 500% research speed</div>
        </Card>
        <Card className="col-span-2 p-4 lg:col-span-1">
          <div className="text-[11px] font-semibold uppercase tracking-wide text-zinc-400">Building RSS · L{level}</div>
          <div className="mt-1.5 grid grid-cols-2 gap-x-3 gap-y-0.5 text-[12px] tabular-nums">
            <span style={{ color: '#16a34a' }}>Food <b>{acFmtB(AC_BUILD.Food[li])}</b></span>
            <span style={{ color: '#a16207' }}>Wood <b>{acFmtB(AC_BUILD.Wood[li])}</b></span>
            <span style={{ color: '#64748b' }}>Stone <b>{acFmtB(AC_BUILD.Stone[li])}</b></span>
            <span style={{ color: '#dc2626' }}>Ore <b>{acFmtB(AC_BUILD.Ore[li])}</b></span>
          </div>
        </Card>
      </div>

      {/* research groups */}
      {grouped.map(([k, list]) => (
        <Card key={k} className="overflow-hidden">
          <div className="flex items-center gap-2 border-b border-zinc-100 px-4 py-2.5 dark:border-zinc-800">
            <Icon name={AC_KIND_ICON[k]} size={15} className="text-brand" />
            <span className="text-[12.5px] font-bold uppercase tracking-wide text-zinc-900 dark:text-white">{k === 'Battle' ? (tree === 'ATK' ? 'Attacking buffs' : 'Defending buffs') : k === 'Single' ? 'Single-type buffs' : k === 'In City' ? 'In-city buffs' : k + (k === 'Debuff' ? 's' : k === 'Rally' ? ' buffs' : '')}</span>
            <span className="text-[11px] text-zinc-400">{list.length}</span>
          </div>
          <div className="divide-y divide-zinc-50 dark:divide-zinc-800/60">
            {list.map((r, i) => {
              const shown = view === 'total' ? r.total : r.gain;
              return (
                <div key={r.name + i} className="flex flex-wrap items-center gap-x-3 gap-y-1 px-4 py-2.5">
                  {r.troop !== 'Other'
                    ? <img src={AC_TROOP_IMG[r.troop]} alt="" className="h-7 w-7 shrink-0 rounded-md" />
                    : <span className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-zinc-100 dark:bg-zinc-800"><Icon name="bolt" size={14} className="text-zinc-400" /></span>}
                  <div className="min-w-0 flex-1">
                    <div className="truncate text-[13px] font-semibold text-zinc-900 dark:text-white">{r.name}</div>
                    <div className="truncate text-[11.5px]" style={{ color: AC_TROOP_COLOR[r.troop] }}>{r.stat}</div>
                  </div>
                  {/* level progression */}
                  <div className="hidden gap-1 sm:flex">
                    {r.vals.map((v, j) => (
                      <div key={j} title={'Level ' + (41 + j) + ': ' + acFmtVal(v, r.flat)}
                        className={`flex h-7 min-w-[44px] items-center justify-center rounded-md px-1 text-[10.5px] font-semibold tabular-nums ${j === li ? 'bg-brand text-white' : v > 0 ? 'bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-400' : 'bg-zinc-50 text-zinc-300 dark:bg-zinc-800/40 dark:text-zinc-600'}`}>
                        {v > 0 ? acFmtVal(v, r.flat) : '—'}
                      </div>
                    ))}
                  </div>
                  <div className="w-20 text-right text-[15px] font-bold tabular-nums" style={{ color: shown > 0 ? '#FF6B00' : '#a1a1aa' }}>
                    {shown > 0 ? (view === 'gain' ? '+' : '') + acFmtVal(shown, r.flat) : '—'}
                  </div>
                </div>
              );
            })}
          </div>
        </Card>
      ))}
      {!grouped.length && <Card className="p-8 text-center text-[13px] text-zinc-400">No researches match these filters.</Card>}

      <ResearchSpeedChecklist />

      {io && <DataIOModal title="Academy costs (levels 41–45)" datasetKey="academy_costs" filename="vig-academy-costs.csv"
        isOverridden={DataIO.has('academy_costs')} onClose={() => setIo(false)}
        currentCSV={toCSV([['Row', 'L41', 'L42', 'L43', 'L44', 'L45'],
          ['ATK Stones', ...AC_COST.ATK.stones], ['ATK Gold', ...AC_COST.ATK.gold], ['ATK Speed', ...AC_COST.ATK.speed],
          ['DEF Stones', ...AC_COST.DEF.stones], ['DEF Gold', ...AC_COST.DEF.gold], ['DEF Speed', ...AC_COST.DEF.speed],
          ['Build Food', ...AC_BUILD.Food], ['Build Wood', ...AC_BUILD.Wood], ['Build Stone', ...AC_BUILD.Stone], ['Build Ore', ...AC_BUILD.Ore]])}
        onImport={rows => {
          const map = {}; rows.slice(1).forEach(r => { map[String(r[0]).trim().toLowerCase()] = r.slice(1, 6).map(x => parseFloat(String(x).replace(/[^\d.-]/g, '')) || 0); });
          const g = k => map[k] && map[k].length === 5 ? map[k] : null;
          const COST = { ATK: { stones: g('atk stones'), gold: g('atk gold'), speed: g('atk speed') }, DEF: { stones: g('def stones'), gold: g('def gold'), speed: g('def speed') } };
          const BUILD = { Food: g('build food'), Wood: g('build wood'), Stone: g('build stone'), Ore: g('build ore') };
          for (const t of ['ATK', 'DEF']) for (const k of ['stones', 'gold', 'speed']) if (!COST[t][k]) COST[t][k] = AC_COST[t][k];
          for (const k of ['Food', 'Wood', 'Stone', 'Ore']) if (!BUILD[k]) BUILD[k] = AC_BUILD[k];
          DataIO.set('academy_costs', { COST, BUILD });
          return { n: rows.length - 1 };
        }} />}

      <p className="px-1 text-[11.5px] text-zinc-400">Cumulative totals per Academy level from the ViG "Academy 41–45" sheet. "Gain this level" shows what each level adds over the previous one. Research costs per tree from Smoken's data (speedup days assume 500% research speed); building upgrade RSS from Theria.</p>
    </div>
  );
}
window.AcademyPage = AcademyPage;
