// WeaveStudy — Origins (oirgin lineup) + Character Sheet (DnDBeyond-inspired)

const { useState: useStateOrigins } = React;

function Origins({ navigate }) {
  const { CHARACTERS } = window.WS_DATA;
  const [filter, setFilter] = useStateOrigins("all");
  const [sort, setSort] = useStateOrigins("popular");

  const filters = [
    { id: "all", label: "전체 PC + 드림주" },
    { id: "oc", label: "OC (자캐)" },
    { id: "dreamju", label: "드림주" },
    { id: "npc", label: "NPC" },
    { id: "wizard", label: "위저드" },
    { id: "sorcerer", label: "소서러" },
    { id: "warlock", label: "워락" },
    { id: "cleric", label: "클래릭" },
    { id: "monk", label: "몽크" },
    { id: "fighter", label: "파이터" },
    { id: "barbarian", label: "바바리안" },
    { id: "rogue", label: "로그" }
  ];

  const list = CHARACTERS.filter(c => {
    if (filter === "all") return !c.isNpc;
    if (filter === "dreamju") return c.isDreamju;
    if (filter === "oc") return !c.isDreamju && !c.isNpc;
    if (filter === "npc") return c.isNpc;
    return c.classKey === filter && !c.isNpc;
  });

  return (
    <main>
      {/* page header */}
      <div style={{ background: "white", borderBottom: "1px solid var(--line-normal)" }}>
        <div className="container" style={{ paddingTop: 48, paddingBottom: 32 }}>
          <div className="sec-eyebrow">ORIGIN LINEUP · 동료 도감</div>
          <h1 style={{ fontSize: 40, fontWeight: 800, margin: "8px 0 8px", letterSpacing: "-0.03em", fontFamily: "var(--font-serif-display)", color: "var(--weave-ink)" }}>
            오리진 라인업
          </h1>
          <p style={{ fontSize: 15, color: "var(--label-neutral)", margin: 0, maxWidth: 640 }}>
            당신의 캠프에 합류한 모든 모험가의 캐릭터 시트.<br />
            드림주 라인 (BG3 공식)과 OC (창작 캐릭터)는 카드 우상단 표기로 구분합니다.
          </p>
        </div>
      </div>

      <div className="container" style={{ paddingTop: 32 }}>
        {/* Filter / sort bar */}
        <div style={{
          display: "flex", alignItems: "center", gap: 12, flexWrap: "wrap",
          padding: "12px 16px",
          background: "var(--cool-neutral-99)",
          borderRadius: 14,
          marginBottom: 24
        }}>
          <Icon name="filter" size={16} color="var(--label-alternative)" />
          {filters.map(f => (
            <button key={f.id} onClick={() => setFilter(f.id)}
                    style={{
                      padding: "6px 14px",
                      borderRadius: 999,
                      background: filter === f.id ? "var(--weave-ink)" : "transparent",
                      color: filter === f.id ? "white" : "var(--label-neutral)",
                      fontSize: 13,
                      fontWeight: 700
                    }}>
              {f.label}
            </button>
          ))}
          <div style={{ marginLeft: "auto", display: "flex", gap: 16, fontSize: 13, color: "var(--label-alternative)" }}>
            <span>총 <strong style={{ color: "var(--weave-ink)" }}>{list.length}</strong>명</span>
            <select value={sort} onChange={e => setSort(e.target.value)}
                    style={{ border: "1px solid var(--line-normal)", borderRadius: 8, padding: "4px 10px", background: "white", fontSize: 13 }}>
              <option value="popular">인기순</option>
              <option value="recent">합류순</option>
              <option value="name">이름순</option>
            </select>
          </div>
        </div>

        {/* 1타 강사진 promo strip */}
        <div style={{
          display: "flex", alignItems: "center", gap: 16,
          background: "linear-gradient(135deg, var(--weave-violet-soft) 0%, var(--weave-teal-soft) 100%)",
          padding: "16px 24px", borderRadius: 14, marginBottom: 24
        }}>
          <div style={{
            background: "white", borderRadius: 6, padding: "4px 8px",
            fontSize: 11, fontWeight: 800, color: "var(--weave-violet-strong)", letterSpacing: "0.06em"
          }}>NOTICE</div>
          <span style={{ fontSize: 13, color: "var(--label-neutral)", fontWeight: 600 }}>
            본 라인업은 졍의 자캐 4명을 기준으로 작성되며, 새 캐릭터가 합류할 때마다 갱신됩니다.
          </span>
          <a style={{ marginLeft: "auto", fontSize: 13, fontWeight: 700, color: "var(--weave-violet-strong)" }}>합류 기록 보기 →</a>
        </div>

        {/* grid */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 20 }}>
          {list.map(ch => <OriginGridCard key={ch.id} character={ch} onClick={() => navigate({ name: "character", id: ch.id })} />)}
        </div>
      </div>
    </main>
  );
}

function OriginGridCard({ character, onClick }) {
  return (
    <button className="card card-hover" onClick={onClick} style={{ textAlign: "left", padding: 0 }}>
      <div style={{ padding: 12 }}>
        <Portrait character={character} size="md" style={{ width: "100%", height: 280 }} />
      </div>
      <div style={{ padding: "4px 16px 20px" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap" }}>
          <span className="badge badge-1ta">{character.rank}</span>
          {character.isDreamju && <span className="badge badge-outline" style={{ fontSize: 10 }}>드림주</span>}
          {character.isNpc && <span className="badge badge-outline" style={{ fontSize: 10, borderColor: "var(--weave-gold)", color: "var(--weave-gold)" }}>NPC</span>}
        </div>
        <div style={{ fontSize: 22, fontWeight: 800, color: "var(--weave-ink)", letterSpacing: "-0.02em" }}>{character.name}</div>
        <div style={{ fontSize: 12, color: "var(--label-alternative)", marginTop: 4 }}>
          {character.race} · {character.class}
        </div>
        <div style={{ marginTop: 12, padding: 12, background: "var(--fill-normal)", borderRadius: 10, fontSize: 13, color: "var(--label-neutral)", lineHeight: 1.5, fontWeight: 600 }}>
          "{character.catchphrase}"
        </div>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap", marginTop: 12 }}>
          <span className="tag tag-violet">{character.bg}</span>
          <span className="tag">{character.alignment}</span>
        </div>
      </div>
    </button>
  );
}

/* ════════════════════════════════════════════════════════════
   CHARACTER SHEET — DnDBeyond-inspired clean layout
   ════════════════════════════════════════════════════════════ */
function CharacterSheet({ id, navigate }) {
  const { CHARACTERS, CAMPAIGNS, ALIGNMENT_GRID } = window.WS_DATA;
  const c = CHARACTERS.find(x => x.id === id);
  const [tab, setTab] = useStateOrigins("profile");
  if (!c) return <div className="container" style={{ padding: 64 }}>캐릭터를 찾을 수 없습니다.</div>;

  const tabs = [
    { id: "profile", label: "프로필" },
    { id: "abilities", label: "능력치" },
    { id: "log", label: "모험 일지" },
    { id: "relations", label: "관계도" },
    { id: "sessions", label: "출연 세션" },
    { id: "gallery", label: "갤러리" }
  ];

  return (
    <main>
      {/* breadcrumb */}
      <div className="container" style={{ paddingTop: 24 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 12, color: "var(--label-alternative)", whiteSpace: "nowrap", flexWrap: "wrap" }}>
          <button onClick={() => navigate({ name: "camp" })} style={{ color: "var(--label-alternative)", whiteSpace: "nowrap" }}>캠프</button>
          <Icon name="chevron-right" size={12} color="var(--label-alternative)" />
          <button onClick={() => navigate({ name: "origins" })} style={{ color: "var(--label-alternative)", whiteSpace: "nowrap" }}>오리진 라인업</button>
          <Icon name="chevron-right" size={12} color="var(--label-alternative)" />
          <span style={{ color: "var(--weave-ink)", fontWeight: 600, whiteSpace: "nowrap" }}>{c.name}</span>
        </div>
      </div>

      {/* hero band — portrait + identity */}
      <div className="container" style={{ paddingTop: 24 }}>
        <div style={{
          background: "white",
          borderRadius: 20,
          border: "1px solid var(--line-normal)",
          padding: 32,
          display: "grid",
          gridTemplateColumns: "320px 1fr",
          gap: 32
        }}>
          <Portrait character={c} size="xl" style={{ width: 320, height: 440 }} />
          <div style={{ display: "flex", flexDirection: "column" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12, flexWrap: "wrap" }}>
              <span className="badge badge-1ta">{c.rank}</span>
              {c.isDreamju && <span className="badge badge-outline">드림주 · BG3 공식</span>}
              {c.isNpc && <span className="badge badge-outline" style={{ borderColor: "var(--weave-gold)", color: "var(--weave-gold)" }}>NPC · 관계도 캐릭터</span>}
              {!c.isDreamju && !c.isNpc && <span className="badge badge-outline" style={{ background: "var(--weave-teal-soft)", borderColor: "var(--weave-teal-deep)", color: "var(--weave-teal-deep)" }}>OC · 창작 캐릭터</span>}
            </div>
            <h1 style={{ fontSize: 48, fontWeight: 800, letterSpacing: "-0.035em", margin: 0, fontFamily: "var(--font-serif-display)", color: "var(--weave-ink)" }}>
              {c.name}
              <span style={{ fontSize: 18, fontWeight: 500, color: "var(--label-alternative)", marginLeft: 12, letterSpacing: 0 }}>{c.nameEn}</span>
            </h1>
            <div style={{ marginTop: 12, padding: "16px 20px", background: "var(--weave-violet-soft)", borderRadius: 12, borderLeft: "3px solid var(--weave-violet)" }}>
              <div style={{ fontSize: 11, fontWeight: 700, color: "var(--weave-violet-strong)", letterSpacing: "0.08em", textTransform: "uppercase", marginBottom: 6 }}>
                CATCHPHRASE
              </div>
              <div style={{ fontSize: 18, fontWeight: 700, color: "var(--weave-ink)", lineHeight: 1.45, letterSpacing: "-0.015em" }}>
                "{c.catchphrase}"
              </div>
              <div style={{ fontSize: 13, color: "var(--label-neutral)", marginTop: 6 }}>{c.catchphraseSub}</div>
            </div>

            {/* Identity grid — DnDBeyond style */}
            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 16, marginTop: 24 }}>
              <IdentBlock label="종족" value={c.race} />
              <IdentBlock label="클래스" value={`${c.class} / ${c.subclass}`} />
              <IdentBlock label="배경" value={c.bg} />
              <IdentBlock label="성향" value={c.alignment} action={() => navigate({ name: "alignment" })} />
              <IdentBlock label="나이" value={c.ageDisplay || (c.age != null ? `${c.age}세` : "??세")} mono />
              <IdentBlock label="플레이어 캐릭터" value={c.pcRole} note={c.pcRoleNote} wide />
            </div>

            <div style={{ marginTop: "auto", paddingTop: 24, display: "flex", gap: 8 }}>
              <button className="btn btn-secondary btn-sm">
                <Icon name="heart-fill" size={14} color="#FF3D5A" /> 좋아요 {c.likes.toLocaleString()}
              </button>
              <button className="btn btn-secondary btn-sm">
                <Icon name="bookmark" size={14} /> 북마크 {c.bookmarks.toLocaleString()}
              </button>
              <button className="btn btn-secondary btn-sm">
                <Icon name="share" size={14} /> 공유
              </button>
              <button className="btn btn-primary btn-sm" style={{ marginLeft: "auto" }}>
                이 캐릭터의 캠페인 보기 →
              </button>
            </div>
          </div>
        </div>
      </div>

      {/* Tabs */}
      <div className="container" style={{ paddingTop: 32 }}>
        <div className="tab-row" style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--line-normal)", overflowX: "auto" }}>
          {tabs.map(t => (
            <button key={t.id} onClick={() => setTab(t.id)}
                    style={{
                      padding: "12px 20px",
                      fontWeight: 700, fontSize: 14,
                      color: tab === t.id ? "var(--weave-ink)" : "var(--label-alternative)",
                      borderBottom: tab === t.id ? "3px solid var(--weave-violet)" : "3px solid transparent",
                      marginBottom: -1,
                      transition: "color 120ms"
                    }}>
              {t.label}
            </button>
          ))}
        </div>
      </div>

      {/* Tab content */}
      <div className="container" style={{ paddingTop: 32, paddingBottom: 32 }}>
        {tab === "profile" && <TabProfile c={c} />}
        {tab === "abilities" && <TabAbilities c={c} />}
        {tab === "log" && <TabLog c={c} />}
        {tab === "relations" && <TabRelations c={c} navigate={navigate} />}
        {tab === "sessions" && <TabSessions c={c} navigate={navigate} />}
        {tab === "gallery" && <TabGallery c={c} />}
      </div>
    </main>
  );
}

function IdentBlock({ label, value, note, mono, wide, action }) {
  return (
    <div style={{
      gridColumn: wide ? "span 2" : "auto",
      padding: 12,
      border: "1px solid var(--line-normal)",
      borderRadius: 10,
      background: "var(--cool-neutral-99)",
      cursor: action ? "pointer" : "default"
    }} onClick={action}>
      <div style={{ fontSize: 10, fontWeight: 700, color: "var(--label-alternative)", letterSpacing: "0.08em", textTransform: "uppercase" }}>
        {label}{action && " ↗"}
      </div>
      <div style={{ fontSize: 14, fontWeight: 700, color: "var(--weave-ink)", marginTop: 4, fontFamily: mono ? "var(--font-mono)" : "inherit" }}>{value}</div>
      {note && <div style={{ fontSize: 11, color: "var(--label-alternative)", marginTop: 2 }}>{note}</div>}
    </div>
  );
}

/* ── Profile tab ── */
function TabProfile({ c }) {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 20 }}>
      <div className="card" style={{ padding: 24 }}>
        <SubHead>외형 묘사</SubHead>
        <p style={{ fontSize: 15, color: "var(--label-neutral)", lineHeight: 1.7, margin: 0 }}>
          {c.appearance}
        </p>
      </div>
      <div className="card" style={{ padding: 24 }}>
        <SubHead>성격</SubHead>
        <p style={{ fontSize: 15, color: "var(--label-neutral)", lineHeight: 1.7, margin: 0 }}>
          {c.personality}
        </p>
      </div>
      <div className="card" style={{ padding: 24, gridColumn: "span 2" }}>
        <SubHead>백스토리 <span style={{ fontSize: 11, color: "var(--label-alternative)", fontWeight: 500, marginLeft: 8 }}>본 사이트 창작 설정</span></SubHead>
        <p style={{ fontSize: 15, color: "var(--label-neutral)", lineHeight: 1.7, margin: 0 }}>
          {c.backstory}
        </p>
      </div>
    </div>
  );
}

/* ── Abilities tab ── DnDBeyond-style ── */
function TabAbilities({ c }) {
  const abilityKeys = ["근력", "민첩", "건강", "지능", "지혜", "매력"];
  const maxAbility = 20;
  const spellSlotLevels = Object.keys(c.spellSlots);

  return (
    <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 20 }}>
      {/* Six ability blocks */}
      <div className="card" style={{ padding: 24, gridColumn: "span 2" }}>
        <SubHead>능력치</SubHead>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(6, 1fr)", gap: 12 }}>
          {abilityKeys.map(k => <AbilityScore key={k} name={k} value={c.abilities[k]} />)}
        </div>

        {/* hex chart */}
        <div style={{ marginTop: 32, display: "flex", justifyContent: "center" }}>
          <AbilityHexChart abilities={c.abilities} />
        </div>
      </div>

      {/* Proficiencies */}
      <div className="card" style={{ padding: 24 }}>
        <SubHead>주요 숙련</SubHead>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
          {c.proficiencies.map(p => (
            <span key={p} style={{
              padding: "8px 14px", background: "var(--weave-ink)", color: "white",
              borderRadius: 8, fontSize: 13, fontWeight: 700, letterSpacing: "-0.01em",
              display: "inline-flex", alignItems: "center", gap: 6
            }}>
              <Icon name="check" size={12} color="white" /> {p}
            </span>
          ))}
        </div>
        <div style={{ marginTop: 20, padding: 14, background: "var(--fill-normal)", borderRadius: 10, fontSize: 12, color: "var(--label-neutral)", lineHeight: 1.6 }}>
          <strong style={{ color: "var(--weave-ink)" }}>참고:</strong> 숙련 보너스는 D&D 5e PHB 기준 캐릭터 레벨에 따라 산정됩니다.
        </div>
      </div>

      {/* Spell slots */}
      {Object.keys(c.spellSlots).length > 0 && (
        <div className="card" style={{ padding: 24 }}>
          <SubHead>주문 슬롯 현황 <span style={{ fontSize: 11, color: "var(--label-alternative)", fontWeight: 500, marginLeft: 8 }}>현재 / 최대</span></SubHead>
          <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
            {spellSlotLevels.map(lvl => (
              <SpellSlotRow key={lvl} level={lvl} count={c.spellSlots[lvl]} used={Math.floor(c.spellSlots[lvl] / 3)} />
            ))}
          </div>
        </div>
      )}
      {Object.keys(c.spellSlots).length === 0 && (
        <div className="card" style={{ padding: 24 }}>
          <SubHead>주문 슬롯 현황</SubHead>
          <div style={{ padding: 16, background: "var(--fill-normal)", borderRadius: 10, fontSize: 13, color: "var(--label-alternative)", lineHeight: 1.6 }}>
            이 클래스는 기본 주문 시전자가 아닙니다. 클래스 고유 자원(분노 횟수 · 기 포인트 · 전투 술수 등)으로 표기됩니다.
          </div>
        </div>
      )}

      {/* Key spells */}
      {c.keySpells.length > 0 && (
        <div className="card" style={{ padding: 24, gridColumn: "span 2" }}>
          <SubHead>주요 주문 목록</SubHead>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
            {c.keySpells.map(s => (
              <div key={s.name} style={{
                padding: 16,
                border: "1px solid var(--line-normal)",
                borderRadius: 12,
                background: "linear-gradient(135deg, white 0%, var(--weave-violet-soft) 200%)"
              }}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start" }}>
                  <div style={{ fontSize: 15, fontWeight: 800, color: "var(--weave-ink)", letterSpacing: "-0.015em" }}>{s.name}</div>
                  <span style={{
                    display: "inline-flex", alignItems: "center", justifyContent: "center",
                    width: 28, height: 28, borderRadius: 8,
                    background: "var(--weave-violet)", color: "white",
                    fontSize: 12, fontWeight: 800, fontFamily: "var(--font-mono)"
                  }}>{s.level}</span>
                </div>
                <div style={{ fontSize: 11, color: "var(--label-alternative)", marginTop: 4, letterSpacing: "0.04em" }}>{s.school}</div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

function AbilityHexChart({ abilities }) {
  // 6-axis radar chart
  const size = 320;
  const center = size / 2;
  const radius = 110;
  const keys = ["근력", "민첩", "건강", "지능", "지혜", "매력"];
  // angle starts at -90 (top), every 60°
  const points = keys.map((k, i) => {
    const angle = -Math.PI / 2 + i * (Math.PI / 3);
    const val = abilities[k] / 20;
    return {
      x: center + Math.cos(angle) * radius * val,
      y: center + Math.sin(angle) * radius * val,
      lx: center + Math.cos(angle) * (radius + 28),
      ly: center + Math.sin(angle) * (radius + 28),
      label: k,
      val: abilities[k]
    };
  });
  const ringPoints = [0.25, 0.5, 0.75, 1.0].map(scale =>
    keys.map((k, i) => {
      const angle = -Math.PI / 2 + i * (Math.PI / 3);
      return `${center + Math.cos(angle) * radius * scale},${center + Math.sin(angle) * radius * scale}`;
    }).join(" ")
  );
  const path = points.map(p => `${p.x},${p.y}`).join(" ");
  return (
    <svg width={size} height={size}>
      {ringPoints.map((p, i) => (
        <polygon key={i} points={p} fill="none" stroke="var(--line-normal)" strokeWidth={1} />
      ))}
      {keys.map((k, i) => {
        const angle = -Math.PI / 2 + i * (Math.PI / 3);
        return (
          <line key={k} x1={center} y1={center}
                x2={center + Math.cos(angle) * radius}
                y2={center + Math.sin(angle) * radius}
                stroke="var(--line-normal)" strokeWidth={1} />
        );
      })}
      <polygon points={path} fill="rgba(101,65,242,0.18)" stroke="var(--weave-violet)" strokeWidth={2.5} strokeLinejoin="round" />
      {points.map(p => (
        <circle key={p.label} cx={p.x} cy={p.y} r={4} fill="var(--weave-violet)" stroke="white" strokeWidth={2} />
      ))}
      {points.map(p => (
        <g key={"l" + p.label}>
          <text x={p.lx} y={p.ly} textAnchor="middle" alignmentBaseline="middle"
                fontSize="12" fontWeight="700" fill="var(--weave-ink)">{p.label}</text>
          <text x={p.lx} y={p.ly + 14} textAnchor="middle" alignmentBaseline="middle"
                fontSize="11" fontWeight="700" fill="var(--weave-violet)" fontFamily="var(--font-mono)">{p.val}</text>
        </g>
      ))}
    </svg>
  );
}

/* ── Log tab ── timeline of acts ── */
function TabLog({ c }) {
  if (!c.arc || c.arc.length === 0) {
    return (
      <div className="card" style={{ padding: 32 }}>
        <SubHead>모험 일지</SubHead>
        <div style={{ padding: 24, background: "var(--fill-normal)", borderRadius: 12, fontSize: 14, color: "var(--label-alternative)", lineHeight: 1.6 }}>
          이 캐릭터는 메인 캐릭터의 관계도에만 등장하는 NPC입니다. 별도의 모험 일지는 없습니다.
        </div>
      </div>
    );
  }
  return (
    <div className="card" style={{ padding: 32 }}>
      <SubHead>모험 일지 <span style={{ fontSize: 11, color: "var(--label-alternative)", fontWeight: 500, marginLeft: 8 }}>캐릭터 아크 (창작 설정)</span></SubHead>
      <div style={{ position: "relative", marginTop: 16, paddingLeft: 28 }}>
        <div style={{ position: "absolute", left: 14, top: 8, bottom: 8, width: 2, background: "linear-gradient(180deg, var(--weave-violet) 0%, var(--weave-teal-deep) 100%)", opacity: 0.4 }} />
        {c.arc.map((a, i) => (
          <div key={i} style={{ position: "relative", paddingBottom: 32 }}>
            <div style={{
              position: "absolute", left: -28, top: 0,
              width: 28, height: 28, borderRadius: 99,
              background: "var(--weave-violet)", color: "white",
              display: "flex", alignItems: "center", justifyContent: "center",
              fontSize: 13, fontWeight: 800, fontFamily: "var(--font-mono)",
              border: "3px solid white",
              boxShadow: "0 0 0 1px var(--weave-violet)"
            }}>{a.act}</div>
            <div style={{ fontSize: 11, fontWeight: 700, color: "var(--weave-violet)", letterSpacing: "0.08em" }}>ACT {a.act}</div>
            <div style={{ fontSize: 20, fontWeight: 800, color: "var(--weave-ink)", letterSpacing: "-0.02em", marginTop: 2 }}>{a.title}</div>
            <p style={{ fontSize: 14, color: "var(--label-neutral)", lineHeight: 1.65, marginTop: 6, marginBottom: 0, maxWidth: 720 }}>
              {a.desc}
            </p>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ── Relations tab ── */
function TabRelations({ c, navigate }) {
  const { CHARACTERS } = window.WS_DATA;
  return (
    <div className="card" style={{ padding: 32 }}>
      <SubHead>관계도 <span style={{ fontSize: 11, color: "var(--label-alternative)", fontWeight: 500, marginLeft: 8 }}>파티 내 관계성</span></SubHead>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 16, marginTop: 8 }}>
        {c.relationships.map(rel => {
          const target = CHARACTERS.find(x => x.id === rel.id);
          if (!target) return null;
          return (
            <button key={rel.id} onClick={() => navigate({ name: "character", id: rel.id })}
                    style={{
                      display: "flex", alignItems: "center", gap: 16,
                      padding: 16,
                      border: "1px solid var(--line-normal)",
                      borderRadius: 14,
                      background: "white", textAlign: "left",
                      cursor: "pointer",
                      transition: "border-color 120ms, box-shadow 120ms"
                    }}
                    onMouseEnter={e => { e.currentTarget.style.borderColor = "var(--weave-violet)"; e.currentTarget.style.boxShadow = "var(--shadow-sm)"; }}
                    onMouseLeave={e => { e.currentTarget.style.borderColor = "var(--line-normal)"; e.currentTarget.style.boxShadow = "none"; }}>
              <div style={{
                width: 56, height: 56, borderRadius: 12,
                background: `linear-gradient(135deg, ${target.portraitColors[0]}, ${target.portraitColors[1]})`,
                color: "white",
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: 22, fontWeight: 800, fontFamily: "var(--font-serif-display)",
                flexShrink: 0
              }}>{target.name[0]}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                  <span style={{ fontSize: 16, fontWeight: 800, color: "var(--weave-ink)" }}>{target.name}</span>
                  <span style={{ fontSize: 11, color: "var(--label-alternative)" }}>{target.class}</span>
                </div>
                <div style={{ fontSize: 12, color: "var(--weave-violet)", fontWeight: 700, marginTop: 4 }}>
                  {rel.label}
                </div>
                <div style={{ fontSize: 13, color: "var(--label-neutral)", marginTop: 4, lineHeight: 1.5 }}>
                  {rel.note}
                </div>
              </div>
              <Icon name="chevron-right" size={16} color="var(--label-alternative)" />
            </button>
          );
        })}
      </div>
    </div>
  );
}

/* ── Sessions tab ── */
function TabSessions({ c, navigate }) {
  const { CAMPAIGNS } = window.WS_DATA;
  const myCampaigns = CAMPAIGNS.filter(cmp => cmp.members.includes(c.id));
  if (myCampaigns.length === 0) {
    return (
      <div className="card" style={{ padding: 32 }}>
        <SubHead>출연 세션</SubHead>
        <div style={{ padding: 24, background: "var(--fill-normal)", borderRadius: 12, fontSize: 14, color: "var(--label-alternative)", lineHeight: 1.6 }}>
          이 캐릭터가 직접 출연한 세션은 아직 없습니다. 관계도 탭을 확인해 보세요.
        </div>
      </div>
    );
  }
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
      {myCampaigns.map(cmp => (
        <div key={cmp.id} className="card" style={{ padding: 24 }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 12 }}>
            <div>
              <div style={{ fontSize: 11, fontWeight: 700, color: "var(--weave-violet)", letterSpacing: "0.08em" }}>CAMPAIGN</div>
              <div style={{ fontSize: 20, fontWeight: 800, color: "var(--weave-ink)", letterSpacing: "-0.02em" }}>{cmp.name}</div>
              <div style={{ fontSize: 12, color: "var(--label-alternative)", marginTop: 2 }}>{cmp.nameSub}</div>
            </div>
            <button className="btn btn-secondary btn-sm" onClick={() => navigate({ name: "campaign", id: cmp.id })}>
              캠페인 보기 →
            </button>
          </div>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {cmp.acts.map(a => (
              <div key={a.act} style={{
                display: "flex", alignItems: "center", gap: 12,
                padding: 12, background: "var(--cool-neutral-99)", borderRadius: 10
              }}>
                <span className="tag tag-ink" style={{ fontSize: 11, padding: "3px 8px" }}>{a.act}막</span>
                <span style={{ flex: 1, fontSize: 14, fontWeight: 700, color: "var(--weave-ink)" }}>{a.title}</span>
                <span style={{ fontSize: 12, color: a.status === "수료" ? "var(--weave-teal-deep)" : a.status === "진행 중" ? "var(--weave-violet)" : "var(--label-alternative)", fontWeight: 700 }}>
                  {a.status}
                </span>
                <span style={{ fontSize: 11, color: "var(--label-alternative)", fontFamily: "var(--font-mono)" }}>
                  {a.sessions.length}회차
                </span>
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

function TabGallery({ c }) {
  return (
    <div className="card" style={{ padding: 32 }}>
      <SubHead>갤러리</SubHead>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 12 }}>
        {Array.from({ length: 8 }).map((_, i) => (
          <div key={i} style={{
            aspectRatio: "3/4",
            background: `linear-gradient(${135 + i * 20}deg, ${c.portraitColors[0]} 0%, ${c.portraitColors[1]} 100%)`,
            borderRadius: 12,
            position: "relative",
            display: "flex", alignItems: "flex-end", padding: 12,
            color: "white"
          }}>
            <div style={{
              position: "absolute", inset: 0,
              backgroundImage: "radial-gradient(circle, rgba(255,255,255,0.15) 1px, transparent 1.5px)",
              backgroundSize: "18px 18px"
            }} />
            <div style={{ position: "relative", fontSize: 11, fontWeight: 700 }}>이미지 #{i + 1}</div>
          </div>
        ))}
      </div>
      <div style={{ marginTop: 16, padding: 14, background: "var(--fill-normal)", borderRadius: 10, fontSize: 12, color: "var(--label-neutral)", lineHeight: 1.6 }}>
        <strong style={{ color: "var(--weave-ink)" }}>이미지 자리</strong> · 실제 일러스트를 업로드하면 이 영역에 표시됩니다.
      </div>
    </div>
  );
}

function SubHead({ children }) {
  return (
    <div style={{
      fontSize: 12, fontWeight: 800, color: "var(--weave-violet)",
      letterSpacing: "0.1em", textTransform: "uppercase",
      marginBottom: 16, display: "flex", alignItems: "center"
    }}>{children}</div>
  );
}

Object.assign(window, { Origins, CharacterSheet });
