/* ============================================================
   Builder wizard — 8 steps
   Props: { char, patch, go } where patch(obj) merges into char.
   ============================================================ */

/* small helpers */
const ABK = ["str","dex","con","int","wis","cha"];
const abilName = (k)=>DND.ABILITIES.find(a=>a.key===k).name;
const abilShort = (k)=>k.toUpperCase();
const roll4d6 = ()=>{ const d=[0,0,0,0].map(()=>1+Math.floor(Math.random()*6)).sort((a,b)=>a-b); return d[1]+d[2]+d[3]; };

/* ---------------- STEP 1: CLASS ---------------- */
function ClassStep({ char, patch }){
  const cls = char.classKey ? DND.klass(char.classKey) : null;
  const lvl = char.level || 1;
  const mcs = char.multiclasses || [];
  const mcTotalLv = mcs.reduce((s, m) => s + (m.level || 1), 0);
  const totalLv = lvl + mcTotalLv;
  const maxPrimaryLv = 20 - mcTotalLv;
  const ORDINALS = ["1st","2nd","3rd","4th"];

  const setLevel = (v)=>{
    const nv = Math.max(1, Math.min(maxPrimaryLv, v));
    const p = { level:nv };
    if (nv < DND.SUBCLASS_LEVEL) p.subclass = null;
    patch(p);
  };
  const patchMC = (i, obj) => {
    patch({ multiclasses: mcs.map((m, idx) => idx === i ? {...m, ...obj} : m) });
  };
  const handleClassClick = (key) => {
    const subClear = { battleMasterManeuvers:[], wildHeartAspect:null, hunterPrey:null, landCircleTerrain:null, draconicAncestry:null, zealotFuryType:null };
    if (key === char.classKey) {
      // Deselect primary — promote first secondary or clear
      if (mcs.length === 0) {
        patch({ classKey:null, subclass:null, classSkills:[], expertise:[], cantrips:[], spells:[], classInstruments:[], monkTool:null, clericOrder:null, clericExtraCantrip:null, druidOrder:null, druidExtraCantrip:null, warlockInvocations:[], ...subClear });
      } else {
        const [promoted, ...rest] = mcs;
        const g = DND.CLASS_DEFAULT_GEAR[promoted.classKey];
        patch({ classKey:promoted.classKey, level:promoted.level, subclass:promoted.subclass,
          multiclasses:rest, classSkills:[], expertise:[], cantrips:[], spells:[],
          classInstruments:[], monkTool:null, clericOrder:null, clericExtraCantrip:null, druidOrder:null, druidExtraCantrip:null, warlockInvocations:[], ...subClear,
          gear: g ? {...g, shield:!!g.shield} : char.gear });
      }
    } else if (mcs.some(m => m.classKey === key)) {
      // Deselect secondary
      patch({ multiclasses: mcs.filter(m => m.classKey !== key) });
    } else if (!char.classKey) {
      // First class — becomes primary
      const g = DND.CLASS_DEFAULT_GEAR[key];
      patch({ classKey:key, subclass:null, classSkills:[], expertise:[], cantrips:[], spells:[],
        classInstruments:[], monkTool:null, clericOrder:null, clericExtraCantrip:null, druidOrder:null, druidExtraCantrip:null, warlockInvocations:[], ...subClear,
        gear: g ? {...g, shield:!!g.shield} : char.gear });
    } else if (totalLv < 20) {
      // Add as secondary
      patch({ multiclasses: [...mcs, { classKey:key, level:1, subclass:null }] });
    }
  };
  const subs = cls ? DND.subclasses(cls.key) : [];
  return (
    <div>
      <StepHeader eyebrow="Step 1 · Class" title="Choose your classes"
        sub="Pick one class — or click multiple to multiclass. Levels split across all chosen classes; total cannot exceed 20." />

      {/* Summary bar — info only, no steppers */}
      {cls && (
        <div className="level-bar">
          <div className="lb-meta">
            <span className="tag">{cls.name} <b className="mono">Lv {lvl}</b></span>
            {mcs.map(mc=>{ const mcCls=DND.klass(mc.classKey); return mcCls ? <span key={mc.classKey} className="tag">{mcCls.name} <b className="mono">Lv {mc.level||1}</b></span> : null; })}
            {mcs.length>0 && <span className="tag">Total <b className="mono">{totalLv}</b></span>}
            <span className="tag">Prof <b className="mono">{DND.fmt(DND.profBonus(totalLv))}</b></span>
            {DND.asiLevelsFor(char.classKey).filter(l=>l<=lvl).length>0 && <span className="tag acc">{DND.asiLevelsFor(char.classKey).filter(l=>l<=lvl).length} ASI/Feat</span>}
            {lvl>=DND.SUBCLASS_LEVEL && <span className="tag acc">Subclass unlocked</span>}
          </div>
        </div>
      )}

      {/* Class card grid — level stepper embedded on selected cards */}
      <div className="opt-grid cols-3" style={{marginTop:22}}>
        {DND.CLASSES.map(c=>{
          const isPrimary = c.key === char.classKey;
          const mcIdx = mcs.findIndex(m => m.classKey === c.key);
          const isSelected = isPrimary || mcIdx >= 0;
          const ordinal = isPrimary ? ORDINALS[0] : mcIdx >= 0 ? ORDINALS[mcIdx+1] : null;
          const blocked = !isSelected && totalLv >= 20;

          // Compute level values for this card's stepper
          const cardLv = isPrimary ? lvl : (mcs[mcIdx]?.level || 1);
          const cardMaxLv = isPrimary
            ? maxPrimaryLv
            : 20 - lvl - mcs.filter((_,j)=>j!==mcIdx).reduce((s,m)=>s+(m.level||1),0);
          const stepDown = () => isPrimary
            ? setLevel(cardLv-1)
            : patchMC(mcIdx,{level:Math.max(1,cardLv-1),subclass:cardLv-1<DND.SUBCLASS_LEVEL?null:mcs[mcIdx].subclass});
          const stepUp = () => isPrimary
            ? setLevel(cardLv+1)
            : patchMC(mcIdx,{level:Math.min(cardMaxLv,cardLv+1)});
          const stepInput = (v) => isPrimary
            ? setLevel(Number(v)||1)
            : patchMC(mcIdx,{level:Math.max(1,Math.min(cardMaxLv,Number(v)||1))});

          return (
            <div key={c.key} style={{position:"relative"}}>
              {isSelected ? (
                /* Selected: div so we can nest interactive stepper inline in o-top */
                <div className="opt sel" style={{textAlign:"left"}}
                  onClick={()=>handleClassClick(c.key)}>
                  <div className="o-top">
                    <span className="o-emb">{c.name[0]}</span>
                    <div style={{flex:1}}>
                      <div className="o-name">{c.name}</div>
                      <div className="o-meta">{`d${c.hd} · ${c.primary.map(abilShort).join("/")}`}</div>
                    </div>
                    <div onClick={e=>e.stopPropagation()}
                      style={{marginLeft:"auto",flexShrink:0,display:"flex",alignItems:"center",gap:2}}>
                      <button onClick={stepDown} disabled={cardLv<=1} style={{width:22,height:22,border:"1px solid var(--line-2)",background:"var(--surface-2)",borderRadius:5,fontSize:13,cursor:cardLv<=1?"default":"pointer",opacity:cardLv<=1?0.35:1,padding:0,color:"var(--ink-2)"}}>−</button>
                      <input type="number" min="1" max={cardMaxLv} value={cardLv}
                        onChange={e=>stepInput(e.target.value)}
                        style={{width:28,height:22,textAlign:"center",fontFamily:"var(--mono)",fontSize:11,fontWeight:700,border:"1px solid var(--line-2)",borderRadius:3,padding:0,boxSizing:"border-box",background:"var(--surface-2)"}} />
                      <button onClick={stepUp} disabled={cardLv>=cardMaxLv} style={{width:22,height:22,border:"1px solid var(--line-2)",background:"var(--surface-2)",borderRadius:5,fontSize:13,cursor:cardLv>=cardMaxLv?"default":"pointer",opacity:cardLv>=cardMaxLv?0.35:1,padding:0,color:"var(--ink-2)"}}>+</button>
                    </div>
                  </div>
                  <div className="o-blurb">{c.blurb}</div>
                  <div className="o-tags">
                    <span className={"tag"+(c.spellcasting?" acc":"")}>{c.spellcasting?"Spellcaster":"Martial"}</span>
                  </div>
                </div>
              ) : (
                <OptionCard
                  emblem={c.name[0]} name={c.name}
                  meta={`d${c.hd} · ${c.primary.map(abilShort).join("/")}`}
                  blurb={c.blurb}
                  tags={[{label:c.spellcasting?"Spellcaster":"Martial",acc:!!c.spellcasting}]}
                  selected={false} noCheck
                  onClick={()=>!blocked && handleClassClick(c.key)}
                />
              )}
              {ordinal && <span style={{position:"absolute",top:8,right:8,background:"var(--accent)",
                color:"#fff",borderRadius:4,fontSize:10,fontWeight:700,padding:"2px 6px",
                fontFamily:"var(--mono)",pointerEvents:"none"}}>{ordinal}</span>}
              {blocked && <span style={{position:"absolute",inset:0,borderRadius:"var(--radius)",
                background:"var(--surface)",opacity:.5,pointerEvents:"none"}}></span>}
            </div>
          );
        })}
      </div>

      {/* Primary class detail */}
      {cls && (
        <div style={{marginTop:26}} className="detail">
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:10}}>
            <h3>{cls.name}</h3>
            <div className="chip-row">
              <span className="tag">Hit Die d{cls.hd}</span>
              <span className="tag">Saves: {cls.saves.map(abilShort).join(", ")}</span>
              <span className="tag">{cls.skillCount} skills{cls.skillList==="any"?" (any)":""}</span>
              {cls.spellcasting && <span className="tag acc">{cls.spellcasting.type} · {abilShort(cls.spellcasting.ability)}</span>}
            </div>
          </div>
          <div className="kv"><span className="k">Armor</span><span className="v">{cls.armor}</span></div>
          <div className="kv"><span className="k">Weapons</span><span className="v">{cls.weapons}</span></div>
          <div style={{marginTop:8}}>
            {cls.features.map((f,i)=>(
              <div className="trait" key={i}><div className="tn">{f.name} <span className="lvtag">Lv 1</span></div><div className="tt">{f.text}</div></div>
            ))}
          </div>
        </div>
      )}

      {/* Bard — Musical Instrument proficiency (3 of choice) */}
      {cls && cls.key==="bard" && (
        <div>
          <SectionCap>Musical Instrument Proficiencies — choose 3 <span style={{float:"right",fontWeight:400,color:(char.classInstruments||[]).length===3?"var(--accent)":"var(--faint)"}}>{(char.classInstruments||[]).length}/3</span></SectionCap>
          <div className="chip-row">
            {DND.INSTRUMENTS.map(n=>{
              const on=(char.classInstruments||[]).includes(n);
              const full=(char.classInstruments||[]).length>=3&&!on;
              return <Chip key={n} label={n} on={on} disabled={full} onClick={()=>patch({classInstruments:on?(char.classInstruments||[]).filter(x=>x!==n):[...(char.classInstruments||[]),n]})} />;
            })}
          </div>
        </div>
      )}

      {/* Monk — Artisan's Tool or Musical Instrument (choose 1) */}
      {cls && cls.key==="monk" && (
        <div>
          <SectionCap>Tool Proficiency — choose one Artisan's Tool or Instrument</SectionCap>
          <div className="hint" style={{marginBottom:6}}>Artisan's Tools</div>
          <div className="chip-row">
            {DND.ARTISAN_TOOLS.map(n=>(
              <Chip key={n} label={n} on={char.monkTool===n} onClick={()=>patch({monkTool:char.monkTool===n?null:n})} />
            ))}
          </div>
          <div className="hint" style={{marginTop:10,marginBottom:6}}>Musical Instruments</div>
          <div className="chip-row">
            {DND.INSTRUMENTS.map(n=>(
              <Chip key={n} label={n} on={char.monkTool===n} onClick={()=>patch({monkTool:char.monkTool===n?null:n})} />
            ))}
          </div>
        </div>
      )}

      {/* Cleric — Divine Order */}
      {cls && cls.key==="cleric" && (
        <div>
          <SectionCap>Divine Order — choose one</SectionCap>
          <div className="opt-grid cols-2">
            {[
              {key:"protector",   name:"Protector",   text:"Gain proficiency with Martial weapons and training with Heavy armor."},
              {key:"thaumaturge", name:"Thaumaturge", text:"Learn one extra Cleric cantrip. Add your full Proficiency Bonus to Arcana and Religion checks."},
            ].map(o=>(
              <button key={o.key} className={"opt"+(char.clericOrder===o.key?" sel":"")} onClick={()=>patch({clericOrder:char.clericOrder===o.key?null:o.key,clericExtraCantrip:null})}>
                <span className="o-check"><Ic.check/></span>
                <div className="o-name" style={{fontSize:15}}>{o.name}</div>
                <div className="o-blurb">{o.text}</div>
              </button>
            ))}
          </div>
          {char.clericOrder==="thaumaturge" && (
            <div style={{marginTop:10}}>
              <div className="hint" style={{marginBottom:6}}>Extra Cleric cantrip — choose one:</div>
              <div className="chip-row">
                {DND.MAGIC_INITIATE["Cleric"].cantrips.map(n=>(
                  <Chip key={n} label={n} on={char.clericExtraCantrip===n} onClick={()=>patch({clericExtraCantrip:char.clericExtraCantrip===n?null:n})} />
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* Druid — Primal Order */}
      {cls && cls.key==="druid" && (
        <div>
          <SectionCap>Primal Order — choose one</SectionCap>
          <div className="opt-grid cols-2">
            {[
              {key:"magician", name:"Magician", text:"Learn one extra cantrip from any spell list. Add your full Proficiency Bonus to Arcana and Nature checks."},
              {key:"warden",   name:"Warden",   text:"Gain proficiency with Martial weapons and training with Medium armor."},
            ].map(o=>(
              <button key={o.key} className={"opt"+(char.druidOrder===o.key?" sel":"")} onClick={()=>patch({druidOrder:char.druidOrder===o.key?null:o.key,druidExtraCantrip:null})}>
                <span className="o-check"><Ic.check/></span>
                <div className="o-name" style={{fontSize:15}}>{o.name}</div>
                <div className="o-blurb">{o.text}</div>
              </button>
            ))}
          </div>
          {char.druidOrder==="magician" && (
            <div style={{marginTop:10}}>
              <div className="hint" style={{marginBottom:6}}>Extra cantrip (any list) — choose one:</div>
              <div className="chip-row">
                {[...new Set([...DND.MAGIC_INITIATE["Cleric"].cantrips,...DND.MAGIC_INITIATE["Druid"].cantrips,...DND.MAGIC_INITIATE["Wizard"].cantrips])].sort().map(n=>(
                  <Chip key={n} label={n} on={char.druidExtraCantrip===n} onClick={()=>patch({druidExtraCantrip:char.druidExtraCantrip===n?null:n})} />
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* Warlock — Eldritch Invocations */}
      {cls && cls.key==="warlock" && (()=>{
        const invCount = DND.warlockInvocationCount(char.level||1);
        const chosen = char.warlockInvocations || [];
        const toggle = (n) => chosen.includes(n)
          ? patch({warlockInvocations:chosen.filter(x=>x!==n)})
          : chosen.length < invCount && patch({warlockInvocations:[...chosen,n]});
        return (
          <div>
            <SectionCap>Eldritch Invocations — choose {invCount} <span style={{float:"right",fontWeight:400,color:chosen.length===invCount?"var(--accent)":"var(--faint)"}}>{chosen.length}/{invCount}</span></SectionCap>
            <div className="feat-pick">
              {DND.ELDRITCH_INVOCATIONS.map(inv=>{
                const locked=inv.minLevel>(char.level||1);
                const on=chosen.includes(inv.name);
                const full=!on&&chosen.length>=invCount;
                return (
                  <button key={inv.name} className={"feat-opt"+(on?" sel":"")}
                    disabled={locked||full} onClick={()=>!locked&&toggle(inv.name)}>
                    <div className="fo-top">
                      <span className="fo-name">{inv.name}</span>
                      {inv.minLevel>1&&<span className="fo-asi">Lv {inv.minLevel}+</span>}
                      {on&&<span className="fo-check"><Ic.check/></span>}
                    </div>
                    <div className="fo-text">{inv.text}</div>
                  </button>
                );
              })}
            </div>
          </div>
        );
      })()}

      {/* Fighting Style — primary */}
      {cls && ["fighter","paladin","ranger"].includes(cls.key) && (
        <div>
          <SectionCap>Fighting Style</SectionCap>
          <div className="feat-pick">
            {DND.FIGHTING_STYLE_FEATS.map(f=>{
              const on = char.fightingStyle===f.name;
              return (
                <button key={f.name} className={"feat-opt"+(on?" sel":"")} onClick={()=>patch({fightingStyle:on?null:f.name})}>
                  <div className="fo-top"><span className="fo-name">{f.name}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div>
                  <div className="fo-text">{f.text}</div>
                </button>
              );
            })}
          </div>
        </div>
      )}

      {/* Primary subclass */}
      {cls && (
        <div>
          <SectionCap>{DND.SUBCLASS_LABEL[cls.key]} {lvl<DND.SUBCLASS_LEVEL && <span style={{color:"var(--faint)",marginLeft:8,textTransform:"none",letterSpacing:0,fontWeight:400}}>· unlocks at level 3</span>}</SectionCap>
          {lvl<DND.SUBCLASS_LEVEL ? (
            <Callout>Set your {cls.name} level to 3 or higher to choose a {DND.SUBCLASS_LABEL[cls.key]}.</Callout>
          ) : (
            <div>
              <div className="opt-grid cols-2">
                {subs.map(s=>(
                  <button key={s.key} className={"opt"+(char.subclass===s.key?" sel":"")} onClick={()=>patch({subclass:char.subclass===s.key?null:s.key, battleMasterManeuvers:[], wildHeartAspect:null, hunterPrey:null, landCircleTerrain:null, draconicAncestry:null, zealotFuryType:null})}>
                    <span className="o-check"><Ic.check/></span>
                    <div className="o-name" style={{fontSize:16}}>{s.name}</div>
                    <div className="o-blurb">{s.blurb}</div>
                  </button>
                ))}
              </div>
              {char.subclass && (()=>{ const sub=DND.subclass(cls.key,char.subclass); return (
                <div className="detail" style={{marginTop:16}}>
                  <h3 style={{fontSize:17}}>{sub.name}</h3>
                  {sub.features.map((f,i)=>(
                    <div className="trait" key={i} style={f.l>lvl?{opacity:.5}:{}}>
                      <div className="tn">{f.name} <span className={"lvtag"+(f.l>lvl?" locked":"")}>Lv {f.l}</span></div>
                      <div className="tt">{f.t}</div>
                    </div>
                  ))}
                </div>
              ); })()}
              {/* Subclass-specific choices */}
              {char.subclass && lvl >= DND.SUBCLASS_LEVEL && (()=>{
                const sub = char.subclass; const clsKey = cls.key;
                // Battle Master maneuvers
                if (clsKey==="fighter" && sub==="battlemaster") {
                  const count=DND.battleMasterManeuverCount(lvl);
                  const chosen=char.battleMasterManeuvers||[];
                  const toggle=(n)=>chosen.includes(n)?patch({battleMasterManeuvers:chosen.filter(x=>x!==n)}):chosen.length<count&&patch({battleMasterManeuvers:[...chosen,n]});
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Battle Master Maneuvers — choose {count} <span style={{float:"right",fontWeight:400,color:chosen.length===count?"var(--accent)":"var(--faint)"}}>{chosen.length}/{count}</span></SectionCap>
                    <div className="feat-pick">
                      {DND.BATTLE_MASTER_MANEUVERS.map(m=>{const on=chosen.includes(m.name);const full=!on&&chosen.length>=count;return(<button key={m.name} className={"feat-opt"+(on?" sel":"")} disabled={full} onClick={()=>toggle(m.name)}><div className="fo-top"><span className="fo-name">{m.name}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div><div className="fo-text">{m.text}</div></button>);})}
                    </div>
                  </div>);
                }
                // Wild Heart Rage aspect
                if (clsKey==="barbarian" && sub==="wildheart") {
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Rage of the Wilds — choose an aspect</SectionCap>
                    <div className="opt-grid cols-3">
                      {DND.WILD_HEART_ASPECTS.map(a=>(<button key={a.key} className={"opt"+(char.wildHeartAspect===a.key?" sel":"")} onClick={()=>patch({wildHeartAspect:char.wildHeartAspect===a.key?null:a.key})}><span className="o-check"><Ic.check/></span><div className="o-name" style={{fontSize:15}}>{a.name}</div><div className="o-blurb">{a.text}</div></button>))}
                    </div>
                  </div>);
                }
                // Zealot Divine Fury type
                if (clsKey==="barbarian" && sub==="zealot") {
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Divine Fury — choose damage type</SectionCap>
                    <div className="opt-grid cols-2">
                      {[{key:"radiant",name:"Radiant",text:"Your Divine Fury adds Radiant damage — fitting a deity of light and order."},{key:"necrotic",name:"Necrotic",text:"Your Divine Fury adds Necrotic damage — fitting a deity of death and darkness."}].map(o=>(<button key={o.key} className={"opt"+(char.zealotFuryType===o.key?" sel":"")} onClick={()=>patch({zealotFuryType:char.zealotFuryType===o.key?null:o.key})}><span className="o-check"><Ic.check/></span><div className="o-name" style={{fontSize:15}}>{o.name}</div><div className="o-blurb">{o.text}</div></button>))}
                    </div>
                  </div>);
                }
                // Hunter's Prey
                if (clsKey==="ranger" && sub==="hunter") {
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Hunter's Prey — choose one</SectionCap>
                    <div className="opt-grid cols-3">
                      {DND.HUNTER_PREY_OPTIONS.map(o=>(<button key={o.key} className={"opt"+(char.hunterPrey===o.key?" sel":"")} onClick={()=>patch({hunterPrey:char.hunterPrey===o.key?null:o.key})}><span className="o-check"><Ic.check/></span><div className="o-name" style={{fontSize:15}}>{o.name}</div><div className="o-blurb">{o.text}</div></button>))}
                    </div>
                  </div>);
                }
                // Circle of the Land terrain
                if (clsKey==="druid" && sub==="land") {
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Land's Circle — choose a terrain</SectionCap>
                    <div className="opt-grid cols-2">
                      {DND.LAND_CIRCLE_TERRAINS.map(t=>(<button key={t.key} className={"opt"+(char.landCircleTerrain===t.key?" sel":"")} onClick={()=>patch({landCircleTerrain:char.landCircleTerrain===t.key?null:t.key})}><span className="o-check"><Ic.check/></span><div className="o-name" style={{fontSize:15}}>{t.name}</div><div className="o-blurb">{t.text}</div></button>))}
                    </div>
                  </div>);
                }
                // Draconic ancestry
                if (clsKey==="sorcerer" && sub==="draconic") {
                  return (<div style={{marginTop:16}}>
                    <SectionCap>Draconic Ancestry — choose a dragon type</SectionCap>
                    <div className="opt-grid cols-2">
                      {DND.DRACONIC_ANCESTORS.map(a=>(<button key={a.key} className={"opt"+(char.draconicAncestry===a.key?" sel":"")} onClick={()=>patch({draconicAncestry:char.draconicAncestry===a.key?null:a.key})}><span className="o-check"><Ic.check/></span><div className="o-name" style={{fontSize:15}}>{a.name}</div><div className="o-blurb">{a.damage} damage</div></button>))}
                    </div>
                  </div>);
                }
                return null;
              })()}
            </div>
          )}
        </div>
      )}

      {/* Secondary/tertiary class details */}
      {mcs.map((mc, i) => {
        const mcCls = DND.klass(mc.classKey); if (!mcCls) return null;
        const mcLv = mc.level || 1;
        const mcSubs = DND.subclasses(mcCls.key);
        const label = ORDINALS[i+1] ? `${ORDINALS[i+1]} class` : "Additional class";
        return (
          <div key={mc.classKey}>
            <div style={{marginTop:26}} className="detail">
              <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:10}}>
                <h3>{mcCls.name} <span style={{color:"var(--faint)",fontWeight:400,fontSize:14}}>· {label}</span></h3>
                <div className="chip-row">
                  <span className="tag">Hit Die d{mcCls.hd}</span>
                  {mcCls.spellcasting && <span className="tag acc">{abilShort(mcCls.spellcasting.ability)}</span>}
                </div>
              </div>
              <div className="kv"><span className="k">Prereq</span><span className="v">{DND.prereqText(mc.classKey)}</span></div>
              <div className="kv"><span className="k">Gains</span><span className="v">{DND.MULTICLASS_PROFS[mc.classKey]}</span></div>
            </div>
            {["fighter","paladin","ranger"].includes(mcCls.key) && (
              <div>
                <SectionCap>Fighting Style · {mcCls.name}</SectionCap>
                <div className="feat-pick">
                  {DND.FIGHTING_STYLE_FEATS.map(f=>{
                    const on = char.fightingStyle===f.name;
                    return (
                      <button key={f.name} className={"feat-opt"+(on?" sel":"")} onClick={()=>patch({fightingStyle:on?null:f.name})}>
                        <div className="fo-top"><span className="fo-name">{f.name}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div>
                        <div className="fo-text">{f.text}</div>
                      </button>
                    );
                  })}
                </div>
              </div>
            )}
            <div>
              <SectionCap>{DND.SUBCLASS_LABEL[mcCls.key]} · {mcCls.name} {mcLv<DND.SUBCLASS_LEVEL && <span style={{color:"var(--faint)",marginLeft:8,textTransform:"none",letterSpacing:0,fontWeight:400}}>· unlocks at level 3</span>}</SectionCap>
              {mcLv<DND.SUBCLASS_LEVEL ? (
                <Callout>Raise {mcCls.name} to level 3 to unlock a {DND.SUBCLASS_LABEL[mcCls.key]}.</Callout>
              ) : (
                <div className="opt-grid cols-2">
                  {mcSubs.map(s=>(
                    <button key={s.key} className={"opt"+(mc.subclass===s.key?" sel":"")}
                      onClick={()=>{ patchMC(i,{subclass:mc.subclass===s.key?null:s.key}); patch({battleMasterManeuvers:[], wildHeartAspect:null, hunterPrey:null, landCircleTerrain:null, draconicAncestry:null, zealotFuryType:null}); }}>
                      <span className="o-check"><Ic.check/></span>
                      <div className="o-name" style={{fontSize:14}}>{s.name}</div>
                      <div className="o-blurb">{s.blurb}</div>
                    </button>
                  ))}
                </div>
              )}
            </div>
          </div>
        );
      })}

    </div>
  );
}

/* ---------------- STEP 2: SPECIES ---------------- */
function SpeciesStep({ char, patch }){
  const sel = char.speciesKey;
  const sp = sel ? DND.species(sel) : null;
  const choice = sp && sp.choice;
  const chosenChoice = choice ? (char.speciesChoice||{})[choice.id] : null;

  // ── Custom Lineage helpers ──
  const DEFAULT_CS = { name:"", size:"Medium", speed:30, darkvision:0, lang:null, skill:null, feat:null, traits:[] };
  const cs = char.customSpecies || DEFAULT_CS;
  const patchCS = (obj) => patch({ customSpecies: {...DEFAULT_CS, ...cs, ...obj} });
  const updateTrait = (i, field, val) => {
    const traits = [...(cs.traits||[])]; traits[i] = {...traits[i], [field]:val};
    patchCS({ traits });
  };
  const addTrait    = () => patchCS({ traits: [...(cs.traits||[]), {name:"", text:""}] });
  const removeTrait = (i) => patchCS({ traits: (cs.traits||[]).filter((_,idx)=>idx!==i) });

  return (
    <div>
      <StepHeader eyebrow="Step 2 · Species" title="Choose a species"
        sub="Your species shapes your body and innate magic — size, speed, senses, and special traits. Pick Custom Lineage to translate any 5e race or homebrew." />
      <div className="opt-grid cols-2" style={{marginTop:26}}>
        {DND.SPECIES.map(s=>(
          <OptionCard key={s.key}
            emblem={s.isCustom ? "+" : s.name[0]}
            name={s.isCustom ? (cs.name || "Custom Lineage") : s.name}
            meta={s.isCustom ? "Any size · custom speed & traits" : `${s.size.split(" ")[0]} · ${s.speed} ft${s.darkvision?` · DV ${s.darkvision}`:""}`}
            blurb={s.blurb}
            tags={s.isCustom ? [{label:"Custom / Homebrew"}] : (s.choice?[{label:s.choice.label, acc:true}]:[]).concat(s.darkvision?[{label:"Darkvision"}]:[])}
            selected={sel===s.key}
            onClick={()=>{
              if (s.isCustom) {
                patch({ speciesKey:"custom", speciesChoice:{}, elfKeenSense:null, humanSkill:null,
                  speciesLangs: [], customSpecies: char.customSpecies || {...DEFAULT_CS} });
              } else {
                const defLangs = s.lang ? ["Common", s.lang] : ["Common"];
                patch({ speciesKey:s.key, speciesChoice:{}, elfKeenSense:null, humanSkill:null, humanLang:null, speciesLangs: defLangs });
              }
            }}
          />
        ))}
      </div>

      {/* ── Standard species detail ── */}
      {sp && !sp.isCustom && (
        <div style={{marginTop:26}} className="detail">
          <div style={{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:10}}>
            <h3>{sp.name}</h3>
            <div className="chip-row">
              <span className="tag">{sp.size}</span>
              <span className="tag">Speed {sp.speed} ft</span>
              {sp.darkvision>0 && <span className="tag">Darkvision {sp.darkvision} ft</span>}
            </div>
          </div>
          <div className="kv"><span className="k">Languages</span><span className="v">Common{sp.lang?`, ${sp.lang}`:`, + one of your choice`}</span></div>
          <div style={{marginTop:6}}>
            {sp.traits.map((t,i)=>(
              <div className="trait" key={i}><div className="tn">{t.name}</div><div className="tt">{t.text}</div></div>
            ))}
          </div>
          {choice && (
            <div style={{marginTop:18}}>
              <SectionCap>{choice.label}</SectionCap>
              <div className="opt-grid cols-3">
                {choice.options.map(o=>(
                  <button key={o.key} className={"opt"+(chosenChoice===o.key?" sel":"")}
                    onClick={()=>patch({ speciesChoice:{...(char.speciesChoice||{}), [choice.id]:o.key} })}>
                    <span className="o-check"><Ic.check/></span>
                    <div className="o-name" style={{fontSize:15}}>{o.name}</div>
                    {o.note && <div className="o-blurb">{o.note}</div>}
                  </button>
                ))}
              </div>
            </div>
          )}
          {sp.key==="elf" && (
            <div style={{marginTop:18}}>
              <SectionCap>Keen Senses — choose a skill</SectionCap>
              <div className="chip-row">
                {["insight","perception","survival"].map(k=>(
                  <Chip key={k} label={DND.skillName(k)} on={char.elfKeenSense===k}
                    onClick={()=>patch({ elfKeenSense: char.elfKeenSense===k?null:k })} />
                ))}
              </div>
            </div>
          )}
          {sp.key==="human" && (
            <div style={{marginTop:18}}>
              <SectionCap>Skillful — choose a skill</SectionCap>
              <div className="chip-row">
                {DND.SKILLS.map(s=>(
                  <Chip key={s.key} label={s.name} on={char.humanSkill===s.key}
                    onClick={()=>patch({ humanSkill: char.humanSkill===s.key?null:s.key })} />
                ))}
              </div>
              <SectionCap>Versatile — choose an Origin feat</SectionCap>
              <div className="feat-pick">
                {DND.ORIGIN_FEATS.map(f=>{
                  const on = char.humanFeat===f;
                  return (
                    <button key={f} className={"feat-opt"+(on?" sel":"")}
                      onClick={()=>patch({ humanFeat: on?null:f })}>
                      <div className="fo-top"><span className="fo-name">{f}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div>
                      <div className="fo-text">{DND.FEATS[f]}</div>
                    </button>
                  );
                })}
              </div>
            </div>
          )}
          {/* Generic language picker — all standard species */}
          {(()=>{
            const srdNote = sp.lang ? `Common and ${sp.lang}` : sp.key==="human" ? "Common and one language of your choice" : "Common";
            const langs = char.speciesLangs || [];
            const toggle = (l) => patch({ speciesLangs: langs.includes(l) ? langs.filter(x=>x!==l) : [...langs, l] });
            return (
              <div style={{marginTop:18}}>
                <SectionCap>Languages</SectionCap>
                <div className="hint" style={{marginBottom:7}}>SRD default: <b>{srdNote}</b> — select freely below.</div>
                <div className="hint" style={{marginBottom:5}}>Standard</div>
                <div className="chip-row">
                  {DND.LANGUAGES.standard.map(l=>(
                    <Chip key={l} label={l} on={langs.includes(l)} onClick={()=>toggle(l)} />
                  ))}
                </div>
                <div className="hint" style={{marginTop:8,marginBottom:5}}>Rare</div>
                <div className="chip-row">
                  {DND.LANGUAGES.rare.map(l=>(
                    <Chip key={l} label={l} on={langs.includes(l)} onClick={()=>toggle(l)} />
                  ))}
                </div>
              </div>
            );
          })()}
          {sp.legacyAbilityChoice && (
            <div style={{marginTop:18}}>
              <SectionCap>Fiendish Legacy — spellcasting ability</SectionCap>
              <div className="chip-row">
                {["int","wis","cha"].map(k=>(
                  <Chip key={k} label={abilName(k)} on={char.legacyAbility===k}
                    onClick={()=>patch({ legacyAbility:k })} />
                ))}
              </div>
            </div>
          )}
        </div>
      )}

      {/* ── Custom Lineage builder ── */}
      {sp && sp.isCustom && (
        <div style={{marginTop:26}} className="detail">
          {/* Name */}
          <div style={{marginBottom:20}}>
            <div className="hint" style={{marginBottom:7}}>Species / Lineage name</div>
            <input type="text" placeholder="e.g. Githyanki, Air Genasi, Harengon…"
              value={cs.name} onChange={e=>patchCS({name:e.target.value})}
              style={{fontSize:18,fontFamily:"var(--serif)",fontWeight:600}} />
          </div>

          {/* Stats row */}
          <div style={{display:"grid",gridTemplateColumns:"1fr 1fr 1fr",gap:18,marginBottom:18}} className="loadout-grid">
            <div>
              <div className="hint" style={{marginBottom:7}}>Size</div>
              <div className="chip-row">
                {["Small","Medium","Large"].map(sz=>(
                  <Chip key={sz} label={sz} on={(cs.size||"Medium")===sz} onClick={()=>patchCS({size:sz})} />
                ))}
              </div>
            </div>
            <div>
              <div className="hint" style={{marginBottom:7}}>Speed</div>
              <div className="lvl-stepper">
                <button onClick={()=>patchCS({speed:Math.max(5,(cs.speed||30)-5)})}>−</button>
                <input type="number" min="5" max="60" value={cs.speed||30}
                  onChange={e=>patchCS({speed:Math.max(5,Math.min(60,Number(e.target.value)||30))})} />
                <button onClick={()=>patchCS({speed:Math.min(60,(cs.speed||30)+5)})}>+</button>
              </div>
              <div style={{fontSize:11,color:"var(--faint)",marginTop:4}}>ft.</div>
            </div>
            <div>
              <div className="hint" style={{marginBottom:7}}>Darkvision</div>
              <div className="chip-row">
                {[0,60,120].map(d=>(
                  <Chip key={d} label={d===0?"None":`${d} ft`} on={(cs.darkvision||0)===d} onClick={()=>patchCS({darkvision:d})} />
                ))}
              </div>
            </div>
          </div>

          {/* Language — multi-select, stored on char.speciesLangs */}
          <SectionCap>Languages <span style={{fontWeight:400,color:"var(--faint)"}}>— choose per your lineage's lore</span></SectionCap>
          <div className="hint" style={{marginBottom:5}}>Standard</div>
          <div className="chip-row">
            {DND.LANGUAGES.standard.map(l=>{
              const on=(char.speciesLangs||[]).includes(l);
              return <Chip key={l} label={l} on={on} onClick={()=>patch({speciesLangs:on?(char.speciesLangs||[]).filter(x=>x!==l):[...(char.speciesLangs||[]),l]})} />;
            })}
          </div>
          <div className="hint" style={{marginTop:8,marginBottom:5}}>Rare</div>
          <div className="chip-row">
            {DND.LANGUAGES.rare.map(l=>{
              const on=(char.speciesLangs||[]).includes(l);
              return <Chip key={l} label={l} on={on} onClick={()=>patch({speciesLangs:on?(char.speciesLangs||[]).filter(x=>x!==l):[...(char.speciesLangs||[]),l]})} />;
            })}
          </div>

          {/* Bonus Proficiencies — skills and/or tools, multi-select */}
          <SectionCap>Bonus Proficiencies <span style={{fontWeight:400,color:"var(--faint)"}}>— optional</span></SectionCap>
          <div className="hint" style={{marginBottom:5}}>Skills</div>
          <div className="chip-row">
            {DND.SKILLS.map(s=>{
              const on=(cs.proficiencies||[]).includes(s.key);
              return <Chip key={s.key} label={s.name} on={on}
                onClick={()=>patchCS({proficiencies:on?(cs.proficiencies||[]).filter(k=>k!==s.key):[...(cs.proficiencies||[]),s.key]})} />;
            })}
          </div>
          <div className="hint" style={{marginTop:8,marginBottom:5}}>Tools</div>
          <div className="chip-row">
            {Object.entries(DND.TOOLS).map(([k,name])=>{
              const on=(cs.proficiencies||[]).includes(k);
              return <Chip key={k} label={name} on={on}
                onClick={()=>patchCS({proficiencies:on?(cs.proficiencies||[]).filter(x=>x!==k):[...(cs.proficiencies||[]),k]})} />;
            })}
          </div>

          {/* Origin feat */}
          <SectionCap>Origin feat <span style={{fontWeight:400,color:"var(--faint)"}}>— optional</span></SectionCap>
          <div className="feat-pick">
            {DND.ORIGIN_FEATS.map(f=>{
              const on=cs.feat===f;
              return (
                <button key={f} className={"feat-opt"+(on?" sel":"")} onClick={()=>patchCS({feat:on?null:f})}>
                  <div className="fo-top"><span className="fo-name">{f}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div>
                  <div className="fo-text">{DND.FEATS[f]}</div>
                </button>
              );
            })}
          </div>

          {/* Traits */}
          <SectionCap>Traits</SectionCap>
          {(cs.traits||[]).map((t,i)=>(
            <div key={i} style={{marginBottom:10,padding:"12px 14px",background:"var(--surface-2)",borderRadius:8,position:"relative"}}>
              <input type="text" placeholder="Trait name" value={t.name}
                onChange={e=>updateTrait(i,"name",e.target.value)}
                style={{fontWeight:600,marginBottom:8}} />
              <textarea rows={3} placeholder="Description…" value={t.text}
                onChange={e=>updateTrait(i,"text",e.target.value)}
                style={{fontSize:13,resize:"vertical",marginBottom:8}} />
              <div style={{display:"flex",alignItems:"center",gap:5,flexWrap:"wrap"}}>
                <span style={{fontSize:11,color:"var(--faint)",marginRight:2}}>Action economy:</span>
                {[{val:null,label:"None"},{val:"action",label:"Action"},{val:"bonus",label:"Bonus Action"},{val:"reaction",label:"Reaction"}].map(opt=>(
                  <button key={String(opt.val)}
                    className={"btn"+(t.action===opt.val?" primary":"")}
                    style={{fontSize:11,padding:"2px 8px"}}
                    onClick={()=>updateTrait(i,"action",opt.val)}>
                    {opt.label}
                  </button>
                ))}
              </div>
              <button onClick={()=>removeTrait(i)}
                style={{position:"absolute",top:8,right:8,fontSize:11,padding:"2px 8px"}}
                className="btn">✕</button>
            </div>
          ))}
          <button className="btn" style={{marginTop:4}} onClick={addTrait}>+ Add trait</button>
        </div>
      )}
    </div>
  );
}

/* ---------------- STEP 3: BACKGROUND ---------------- */
function BackgroundStep({ char, patch }){
  const sel = char.backgroundKey;
  const bg = sel === "custom" ? DND.resolvedBg(char) : (sel ? DND.background(sel) : null);

  const DEFAULT_CB = { name:"", blurb:"", abilities:[], feat:null, skills:[], tool:null, equipment:"" };
  const cb = char.customBackground || DEFAULT_CB;
  const patchCB = (obj) => patch({ customBackground: {...DEFAULT_CB, ...cb, ...obj} });

  const ASI_CLEAR = { asi:{str:0,dex:0,con:0,int:0,wis:0,cha:0}, asiMode:null, asiPrimary:null, asiSecondary:null };
  const FEAT_CLEAR = { bonusSkills:[], bonusTools:[], crafterTools:[], musicianInstruments:[], magicInitiateCantrips:[], magicInitiateSpell:null };

  return (
    <div>
      <StepHeader eyebrow="Step 3 · Background" title="Choose a background"
        sub="Your background is who you were before adventuring. In 2024 it carries real weight: ability score increases, an Origin feat, two skills, a tool, and starting gear." />
      <div className="opt-grid cols-3" style={{marginTop:26}}>
        {DND.BACKGROUNDS.map(b=>(
          <OptionCard key={b.key}
            emblem={b.isCustom ? "+" : b.name[0]}
            name={b.isCustom ? (cb.name || "Custom Background") : b.name}
            meta={b.isCustom ? "Any abilities · custom skills & feat" : b.abilities.map(abilShort).join(" · ")}
            blurb={b.blurb}
            tags={b.isCustom ? [{label:"Custom / Homebrew"}] : [ {label:b.feat, acc:true} ]}
            selected={sel===b.key}
            onClick={()=>patch({ backgroundKey:b.key, ...ASI_CLEAR, ...FEAT_CLEAR,
              customBackground: b.isCustom ? (char.customBackground || {...DEFAULT_CB}) : null })}
          />
        ))}
      </div>
      {bg && (
        <div style={{marginTop:26}} className="detail">
          {bg.isCustom ? (
            /* ── Custom Background builder ── */
            <div>
              <div style={{marginBottom:20}}>
                <div className="hint" style={{marginBottom:7}}>Background name</div>
                <input type="text" placeholder="e.g. Street Herbalist, Disgraced Noble, Sea Witch…"
                  value={cb.name} onChange={e=>patchCB({name:e.target.value})}
                  style={{fontSize:18,fontFamily:"var(--serif)",fontWeight:600}} />
              </div>

              {/* Abilities — choose 3 for ASI pool */}
              <SectionCap>Ability Score Increases — choose 3 <span style={{fontWeight:400,color:"var(--faint)",marginLeft:8}}>which abilities can this background raise?</span></SectionCap>
              <div className="chip-row">
                {DND.ABILITIES.map(a=>{
                  const on=(cb.abilities||[]).includes(a.key);
                  const full=!on&&(cb.abilities||[]).length>=3;
                  return <Chip key={a.key} label={a.name} on={on} disabled={full}
                    onClick={()=>patchCB({abilities:on?(cb.abilities||[]).filter(x=>x!==a.key):[...(cb.abilities||[]),a.key], ...ASI_CLEAR})} />;
                })}
              </div>

              {/* Skills — choose 2 */}
              <SectionCap>Skills — choose 2 <span style={{float:"right",fontWeight:400,color:(cb.skills||[]).length===2?"var(--accent)":"var(--faint)"}}>{(cb.skills||[]).length}/2</span></SectionCap>
              <div className="chip-row">
                {DND.SKILLS.map(s=>{
                  const on=(cb.skills||[]).includes(s.key);
                  const full=!on&&(cb.skills||[]).length>=2;
                  return <Chip key={s.key} label={s.name} on={on} disabled={full}
                    onClick={()=>patchCB({skills:on?(cb.skills||[]).filter(x=>x!==s.key):[...(cb.skills||[]),s.key]})} />;
                })}
              </div>

              {/* Tool — choose 1 */}
              <SectionCap>Tool Proficiency — choose 1</SectionCap>
              <div className="chip-row">
                {Object.entries(DND.TOOLS).map(([k,name])=>(
                  <Chip key={k} label={name} on={cb.tool===k}
                    onClick={()=>patchCB({tool:cb.tool===k?null:k})} />
                ))}
              </div>

              {/* Origin Feat */}
              <SectionCap>Origin Feat — choose 1</SectionCap>
              <div className="feat-pick">
                {DND.ORIGIN_FEATS.map(f=>{
                  const on=cb.feat===f;
                  return (
                    <button key={f} className={"feat-opt"+(on?" sel":"")}
                      onClick={()=>patchCB({feat:on?null:f})}>
                      <div className="fo-top"><span className="fo-name">{f}</span>{on&&<span className="fo-check"><Ic.check/></span>}</div>
                      <div className="fo-text">{DND.FEATS[f]}</div>
                    </button>
                  );
                })}
              </div>

              {/* Equipment — free text */}
              <SectionCap>Starting Equipment <span style={{fontWeight:400,color:"var(--faint)"}}>— optional description</span></SectionCap>
              <input type="text" placeholder="e.g. Herbalism Kit, Leather Satchel, 20 GP…"
                value={cb.equipment||""} onChange={e=>patchCB({equipment:e.target.value})}
                style={{fontSize:13}} />
            </div>
          ) : (
            /* ── Standard background summary ── */
            <div>
              <h3>{bg.name}</h3>
              <div className="kv"><span className="k">Ability Scores</span><span className="v">{bg.abilities.map(abilName).join(", ")} <span style={{color:"var(--faint)"}}>— set in the next step</span></span></div>
              <div className="kv"><span className="k">Origin Feat</span><span className="v">{bg.feat}</span></div>
              <div className="kv"><span className="k">Skills</span><span className="v">{bg.skills.map(DND.skillName).join(", ")}</span></div>
              <div className="kv"><span className="k">Tool</span><span className="v">{DND.TOOLS[bg.tool]}</span></div>
              <div className="kv"><span className="k">Equipment</span><span className="v">{bg.equipment} <span style={{color:"var(--faint)"}}>— or 50 GP</span></span></div>
              <div className="trait" style={{marginTop:8}}>
                <div className="tn">{bg.feat}</div>
                <div className="tt">{DND.FEATS[bg.feat]}</div>
              </div>
            </div>
          )}
          {bg.feat === "Crafter" && (() => {
            const crafterTools = char.crafterTools || [];
            const toggle = (n) => crafterTools.includes(n)
              ? patch({ crafterTools: crafterTools.filter(t => t !== n) })
              : crafterTools.length < 3 && patch({ crafterTools: [...crafterTools, n] });
            return (
              <div style={{marginTop:16}}>
                <SectionCap>Crafter — choose 3 Artisan's Tools <span style={{float:"right",fontWeight:400,color:crafterTools.length===3?"var(--accent)":"var(--faint)"}}>{crafterTools.length}/3</span></SectionCap>
                <div className="chip-row">
                  {DND.ARTISAN_TOOLS.map(n => (
                    <Chip key={n} label={n} on={crafterTools.includes(n)}
                      disabled={!crafterTools.includes(n) && crafterTools.length >= 3}
                      onClick={() => toggle(n)} />
                  ))}
                </div>
              </div>
            );
          })()}
          {bg.feat === "Musician" && (() => {
            const instruments = char.musicianInstruments || [];
            const toggle = (n) => instruments.includes(n)
              ? patch({ musicianInstruments: instruments.filter(t => t !== n) })
              : instruments.length < 3 && patch({ musicianInstruments: [...instruments, n] });
            return (
              <div style={{marginTop:16}}>
                <SectionCap>Musician — choose 3 instruments <span style={{float:"right",fontWeight:400,color:instruments.length===3?"var(--accent)":"var(--faint)"}}>{instruments.length}/3</span></SectionCap>
                <div className="chip-row">
                  {DND.INSTRUMENTS.map(n => (
                    <Chip key={n} label={n} on={instruments.includes(n)}
                      disabled={!instruments.includes(n) && instruments.length >= 3}
                      onClick={() => toggle(n)} />
                  ))}
                </div>
              </div>
            );
          })()}
          {bg.feat && bg.feat.startsWith("Magic Initiate") && (() => {
            const clsName = bg.feat.match(/\((\w+)\)/)?.[1];
            const miData = DND.MAGIC_INITIATE?.[clsName];
            if (!miData) return null;
            const miCantrips = char.magicInitiateCantrips || [];
            const miSpell = char.magicInitiateSpell || null;
            const toggleCantrip = (n) => miCantrips.includes(n)
              ? patch({ magicInitiateCantrips: miCantrips.filter(c => c !== n) })
              : miCantrips.length < 2 && patch({ magicInitiateCantrips: [...miCantrips, n] });
            return (
              <div style={{marginTop:16}}>
                <SectionCap>{clsName} Cantrips — choose 2 <span style={{float:"right",fontWeight:400,color:miCantrips.length===2?"var(--accent)":"var(--faint)"}}>{miCantrips.length}/2</span></SectionCap>
                <div className="chip-row">
                  {miData.cantrips.map(n => (
                    <Chip key={n} label={n} on={miCantrips.includes(n)}
                      disabled={!miCantrips.includes(n) && miCantrips.length >= 2}
                      onClick={() => toggleCantrip(n)} />
                  ))}
                </div>
                <SectionCap style={{marginTop:10}}>{clsName} Level-1 Spell — choose 1 <span style={{float:"right",fontWeight:400,color:miSpell?"var(--accent)":"var(--faint)"}}>{miSpell?"1/1":"0/1"}</span></SectionCap>
                <div className="chip-row">
                  {miData.spells.map(n => (
                    <Chip key={n} label={n} on={miSpell===n}
                      onClick={() => patch({ magicInitiateSpell: miSpell===n ? null : n })} />
                  ))}
                </div>
              </div>
            );
          })()}
          {bg.feat === "Skilled" && (() => {
            const bonusSkills = char.bonusSkills || [];
            const bonusTools = char.bonusTools || [];
            const chosen = bonusSkills.length + bonusTools.length;
            // All skills already proficient from any source other than the Skilled choices
            const alreadyGranted = new Set([...DND.skillProfs(char)].filter(k => !bonusSkills.includes(k)));
            const toggleSkill = (k) => {
              if (bonusSkills.includes(k)) patch({ bonusSkills: bonusSkills.filter(s => s !== k) });
              else if (chosen < 3) patch({ bonusSkills: [...bonusSkills, k] });
            };
            const toggleTool = (k) => {
              if (bonusTools.includes(k)) patch({ bonusTools: bonusTools.filter(t => t !== k) });
              else if (chosen < 3) patch({ bonusTools: [...bonusTools, k] });
            };
            return (
              <div style={{marginTop:16}}>
                <SectionCap>
                  Skilled — choose 3 proficiencies
                  <span style={{float:"right",fontWeight:400,color:chosen===3?"var(--accent)":"var(--faint)"}}>{chosen}/3</span>
                </SectionCap>
                <div className="hint" style={{marginBottom:7}}>Skills</div>
                <div className="chip-row">
                  {DND.SKILLS.map(s => {
                    const locked = alreadyGranted.has(s.key);
                    return (
                      <Chip key={s.key} label={s.name}
                        on={locked || bonusSkills.includes(s.key)}
                        disabled={locked || (!bonusSkills.includes(s.key) && chosen >= 3)}
                        onClick={() => toggleSkill(s.key)} />
                    );
                  })}
                </div>
                <div className="hint" style={{marginTop:10,marginBottom:7}}>Tools</div>
                <div className="chip-row">
                  {Object.entries(DND.TOOLS).map(([k, name]) => (
                    <Chip key={k} label={name}
                      on={bonusTools.includes(k)}
                      disabled={!bonusTools.includes(k) && chosen >= 3}
                      onClick={() => toggleTool(k)} />
                  ))}
                </div>
              </div>
            );
          })()}
          <SectionCap>Language — choose one</SectionCap>
          <div className="hint" style={{marginBottom:7}}>Standard</div>
          <div className="chip-row">
            {DND.LANGUAGES.standard.map(l=>(
              <Chip key={l} label={l} on={char.bgLang===l} onClick={()=>patch({bgLang:char.bgLang===l?null:l})} />
            ))}
          </div>
          <div className="hint" style={{marginTop:10,marginBottom:7}}>Rare</div>
          <div className="chip-row">
            {DND.LANGUAGES.rare.map(l=>(
              <Chip key={l} label={l} on={char.bgLang===l} onClick={()=>patch({bgLang:char.bgLang===l?null:l})} />
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, { ClassStep, SpeciesStep, BackgroundStep, ABK, abilName, abilShort, roll4d6 });
