// IAMScouting — shared UI primitives
// All components global via window.* (Babel script-scope rule)

const { useState, useEffect, useMemo, useRef, useCallback } = React;

// Fit score color helper
function fitColor(n) {
  if (n >= 80) return "var(--good)";
  if (n >= 60) return "var(--mid)";
  if (n >= 40) return "#c67a1a";
  return "var(--bad)";
}

// Fit band label
function fitLabel(n) {
  if (n >= 85) return "Strong fit";
  if (n >= 70) return "Good fit";
  if (n >= 55) return "Moderate";
  if (n >= 40) return "Weak";
  return "Poor";
}

// Small logo / wordmark — themes give it different treatment via CSS
function Wordmark({ size = 18 }) {
  return (
    <span className="wordmark" style={{
      display: "inline-flex", alignItems: "center", gap: 8,
      fontFamily: "var(--display)",
      fontSize: size, fontWeight: 600, letterSpacing: "-0.02em",
      color: "var(--ink)",
    }}>
      <span style={{
        width: size * 0.9, height: size * 0.9,
        display: "inline-block",
        background: "var(--accent)",
        borderRadius: "var(--radius)",
        position: "relative",
      }}>
        <span style={{
          position: "absolute", inset: 3,
          border: "2px solid var(--accent-ink)",
          borderRadius: "50%",
        }}/>
        <span style={{
          position: "absolute", left: "50%", top: "50%",
          width: 2, height: size * 0.5,
          background: "var(--accent-ink)",
          transform: "translate(-50%, -50%) rotate(25deg)",
        }}/>
      </span>
      <span>IAMScouting</span>
    </span>
  );
}

// Chrome bar at top of each screen (shown after landing)
function AppChrome({ screen, onNav, clubName }) {
  const tabs = [
    { id: "dashboard", label: "Dashboard" },
    { id: "analysis",  label: "Club Analysis" },
    { id: "map",       label: "World Map" },
    { id: "camelot",   label: "Camelot" },
    { id: "shadow",    label: "Shadow Team" },
    { id: "list",      label: "Shortlist" },
    { id: "profile",   label: "Club Profile" },
  ];

  // XP / Trust readout — the gamification hook in the chrome
  const D = window.IAMS_DATA;
  const xp    = D?.clubXP ? D.clubXP({}).xp : 420;
  const trust = D?.trustFor ? D.trustFor(xp) : null;

  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 22,
      padding: "12px 28px",
      borderBottom: "1px solid var(--rule)",
      background: "var(--panel)",
    }}>
      <Wordmark size={16}/>
      <div style={{ width: 1, height: 18, background: "var(--rule-strong)", opacity: .5 }}/>
      <nav style={{ display: "flex", gap: 2 }}>
        {tabs.map(t => (
          <button key={t.id}
            onClick={() => onNav(t.id)}
            className={screen === t.id ? "on" : ""}
            style={{
              padding: "6px 10px",
              fontSize: 12.5,
              color: screen === t.id ? "var(--ink)" : "var(--ink-muted)",
              borderBottom: screen === t.id ? "2px solid var(--accent)" : "2px solid transparent",
            }}>{t.label}</button>
        ))}
      </nav>
      <div style={{ flex: 1 }}/>
      {trust && <XpBar xp={xp} trust={trust} compact/>}
      <div className="mono" style={{ fontSize: 11, color: "var(--ink-muted)", letterSpacing: "0.06em", textTransform: "uppercase" }}>
        {clubName || "Pilot Club"}
      </div>
      <AuthBadge/>
    </div>
  );
}

// Shows the currently signed-in email (if any), falling back to a "Sign in" link.
// Pulls the session from /api/session at mount — no Supabase SDK in the prototype.
function AuthBadge() {
  const [session, setSession] = useState(null); // null = unknown, {email:null} = anon, {email:...} = authed

  useEffect(() => {
    let cancelled = false;
    fetch("/api/session", { cache: "no-store" })
      .then(r => r.ok ? r.json() : { email: null })
      .then(s => { if (!cancelled) setSession(s); })
      .catch(() => { if (!cancelled) setSession({ email: null }); });
    return () => { cancelled = true; };
  }, []);

  if (session === null) {
    // Loading — keep a neutral placeholder so layout doesn't shift.
    return (
      <div style={{
        width: 28, height: 28, borderRadius: "50%",
        background: "var(--chip-bg)",
      }}/>
    );
  }

  if (!session.email) {
    return (
      <a href="/login" className="mono" style={{
        fontSize: 11, color: "var(--accent)", letterSpacing: "0.08em",
        textTransform: "uppercase", fontWeight: 700,
      }}>Sign in</a>
    );
  }

  const initials = (session.name || session.email).split(/[\s@.]+/).filter(Boolean).slice(0, 2).map(s => s[0].toUpperCase()).join("") || "?";

  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 10 }}>
      <span className="mono" style={{ fontSize: 11, color: "var(--ink-dim)" }} title={session.email}>
        {session.name || session.email.split("@")[0]}
      </span>
      <form action="/auth/signout" method="post" style={{ display: "inline" }}>
        <button type="submit" className="mono" style={{
          fontSize: 10, color: "var(--ink-muted)", letterSpacing: "0.08em",
          textTransform: "uppercase", cursor: "pointer",
        }} title="Sign out">Sign out</button>
      </form>
      <span style={{
        width: 28, height: 28, borderRadius: "50%",
        background: "var(--accent-soft)", color: "var(--accent)",
        display: "grid", placeItems: "center",
        fontFamily: "var(--mono)", fontSize: 11, fontWeight: 700,
      }}>{initials}</span>
    </span>
  );
}

// Section title — theme-driven
function SectionTitle({ eyebrow, title, lede, align = "left" }) {
  return (
    <div style={{ textAlign: align, maxWidth: 720, marginLeft: align === "center" ? "auto" : undefined, marginRight: align === "center" ? "auto" : undefined }}>
      {eyebrow && (
        <div className="mono" style={{
          fontSize: 11, color: "var(--accent)", letterSpacing: "0.14em",
          textTransform: "uppercase", marginBottom: 12,
        }}>{eyebrow}</div>
      )}
      <div className="display" style={{
        fontSize: "clamp(28px, 3.4vw, 48px)",
        lineHeight: 1.05,
        letterSpacing: "-0.02em",
        fontWeight: 600,
        color: "var(--ink)",
        textWrap: "balance",
      }}>{title}</div>
      {lede && (
        <div style={{
          marginTop: 16, fontSize: 17, color: "var(--ink-dim)",
          textWrap: "pretty", maxWidth: 560,
        }}>{lede}</div>
      )}
    </div>
  );
}

// Fit bar — horizontal
function FitBar({ value, height = 6, showLabel = false }) {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <div style={{
        flex: 1, height, background: "var(--chip-bg)",
        borderRadius: height, overflow: "hidden", position: "relative",
      }}>
        <div style={{
          height: "100%",
          width: `${Math.max(2, Math.min(100, value))}%`,
          background: fitColor(value),
          borderRadius: height,
        }}/>
      </div>
      {showLabel && (
        <div className="mono tnum" style={{ fontSize: 11, color: "var(--ink-dim)", minWidth: 28, textAlign: "right" }}>
          {value}
        </div>
      )}
    </div>
  );
}

// Radar chart — polygon + axes
function Radar({ values, keys, size = 220, max = 100 }) {
  const cx = size / 2, cy = size / 2;
  const r = size / 2 - 18;
  const N = keys.length;
  const angle = (i) => (-Math.PI / 2) + (i * 2 * Math.PI / N);
  const pt = (i, v) => {
    const a = angle(i);
    const rr = (v / max) * r;
    return [cx + Math.cos(a) * rr, cy + Math.sin(a) * rr];
  };
  const poly = values.map((v, i) => pt(i, v).join(",")).join(" ");
  const rings = [0.25, 0.5, 0.75, 1.0];
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: "block" }}>
      {rings.map((f, i) => (
        <polygon key={i}
          points={keys.map((_, k) => {
            const a = angle(k);
            return [cx + Math.cos(a) * r * f, cy + Math.sin(a) * r * f].join(",");
          }).join(" ")}
          fill="none" stroke="var(--rule)" strokeWidth={i === rings.length - 1 ? 1 : 0.5}/>
      ))}
      {keys.map((_, i) => {
        const [x, y] = pt(i, max);
        return <line key={i} x1={cx} y1={cy} x2={x} y2={y} stroke="var(--rule)" strokeWidth="0.5"/>;
      })}
      <polygon points={poly}
        fill="var(--accent-soft)"
        stroke="var(--accent)"
        strokeWidth="1.5"/>
      {values.map((v, i) => {
        const [x, y] = pt(i, v);
        return <circle key={i} cx={x} cy={y} r="2.5" fill="var(--accent)"/>;
      })}
      {keys.map((k, i) => {
        const [x, y] = pt(i, max + 8);
        return (
          <text key={i} x={x} y={y}
            textAnchor="middle" dominantBaseline="middle"
            fontFamily="var(--mono)" fontSize="9.5"
            letterSpacing="0.08em"
            fill="var(--ink-muted)">{k.toUpperCase()}</text>
        );
      })}
    </svg>
  );
}

// Trend arrow
function Trend({ value }) {
  if (value === 0) return <span className="mono" style={{ color: "var(--ink-muted)" }}>—</span>;
  const up = value > 0;
  return (
    <span className="mono tnum" style={{
      color: up ? "var(--good)" : "var(--bad)",
      fontSize: 12, display: "inline-flex", alignItems: "center", gap: 2,
    }}>
      {up ? "▲" : "▼"} {Math.abs(value)}
    </span>
  );
}

// IAMS 0-200 dial — big circular progress
function IamsDial({ value, size = 180, label = "IAMS Index", sub = "AI · /200" }) {
  const cx = size / 2, cy = size / 2;
  const r = size / 2 - 10;
  const circ = 2 * Math.PI * r;
  const pct = Math.max(0, Math.min(1, value / 200));
  return (
    <div style={{ display: "inline-flex", flexDirection: "column", alignItems: "center" }}>
      <div style={{ position: "relative", width: size, height: size }}>
        <svg width={size} height={size}>
          <circle cx={cx} cy={cy} r={r}
            fill="none" stroke="var(--rule)" strokeWidth="4"/>
          <circle cx={cx} cy={cy} r={r}
            fill="none" stroke="var(--accent)" strokeWidth="4"
            strokeLinecap="butt"
            strokeDasharray={`${pct * circ} ${circ}`}
            transform={`rotate(-90 ${cx} ${cy})`}/>
          {/* 20-tick marks */}
          {Array.from({ length: 20 }).map((_, i) => {
            const a = -Math.PI / 2 + (i / 20) * 2 * Math.PI;
            const x1 = cx + Math.cos(a) * (r - 8);
            const y1 = cy + Math.sin(a) * (r - 8);
            const x2 = cx + Math.cos(a) * (r - 2);
            const y2 = cy + Math.sin(a) * (r - 2);
            return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--rule-strong)" strokeWidth={i % 5 === 0 ? 1.2 : 0.6}/>;
          })}
        </svg>
        <div style={{
          position: "absolute", inset: 0,
          display: "flex", flexDirection: "column",
          alignItems: "center", justifyContent: "center",
        }}>
          <div className="display tnum" style={{ fontSize: size * 0.32, fontWeight: 600, letterSpacing: "-0.03em", color: "var(--accent)", lineHeight: 1 }}>
            {value}
          </div>
          <div className="mono" style={{ fontSize: 10, color: "var(--ink-muted)", letterSpacing: "0.12em", marginTop: 4 }}>/200</div>
        </div>
      </div>
      <div className="mono" style={{ fontSize: 10, color: "var(--ink-muted)", letterSpacing: "0.14em", textTransform: "uppercase", marginTop: 10 }}>
        {label}
      </div>
      <div className="mono" style={{ fontSize: 10, color: "var(--ink-muted)", letterSpacing: "0.04em", marginTop: 2 }}>{sub}</div>
    </div>
  );
}

// Camelot compatibility wheel — 4 axes split into color-coded arcs
function CamelotWheel({ data, size = 200 }) {
  // data: [{axis, score 0-100, band}]
  const cx = size / 2, cy = size / 2;
  const outerR = size / 2 - 4;
  const innerR = size * 0.22;
  const N = data.length;
  const bandColor = (b) => b === "good" ? "var(--good)" : b === "mid" ? "var(--mid)" : "var(--bad)";
  const arc = (i, score) => {
    const a0 = (i / N) * 2 * Math.PI - Math.PI / 2;
    const a1 = ((i + 1) / N) * 2 * Math.PI - Math.PI / 2 - 0.02;
    // radius driven by score
    const rOuter = innerR + (outerR - innerR) * (score / 100);
    const p = (a, r) => [cx + Math.cos(a) * r, cy + Math.sin(a) * r];
    const [x0o, y0o] = p(a0, rOuter);
    const [x1o, y1o] = p(a1, rOuter);
    const [x0i, y0i] = p(a0, innerR);
    const [x1i, y1i] = p(a1, innerR);
    const large = (a1 - a0) > Math.PI ? 1 : 0;
    return `M ${x0i} ${y0i} L ${x0o} ${y0o} A ${rOuter} ${rOuter} 0 ${large} 1 ${x1o} ${y1o} L ${x1i} ${y1i} A ${innerR} ${innerR} 0 ${large} 0 ${x0i} ${y0i} Z`;
  };
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: "block" }}>
      {/* background ring */}
      <circle cx={cx} cy={cy} r={outerR} fill="none" stroke="var(--rule)" strokeWidth="0.5"/>
      <circle cx={cx} cy={cy} r={innerR} fill="none" stroke="var(--rule)" strokeWidth="0.5"/>
      {data.map((d, i) => (
        <path key={d.axis} d={arc(i, d.score)} fill={bandColor(d.band)} opacity="0.85"/>
      ))}
      {/* dividers */}
      {data.map((_, i) => {
        const a = (i / N) * 2 * Math.PI - Math.PI / 2;
        const x1 = cx + Math.cos(a) * innerR;
        const y1 = cy + Math.sin(a) * innerR;
        const x2 = cx + Math.cos(a) * outerR;
        const y2 = cy + Math.sin(a) * outerR;
        return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke="var(--bg)" strokeWidth="1.5"/>;
      })}
      {/* axis labels */}
      {data.map((d, i) => {
        const a = ((i + 0.5) / N) * 2 * Math.PI - Math.PI / 2;
        const rr = outerR + 18;
        const x = cx + Math.cos(a) * rr;
        const y = cy + Math.sin(a) * rr;
        return (
          <g key={d.axis}>
            <text x={x} y={y - 4} textAnchor="middle" dominantBaseline="middle"
              fontFamily="var(--mono)" fontSize="9.5" letterSpacing="0.1em"
              fill="var(--ink-muted)">{d.axis.toUpperCase()}</text>
            <text x={x} y={y + 8} textAnchor="middle" dominantBaseline="middle"
              fontFamily="var(--display)" fontSize="13" fontWeight="600"
              fill={bandColor(d.band)}>{d.score}</text>
          </g>
        );
      })}
    </svg>
  );
}

// Injury badge
function InjuryBadge({ injury }) {
  const cls = { green: "inj-green", yellow: "inj-yellow", red: "inj-red" }[injury.badge];
  const label = { green: "Fit", yellow: "Caution", red: "Flagged" }[injury.badge];
  return (
    <span className={"inj-badge " + cls}>
      <span className="dot-s"/> {label} · {injury.daysLost12m}d / 12m
    </span>
  );
}

// Source tag (FM / AI / Community / third-party)
function SourceTag({ src }) {
  return <span className="src-tag">{src}</span>;
}

// Attribute row — 0-20 scale with dotted fill
function AttrRow({ label, value, hidden = false }) {
  const cells = Array.from({ length: 20 });
  return (
    <div style={{ display: "grid", gridTemplateColumns: "130px 1fr 26px", gap: 10, alignItems: "center" }}>
      <div style={{
        fontSize: 12,
        color: hidden ? "var(--ink-muted)" : "var(--ink-dim)",
        fontStyle: hidden ? "italic" : "normal",
      }}>
        {label}
        {hidden && <span className="mono" style={{ fontSize: 9, marginLeft: 4, color: "var(--ink-muted)" }}>●hidden</span>}
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "repeat(20, 1fr)", gap: 1 }}>
        {cells.map((_, i) => (
          <div key={i} style={{
            height: 8,
            background: i < value
              ? (value >= 15 ? "var(--accent)" : value >= 10 ? "var(--accent-2)" : "var(--mid)")
              : "var(--rule)",
          }}/>
        ))}
      </div>
      <div className="mono tnum" style={{ fontSize: 12, textAlign: "right", fontWeight: 600, color: "var(--ink)" }}>{value}</div>
    </div>
  );
}

// Probability pill
function ProbPill({ value, label }) {
  const color = value >= 75 ? "var(--good)" : value >= 55 ? "var(--mid)" : "var(--bad)";
  return (
    <div style={{
      display: "inline-flex", alignItems: "center", gap: 8,
      padding: "4px 10px",
      border: "1px solid " + color,
      color,
    }}>
      <span className="mono tnum" style={{ fontSize: 13, fontWeight: 700 }}>{value}%</span>
      <span className="mono" style={{ fontSize: 10, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--ink-dim)" }}>{label}</span>
    </div>
  );
}

// ──────────────────────────── CAMELOT MINI-BADGE ────────────────────────────
// Compact 4-quadrant disc — Role · Geo · League · Mental
function CamelotMini({ data, size = 28, showKey = null }) {
  if (!data || !data.length) return null;
  const cx = size / 2, cy = size / 2;
  const r = size / 2 - 1;
  const band = (b) => b === "good" ? "var(--good)" : b === "mid" ? "var(--mid)" : "var(--bad)";
  const N = data.length;
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6 }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ flexShrink: 0 }}>
        {data.map((d, i) => {
          const a0 = (i / N) * 2 * Math.PI - Math.PI / 2;
          const a1 = ((i + 1) / N) * 2 * Math.PI - Math.PI / 2;
          const x0 = cx + Math.cos(a0) * r, y0 = cy + Math.sin(a0) * r;
          const x1 = cx + Math.cos(a1) * r, y1 = cy + Math.sin(a1) * r;
          const large = (a1 - a0) > Math.PI ? 1 : 0;
          return <path key={i}
            d={`M ${cx} ${cy} L ${x0} ${y0} A ${r} ${r} 0 ${large} 1 ${x1} ${y1} Z`}
            fill={band(d.band)} opacity="0.85"/>;
        })}
        <circle cx={cx} cy={cy} r={r * 0.3} fill="var(--panel)"/>
      </svg>
      {showKey && (
        <span className="mono" style={{ fontSize: 11, fontWeight: 700, color: "var(--accent)", letterSpacing: "0.02em" }}>
          {showKey}
        </span>
      )}
    </span>
  );
}

// ──────────────────────────── CAMELOT KEY PILL ────────────────────────────
// Musical-wheel-style key pill: "8B — Free 10"
function CamelotKeyPill({ keyCode, match }) {
  const colors = {
    perfect:  "var(--good)",
    harmonic: "var(--good)",
    neutral:  "var(--mid)",
    clash:    "var(--bad)",
  };
  const c = colors[match] || "var(--ink-muted)";
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      padding: "3px 10px",
      background: "transparent",
      border: "1.5px solid " + c,
      fontFamily: "var(--mono)",
      fontSize: 11, fontWeight: 700, color: c,
      letterSpacing: "0.06em", textTransform: "uppercase",
    }}>
      <span style={{ width: 6, height: 6, borderRadius: "50%", background: c }}/>
      KEY {keyCode}
    </span>
  );
}

// ──────────────────────────── FM-STYLE ATTRIBUTE CELL ────────────────────────────
// Tiny 1-20 cell — the FM signature. Number-only, color-coded.
function FmAttr({ label, value, hidden = false }) {
  const color = value >= 16 ? "var(--accent)" : value >= 12 ? "var(--ink)" : value >= 8 ? "var(--mid)" : "var(--bad)";
  return (
    <div style={{
      display: "grid", gridTemplateColumns: "1fr 28px", gap: 8,
      alignItems: "center",
      padding: "4px 0",
      borderBottom: "1px dotted var(--rule)",
    }}>
      <div style={{
        fontSize: 12,
        color: hidden ? "var(--ink-muted)" : "var(--ink-dim)",
        fontStyle: hidden ? "italic" : "normal",
      }}>{label}</div>
      <div className="display tnum" style={{
        fontSize: 16, fontWeight: 600, textAlign: "right",
        color,
        fontFeatureSettings: '"tnum" 1',
      }}>{value}</div>
    </div>
  );
}

// ──────────────────────────── IMDB-STYLE STAR RATING ────────────────────────────
function StarRow({ value = 0, max = 10, size = 14, onChange = null, color = "var(--accent)" }) {
  // value 0-10; star count 10 (half-stars rounded)
  const full = Math.round(value);
  return (
    <div style={{ display: "inline-flex", gap: 2 }}>
      {Array.from({ length: max }).map((_, i) => (
        <span key={i}
          onClick={onChange ? () => onChange(i + 1) : undefined}
          style={{
            width: size, height: size,
            cursor: onChange ? "pointer" : "default",
            color: i < full ? color : "var(--rule-strong)",
            fontSize: size,
            lineHeight: 1,
          }}>★</span>
      ))}
    </div>
  );
}

// ──────────────────────────── IMDB-STYLE MINI RATING ROW ────────────────────────────
// Single-line rating: label · /200 value · source note
function RatingMini({ label, value, src, accent }) {
  return (
    <div style={{
      display: "grid", gridTemplateColumns: "1fr auto", gap: 6, alignItems: "baseline",
      padding: "6px 0", borderBottom: "1px dashed var(--rule)",
    }}>
      <div>
        <div className="mono" style={{ fontSize: 9.5, color: accent ? "var(--accent)" : "var(--ink-muted)",
          letterSpacing: "0.1em", textTransform: "uppercase" }}>{label}</div>
        <div className="mono" style={{ fontSize: 9.5, color: "var(--ink-muted)", marginTop: 1 }}>{src}</div>
      </div>
      <div className="display tnum" style={{
        fontSize: 18, fontWeight: 700,
        color: accent ? "var(--accent)" : "var(--ink)",
      }}>{value ?? "—"}</div>
    </div>
  );
}

// ──────────────────────────── XP / TRUST BAR ────────────────────────────
function XpBar({ xp, trust, compact = false }) {
  return (
    <div style={{ display: compact ? "inline-flex" : "flex", alignItems: "center", gap: compact ? 10 : 14 }}>
      <div style={{
        display: "inline-flex", alignItems: "center", gap: 6,
        padding: "3px 8px",
        border: "1px solid " + trust.current.color,
        fontFamily: "var(--mono)",
        fontSize: 10, fontWeight: 700, color: trust.current.color,
        letterSpacing: "0.1em", textTransform: "uppercase",
      }}>
        <span>{trust.current.badge}</span> LVL {trust.current.level} · {trust.current.label}
      </div>
      <div style={{ flex: compact ? undefined : 1, minWidth: compact ? 100 : 180 }}>
        <div style={{ height: 6, background: "var(--chip-bg)", position: "relative", overflow: "hidden" }}>
          <div style={{
            position: "absolute", inset: 0,
            width: `${trust.pct}%`,
            background: "linear-gradient(90deg, var(--accent), var(--accent-2))",
          }}/>
        </div>
        {!compact && (
          <div className="mono" style={{ fontSize: 10, color: "var(--ink-muted)", marginTop: 4, letterSpacing: "0.06em" }}>
            {xp} XP {trust.next ? `· ${trust.next.xp - xp} to ${trust.next.label}` : "· max level"}
          </div>
        )}
      </div>
    </div>
  );
}

Object.assign(window, {
  Wordmark, AppChrome, SectionTitle, FitBar, Radar, Trend, fitColor, fitLabel,
  IamsDial, CamelotWheel, InjuryBadge, SourceTag, AttrRow, ProbPill,
  CamelotMini, CamelotKeyPill, FmAttr, StarRow, XpBar, RatingMini,
});
