// Badges — friendly laurel-medallion progression badges.
// Replaces the hex / "black ops" treatment with a warm, growth-oriented system:
//   • Each family has THREE tiers that visually evolve (sprig → wreath → wreath + sunburst)
//   • Tier palette: Bronze → Sage → Gold (warm, not metallic)
//   • Hidden badges are "Surprises" — playful question-mark medallion with a friendly hint
//   • Standalone "Moment" badges for one-off achievements (no tier)

const { useState: useBadgeState, useMemo: useBadgeMemo } = React;

// ---------- Catalog ----------
// Families produce 3 tiers each (I, II, III). Standalone moments + secrets sit alongside.

const FAMILIES = [
  { id: "calls",     icon: "phone",   group: "Outreach",
    tiers: [
      { name: "First Hello",        criteria: "Make your first 10 calls.",     progressMax: 10    },
      { name: "Good Listener",      criteria: "Reach 500 lifetime calls.",     progressMax: 500   },
      { name: "Conversationalist",  criteria: "Reach 2,500 lifetime calls.",   progressMax: 2500  },
    ]},
  { id: "mail",      icon: "envelope", group: "Outreach",
    tiers: [
      { name: "First Note",         criteria: "Send your first 10 mailings.",  progressMax: 10    },
      { name: "Steady Writer",      criteria: "Send 100 mailings.",            progressMax: 100   },
      { name: "Mail Carrier",       criteria: "Send 500 mailings.",            progressMax: 500   },
    ]},
  { id: "leads",     icon: "lead",    group: "Pipeline",
    tiers: [
      { name: "Curious Eye",        criteria: "Surface your first lead.",      progressMax: 1     },
      { name: "Lead Spotter",       criteria: "Surface 25 lifetime leads.",    progressMax: 25    },
      { name: "Pathfinder",         criteria: "Surface 100 lifetime leads.",   progressMax: 100   },
    ]},
  { id: "visits",    icon: "visit",   group: "Pipeline",
    tiers: [
      { name: "First Footsteps",    criteria: "Complete your first site visit.", progressMax: 1   },
      { name: "Wayfarer",           criteria: "Visit 25 sites.",               progressMax: 25    },
      { name: "Globetrotter",       criteria: "Visit 75 sites.",               progressMax: 75    },
    ]},
  { id: "lois",      icon: "loi",     group: "Pipeline",
    tiers: [
      { name: "First Signature",    criteria: "Sign your first LOI.",          progressMax: 1     },
      { name: "Pen in Hand",        criteria: "Sign 5 LOIs.",                  progressMax: 5     },
      { name: "Trusted Counsel",    criteria: "Sign 15 LOIs.",                 progressMax: 15    },
    ]},
  { id: "closes",    icon: "trophy",  group: "Closing",
    tiers: [
      { name: "First Win",          criteria: "Close your first deal.",        progressMax: 1     },
      { name: "Steady Hand",        criteria: "Close 5 deals.",                progressMax: 5     },
      { name: "Rainmaker",          criteria: "Close 15 deals.",               progressMax: 15    },
    ]},
  { id: "consist",   icon: "fire",    group: "Habit",
    tiers: [
      { name: "Bright Spark",       criteria: "Log activity 5 days in a row.", progressMax: 5     },
      { name: "Hot Streak",         criteria: "30+ calls every week, 4 wks.",  progressMax: 4     },
      { name: "Constant Star",      criteria: "12 perfect weeks of logging.",  progressMax: 12    },
    ]},
  { id: "team",      icon: "team",    group: "Team",
    tiers: [
      { name: "Helping Hand",       criteria: "Refer one deal across teams.",  progressMax: 1     },
      { name: "Good Neighbor",      criteria: "Refer 5 deals across teams.",   progressMax: 5     },
      { name: "Mentor",             criteria: "Mentor a teammate to close.",   progressMax: 1     },
    ]},
];

const MOMENTS = [
  { id: "welcome",      icon: "sun",     name: "Welcome Aboard",   group: "Moments", criteria: "Joined the firm." },
  { id: "the_whale",    icon: "whale",   name: "The Whale",        group: "Moments", criteria: "Single deal over $20M TEV." },
  { id: "comeback",     icon: "phoenix", name: "The Comeback",     group: "Moments", criteria: "Re-engaged a lost prospect to close." },
  { id: "first_lead",   icon: "lead",    name: "Lucky Day",        group: "Moments", criteria: "Sourced a deal in your first 30 days." },
];

const SECRETS = [
  { id: "early_bird",   icon: "sunrise",  name: "Early Bird",        hint: "Up before the rooster.",       criteria: "Log activity before 7am, 10 times." },
  { id: "night_owl",    icon: "moon",     name: "Night Owl",         hint: "Some hours are quieter.",      criteria: "Log activity after 9pm, 10 times." },
  { id: "explorer",     icon: "compass",  name: "Explorer",          hint: "Click around, find things.",   criteria: "Discover 5 hidden screens." },
  { id: "anniversary",  icon: "cake",     name: "Year One",          hint: "A trip around the sun.",       criteria: "One full year at the firm." },
];

// Build flat catalog
const BADGE_CATALOG = (() => {
  const out = [];
  FAMILIES.forEach(fam => {
    fam.tiers.forEach((t, i) => {
      out.push({
        id: `${fam.id}_${i+1}`,
        family: fam.id, familyIcon: fam.icon, familyGroup: fam.group,
        tier: i + 1,             // 1, 2, 3
        name: t.name,
        criteria: t.criteria,
        progressMax: t.progressMax,
        kind: "tier",
      });
    });
  });
  MOMENTS.forEach(m => out.push({ ...m, kind: "moment", tier: 0 }));
  SECRETS.forEach(s => out.push({ ...s, kind: "secret", tier: 0 }));
  return out;
})();

// Tier palette — warm, friendly, growth metaphor
const TIER_PALETTE = {
  1: { name: "Bronze", ring: "#C8854E", fill1: "#F5C28B", fill2: "#C8854E", ribbon: "#8C5526", glyph: "#5C3415", text: "#FFE7CB" },
  2: { name: "Sage",   ring: "#7FA68D", fill1: "#C7DCC8", fill2: "#7FA68D", ribbon: "#4F7762", glyph: "#2A4232", text: "#EAF5EC" },
  3: { name: "Gold",   ring: "#C99528", fill1: "#F8DA78", fill2: "#C99528", ribbon: "#8D6712", glyph: "#5A3F0A", text: "#FFF4D2" },
};

const SECRET_PALETTE = { ring: "#9C8AB9", fill1: "#E0D6F0", fill2: "#9C8AB9", ribbon: "#6E5A92", glyph: "#3E2D5D", text: "#F3ECFF" };
const MOMENT_PALETTE = { ring: "#D8896D", fill1: "#F6D2C2", fill2: "#D8896D", ribbon: "#9B5639", glyph: "#5B2D1A", text: "#FBE7DD" };

// ---------- Glyph icons (centered, small) ----------
const Glyph = {
  phone:    <path d="M11 11c0 16 14 30 30 30l4-9-10-3-3 5c-7-2-12-7-14-14l5-3-3-10z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/>,
  envelope: <><rect x="8" y="14" width="40" height="28" stroke="currentColor" strokeWidth="3" fill="none" rx="2"/><path d="M8 16l20 16 20-16" stroke="currentColor" strokeWidth="3" fill="none"/></>,
  lead:     <><circle cx="28" cy="28" r="18" stroke="currentColor" strokeWidth="3" fill="none"/><circle cx="28" cy="28" r="10" stroke="currentColor" strokeWidth="3" fill="none"/><circle cx="28" cy="28" r="3" fill="currentColor"/></>,
  visit:    <><path d="M28 50s-15-13-15-25a15 15 0 0130 0c0 12-15 25-15 25z" stroke="currentColor" strokeWidth="3" fill="none"/><circle cx="28" cy="22" r="5" stroke="currentColor" strokeWidth="3" fill="none"/></>,
  loi:      <><path d="M14 8h20l10 10v30H14z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/><path d="M34 8v10h10" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M20 28h16M20 36h12" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
  trophy:   <><path d="M18 8h20v12c0 6-4 10-10 10s-10-4-10-10z" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M10 12h8v6a6 6 0 01-6 6h-2zM46 12h-8v6a6 6 0 006 6h2" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M22 38h12v6H22zM18 46h20" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
  fire:     <path d="M28 50c-9 0-15-6-15-13 0-6 6-9 6-15 0 0 3 3 3 7 0 0 4-3 4-9 6 3 12 11 12 19 0 7-5 11-10 11z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/>,
  team:     <><circle cx="20" cy="22" r="6" stroke="currentColor" strokeWidth="3" fill="none"/><circle cx="38" cy="24" r="5" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M8 44c0-7 6-12 12-12s12 5 12 12M28 44c0-5 4-9 10-9s10 4 10 9" stroke="currentColor" strokeWidth="3" fill="none" strokeLinecap="round"/></>,
  sun:      <><circle cx="28" cy="28" r="9" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M28 8v6M28 42v6M8 28h6M42 28h6M14 14l4 4M42 14l-4 4M14 42l4-4M42 42l-4-4" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
  whale:    <><path d="M6 30c4-10 14-14 22-14s16 4 22 14c-4 6-12 10-22 10S10 36 6 30z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/><path d="M50 30c0-6 0-10 4-12-4 0-8 4-10 8" stroke="currentColor" strokeWidth="3" fill="none" strokeLinecap="round"/><circle cx="20" cy="26" r="2" fill="currentColor"/></>,
  phoenix:  <><path d="M12 38c4-14 14-22 22-26-2 6 0 12 4 16-4 2-8 6-10 12 0-6-4-10-8-12 0 6-4 10-8 10z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/><path d="M16 46h24" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
  sunrise:  <><path d="M6 38h44" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/><path d="M14 38a14 14 0 0128 0" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M28 12v8M12 22l5 5M44 22l-5 5" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
  moon:     <path d="M40 32A18 18 0 1126 12a14 14 0 0014 20z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/>,
  compass:  <><circle cx="28" cy="28" r="18" stroke="currentColor" strokeWidth="3" fill="none"/><path d="M28 14l4 12 12 4-12 4-4 12-4-12-12-4 12-4z" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinejoin="round"/></>,
  cake:     <><path d="M10 26h36v18H10z" stroke="currentColor" strokeWidth="3" fill="none" strokeLinejoin="round"/><path d="M10 34h36" stroke="currentColor" strokeWidth="3"/><path d="M28 12v10M22 16v6M34 16v6" stroke="currentColor" strokeWidth="3" strokeLinecap="round"/></>,
};

// ---------- Laurel medallion ----------
//
// Tier 1 → single laurel sprig on each side
// Tier 2 → fuller laurel wreath
// Tier 3 → wreath + outer sunburst rays
// Secret → laurel sprig + "?" centered
// Moment → laurel wreath, peach palette, ribbon = "MOMENT"

function LaurelMedallion({ badge, locked, size = 96 }) {
  const isSecret = badge.kind === "secret";
  const isMoment = badge.kind === "moment";
  const tier = badge.tier; // 0 for non-tier, 1/2/3 for tier
  const palette = isSecret ? SECRET_PALETTE
                : isMoment ? MOMENT_PALETTE
                : (TIER_PALETTE[tier] || TIER_PALETTE[1]);
  const ribbonLabel = isSecret ? (locked ? "SECRET" : "FOUND")
                    : isMoment ? "MOMENT"
                    : (palette.name.toUpperCase());
  const showRays = !locked && tier === 3;
  const wreathLevel = isSecret ? 1 : isMoment ? 2 : tier;
  const Icon = Glyph[badge.familyIcon || badge.icon] || Glyph.trophy;

  const gradId = `lm-${badge.id}-${locked ? "l" : "u"}`;
  const grayed = locked;

  return (
    <svg width={size} height={size} viewBox="0 0 120 120" style={{ display: "block", filter: grayed ? "saturate(0.18) brightness(0.92)" : "none" }}>
      <defs>
        <radialGradient id={gradId} cx="50%" cy="40%" r="65%">
          <stop offset="0%"  stopColor={palette.fill1}/>
          <stop offset="100%" stopColor={palette.fill2}/>
        </radialGradient>
        <linearGradient id={gradId + "-shine"} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#ffffff" stopOpacity="0.55"/>
          <stop offset="55%" stopColor="#ffffff" stopOpacity="0"/>
        </linearGradient>
      </defs>

      {/* Sunburst rays — only at tier 3 unlocked */}
      {showRays && (
        <g opacity="0.55">
          {Array.from({ length: 12 }, (_, i) => {
            const a = (i * 30) * Math.PI / 180;
            const x1 = 60 + Math.cos(a) * 50, y1 = 60 + Math.sin(a) * 50;
            const x2 = 60 + Math.cos(a) * 58, y2 = 60 + Math.sin(a) * 58;
            return <line key={i} x1={x1} y1={y1} x2={x2} y2={y2} stroke={palette.ring} strokeWidth="2.5" strokeLinecap="round"/>;
          })}
        </g>
      )}

      {/* Laurel branches */}
      <Laurel side="left"  level={wreathLevel} color={palette.ring} dimmed={grayed}/>
      <Laurel side="right" level={wreathLevel} color={palette.ring} dimmed={grayed}/>

      {/* Outer ring */}
      <circle cx="60" cy="60" r="34" fill={palette.ring}/>
      {/* Inner medallion */}
      <circle cx="60" cy="60" r="30" fill={`url(#${gradId})`}/>
      {/* Top shine */}
      <circle cx="60" cy="60" r="30" fill={`url(#${gradId}-shine)`}/>

      {/* Glyph or secret "?" */}
      <g style={{ color: palette.glyph }}>
        {isSecret && locked ? (
          <text x="60" y="72" textAnchor="middle" fontSize="32" fontWeight="700" fill={palette.glyph} style={{ fontFamily: "var(--f-display, serif)" }}>?</text>
        ) : (
          <g transform="translate(32,32) scale(0.5)">{Icon}</g>
        )}
      </g>

      {/* Ribbon */}
      <g>
        <path d="M22 92 L60 88 L98 92 L92 110 L60 104 L28 110 Z" fill={palette.ribbon}/>
        <path d="M22 92 L28 100 L22 102 Z" fill={palette.ribbon} opacity="0.6"/>
        <path d="M98 92 L92 100 L98 102 Z" fill={palette.ribbon} opacity="0.6"/>
        <text x="60" y="100" textAnchor="middle" fontSize="9" fontWeight="700"
          fill={palette.text} style={{ fontFamily: "var(--f-mono, monospace)", letterSpacing: "0.1em" }}>
          {ribbonLabel}
        </text>
      </g>

      {/* Tier dots — only on tiered badges */}
      {!isSecret && !isMoment && (
        <g transform="translate(60, 28)">
          {[1, 2, 3].map(n => (
            <circle key={n} cx={(n - 2) * 6} cy="0" r="2.2"
              fill={tier >= n ? palette.text : "#ffffff"}
              opacity={tier >= n ? 1 : 0.35}
            />
          ))}
        </g>
      )}

      {/* Lock badge */}
      {locked && (
        <g transform="translate(86, 86)">
          <circle r="10" fill="#0d0f12" opacity="0.92"/>
          <path d="M-3 -1.5v-2a3 3 0 016 0v2M-4 -1.5h8v6h-8z" stroke="#fff" strokeWidth="1.4" fill="none" strokeLinejoin="round"/>
        </g>
      )}
    </svg>
  );
}

// Laurel branch — drawn as a curving stem with paired leaves.
// `level` controls leaf count: 1=sprig (3 leaves), 2=branch (5), 3=full (7).
function Laurel({ side, level, color, dimmed }) {
  const flip = side === "left" ? -1 : 1;
  const leaves = level >= 3 ? 7 : level >= 2 ? 5 : 3;
  // Stem path: curves from bottom-center outward and up around the medallion
  const stemD = side === "left"
    ? "M 56 96 Q 30 92, 22 70 Q 18 46, 36 28"
    : "M 64 96 Q 90 92, 98 70 Q 102 46, 84 28";
  return (
    <g opacity={dimmed ? 0.55 : 1}>
      <path d={stemD} stroke={color} strokeWidth="2.2" fill="none" strokeLinecap="round" opacity="0.9"/>
      {Array.from({ length: leaves }).map((_, i) => {
        // Place leaves along the stem; manually positioned for visual balance
        const positions = [
          { x: 30, y: 84, a: -45 },
          { x: 23, y: 68, a: -25 },
          { x: 22, y: 52, a: -5  },
          { x: 26, y: 38, a: 15  },
          { x: 34, y: 28, a: 35  },
          { x: 28, y: 60, a: -15 }, // extra (level 3)
          { x: 32, y: 44, a: 5   }, // extra (level 3)
        ];
        const p = positions[i] || positions[0];
        const x = side === "left" ? p.x : 120 - p.x;
        const y = p.y;
        const ang = p.a * flip;
        return (
          <g key={i} transform={`translate(${x} ${y}) rotate(${ang})`}>
            <ellipse rx="6" ry="2.4" fill={color}/>
            <ellipse rx="6" ry="2.4" fill="#ffffff" opacity="0.18"/>
          </g>
        );
      })}
    </g>
  );
}

// ---------- State helpers ----------
function bHash(s) { let h = 2166136261; for (let i = 0; i < s.length; i++) h = Math.imul(h ^ s.charCodeAt(i), 16777619); return Math.abs(h); }

// Pinned earned set for the demo user
const PINNED_USER = "scott_b";
const PINNED_EARNED = new Set([
  "calls_1", "calls_2",                  // family progress through II
  "mail_1",
  "leads_1", "leads_2",
  "visits_1",
  "lois_1",
  "closes_1",
  "consist_1", "consist_2",
  "team_1",
  "welcome", "first_lead",
  "early_bird",                           // one secret found
]);

function userEarnedBadge(badgeId, userId) {
  if (userId === PINNED_USER) return PINNED_EARNED.has(badgeId);
  return (bHash(userId + badgeId) % 100) < 35;
}

function userBadgeProgress(badge, userId) {
  if (!badge.progressMax) return null;
  if (userEarnedBadge(badge.id, userId)) return { cur: badge.progressMax, max: badge.progressMax };
  const r = (bHash(userId + badge.id) % 90) / 100;
  return { cur: Math.round(badge.progressMax * r), max: badge.progressMax };
}

function badgeOwners(badgeId) {
  const F = window.VAULT_FIRM;
  return F.PEOPLE.map(p => p.id).filter(pid => userEarnedBadge(badgeId, pid));
}

// ---------- Family card (shows the 3-tier evolution row) ----------

function FamilyRow({ family, userId, onSelect }) {
  const badges = BADGE_CATALOG.filter(b => b.family === family.id);
  const earnedCount = badges.filter(b => userEarnedBadge(b.id, userId)).length;
  return (
    <div className="card" style={{ padding: 16, display: "flex", flexDirection: "column", gap: 10 }}>
      <div className="row" style={{ gap: 10, alignItems: "center" }}>
        <span className="micro" style={{ color: "var(--muted)" }}>{family.group}</span>
        <span className="stretch"/>
        <span className="mono small" style={{ color: "var(--muted)" }}>
          {earnedCount} of 3
        </span>
        <div style={{ width: 80, height: 4, background: "var(--surface-2)", borderRadius: 2, overflow: "hidden" }}>
          <div style={{ width: `${(earnedCount / 3) * 100}%`, height: "100%", background: "var(--accent)" }}/>
        </div>
      </div>
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 10 }}>
        {badges.map((b, i) => {
          const earned = userEarnedBadge(b.id, userId);
          const prevEarned = i === 0 || userEarnedBadge(badges[i - 1].id, userId);
          return (
            <div key={b.id} onClick={() => onSelect(b)}
              style={{
                cursor: "pointer", padding: "10px 8px",
                borderRadius: 10,
                background: earned ? "var(--surface)" : "transparent",
                border: "1px solid " + (earned ? "var(--line)" : "transparent"),
                display: "flex", flexDirection: "column", alignItems: "center", gap: 6,
                transition: "background .12s, border-color .12s, transform .12s",
              }}
              onMouseEnter={e => { e.currentTarget.style.transform = "translateY(-1px)"; }}
              onMouseLeave={e => { e.currentTarget.style.transform = "none"; }}
            >
              <LaurelMedallion badge={b} locked={!earned} size={84}/>
              <div style={{ textAlign: "center" }}>
                <div className="display" style={{ fontSize: 13, lineHeight: 1.2, color: earned ? "var(--ink)" : "var(--muted)" }}>{b.name}</div>
                {!earned && prevEarned && b.progressMax ? (
                  <ProgressLine badge={b} userId={userId}/>
                ) : (
                  <div className="muted" style={{ fontSize: 10.5, marginTop: 2 }}>
                    {earned ? "Earned" : prevEarned ? "Up next" : "Locked"}
                  </div>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function ProgressLine({ badge, userId }) {
  const p = userBadgeProgress(badge, userId);
  if (!p) return null;
  return (
    <div style={{ marginTop: 4 }}>
      <div className="mono" style={{ fontSize: 10, color: "var(--muted)" }}>
        {p.cur.toLocaleString()} / {p.max.toLocaleString()}
      </div>
      <div style={{ width: 80, height: 3, background: "var(--surface-2)", borderRadius: 2, marginTop: 2, marginLeft: "auto", marginRight: "auto", overflow: "hidden" }}>
        <div style={{ width: `${(p.cur/p.max)*100}%`, height: "100%", background: "var(--accent)" }}/>
      </div>
    </div>
  );
}

// ---------- Compact card (for moments + secrets) ----------

function MomentCard({ badge, userId, onSelect }) {
  const earned = userEarnedBadge(badge.id, userId);
  return (
    <div onClick={() => onSelect(badge)}
      className="card"
      style={{
        padding: 14,
        display: "flex", flexDirection: "column", alignItems: "center", gap: 8,
        cursor: "pointer",
        transition: "transform .12s, box-shadow .12s",
      }}
      onMouseEnter={e => { e.currentTarget.style.transform = "translateY(-2px)"; e.currentTarget.style.boxShadow = "0 8px 20px -10px rgba(0,0,0,0.12)"; }}
      onMouseLeave={e => { e.currentTarget.style.transform = "none"; e.currentTarget.style.boxShadow = "none"; }}
    >
      <LaurelMedallion badge={badge} locked={!earned} size={88}/>
      <div style={{ textAlign: "center" }}>
        <div className="display" style={{ fontSize: 13.5, lineHeight: 1.2 }}>
          {badge.kind === "secret" && !earned ? "Secret Badge" : badge.name}
        </div>
        <div className="muted small" style={{ marginTop: 3, fontSize: 11, lineHeight: 1.4 }}>
          {badge.kind === "secret" && !earned ? badge.hint : badge.criteria}
        </div>
      </div>
    </div>
  );
}

// ---------- Detail modal ----------

function BadgeDetail({ badge, userId, onClose }) {
  if (!badge) return null;
  const earned = userEarnedBadge(badge.id, userId);
  const owners = badgeOwners(badge.id);
  const total  = window.VAULT_FIRM.PEOPLE.length;
  const rarity = Math.round((owners.length / total) * 100);
  const prog   = userBadgeProgress(badge, userId);
  const isSecret = badge.kind === "secret";
  const showName = !(isSecret && !earned);

  return (
    <div onClick={onClose} style={{
      position: "fixed", inset: 0, background: "rgba(8,9,11,0.45)",
      backdropFilter: "blur(4px)", display: "flex", alignItems: "center", justifyContent: "center",
      zIndex: 200,
    }}>
      <div onClick={e => e.stopPropagation()} className="card" style={{ width: 460, maxWidth: "92vw", padding: 26 }}>
        <div className="row" style={{ gap: 16, alignItems: "flex-start" }}>
          <LaurelMedallion badge={badge} locked={!earned} size={120}/>
          <div className="stretch" style={{ minWidth: 0 }}>
            <div className="row" style={{ gap: 8, marginBottom: 4, flexWrap: "wrap" }}>
              <span className="mono small" style={{
                background: "var(--surface-2)", color: "var(--muted)",
                padding: "2px 6px", borderRadius: 3, letterSpacing: "0.06em",
              }}>{(badge.familyGroup || (badge.kind === "secret" ? "Secret" : "Moment")).toUpperCase()}</span>
              {badge.kind === "tier" && (
                <span className="mono small" style={{ color: "var(--muted)", letterSpacing: "0.04em" }}>
                  TIER {badge.tier} of 3
                </span>
              )}
            </div>
            <h3 className="display" style={{ fontSize: 24, fontWeight: 400, margin: 0, letterSpacing: "-0.01em" }}>
              {showName ? badge.name : "A secret badge"}
            </h3>
            <p style={{ marginTop: 8, fontSize: 13, lineHeight: 1.55, color: "var(--ink-2)" }}>
              {showName ? badge.criteria : badge.hint}
            </p>
          </div>
        </div>

        {prog && !isSecret && (
          <div style={{ marginTop: 18 }}>
            <div className="row" style={{ justifyContent: "space-between", fontSize: 11.5 }}>
              <span className="muted">Your progress</span>
              <span className="mono">{prog.cur.toLocaleString()} / {prog.max.toLocaleString()}</span>
            </div>
            <div style={{ height: 6, background: "var(--surface-2)", borderRadius: 3, marginTop: 6, overflow: "hidden" }}>
              <div style={{ width: `${(prog.cur/prog.max)*100}%`, height: "100%", background: "var(--accent)" }}/>
            </div>
          </div>
        )}

        <div style={{ marginTop: 20, paddingTop: 14, borderTop: "1px solid var(--line-2)" }}>
          <div className="row" style={{ justifyContent: "space-between", marginBottom: 10 }}>
            <span className="muted small">
              {isSecret && !earned ? "Discovered by" : `Earned by ${owners.length} of ${total}`}
            </span>
            <span className="mono small" style={{ color: "var(--muted)" }}>
              {isSecret && !earned ? "?? %" : `${rarity}% firm-wide`}
            </span>
          </div>
          {isSecret && !earned ? (
            <div className="muted small" style={{ fontStyle: "italic" }}>
              Keep exploring. You'll find it.
            </div>
          ) : (
            <div className="row" style={{ flexWrap: "wrap", gap: 6 }}>
              {owners.slice(0, 18).map(pid => <window.Avatar key={pid} id={pid}/>)}
              {owners.length > 18 && <span className="muted small mono" style={{ alignSelf: "center" }}>+{owners.length - 18}</span>}
              {owners.length === 0 && <span className="muted small">Be the first.</span>}
            </div>
          )}
        </div>

        <div className="row" style={{ justifyContent: "flex-end", marginTop: 20 }}>
          <button className="btn" onClick={onClose}>Close</button>
        </div>
      </div>
    </div>
  );
}

// ---------- Main view ----------

function BadgesView({ userId = "scott_b" }) {
  const [tab, setTab] = useBadgeState("families"); // families | moments | secrets
  const [selected, setSelected] = useBadgeState(null);

  const me = window.VAULT_FIRM.PEOPLE_BY_ID[userId];

  const totalEarned = BADGE_CATALOG.filter(b => userEarnedBadge(b.id, userId)).length;
  const familiesEarned = BADGE_CATALOG.filter(b => b.kind === "tier" && userEarnedBadge(b.id, userId)).length;
  const familiesTotal  = BADGE_CATALOG.filter(b => b.kind === "tier").length;
  const momentsEarned = BADGE_CATALOG.filter(b => b.kind === "moment" && userEarnedBadge(b.id, userId)).length;
  const momentsTotal  = MOMENTS.length;
  const secretsEarned = BADGE_CATALOG.filter(b => b.kind === "secret" && userEarnedBadge(b.id, userId)).length;
  const secretsTotal  = SECRETS.length;

  // For the highlight medallion: show their highest-tier earned badge family
  const showcase = useBadgeMemo(() => {
    const tierEarned = BADGE_CATALOG.filter(b => b.kind === "tier" && userEarnedBadge(b.id, userId));
    if (tierEarned.length === 0) return null;
    return tierEarned.sort((a, b) => b.tier - a.tier)[0];
  }, [userId]);

  const Tab = ({ id, label, count }) => (
    <button onClick={() => setTab(id)}
      className="btn ghost sm"
      style={{
        background: tab === id ? "var(--ink)" : "transparent",
        color: tab === id ? "var(--canvas)" : "var(--ink)",
        borderColor: tab === id ? "var(--ink)" : "var(--line)",
      }}>
      {label}
      {count != null && <span className="mono" style={{ marginLeft: 8, opacity: 0.7 }}>{count}</span>}
    </button>
  );

  return (
    <div>
      {/* Summary header */}
      <div className="card card-pad" style={{ marginBottom: 18 }}>
        <div className="row" style={{ gap: 22, flexWrap: "wrap", alignItems: "center" }}>
          <div className="row" style={{ gap: 14, alignItems: "center" }}>
            {showcase ? (
              <LaurelMedallion badge={showcase} size={72}/>
            ) : (
              <LaurelMedallion badge={BADGE_CATALOG.find(b => b.id === "calls_1")} locked size={72}/>
            )}
            <div>
              <div className="muted small" style={{ letterSpacing: "0.04em", textTransform: "uppercase" }}>{me ? me.name : "You"}</div>
              <div className="display" style={{ fontSize: 22, fontWeight: 400, letterSpacing: "-0.01em" }}>
                {totalEarned} <span style={{ color: "var(--muted)" }}>/ {BADGE_CATALOG.length}</span> earned
              </div>
            </div>
          </div>
          <div style={{ width: 1, alignSelf: "stretch", background: "var(--line)" }}/>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(4, auto)", gap: "8px 28px", alignContent: "center" }}>
            <SummaryStat label="Families"  cur={familiesEarned} total={familiesTotal}/>
            <SummaryStat label="Moments"   cur={momentsEarned}  total={momentsTotal}/>
            <SummaryStat label="Secrets"   cur={secretsEarned}  total={secretsTotal}/>
            <SummaryStat label="Rank"      custom="#3 of 36"/>
            <SummaryStat label="Tier I"    cur={countTier(1, userId)} total={FAMILIES.length}/>
            <SummaryStat label="Tier II"   cur={countTier(2, userId)} total={FAMILIES.length}/>
            <SummaryStat label="Tier III"  cur={countTier(3, userId)} total={FAMILIES.length}/>
            <SummaryStat label="Streak"    custom="4 wks"/>
          </div>
        </div>
      </div>

      {/* Tabs */}
      <div className="row" style={{ gap: 8, marginBottom: 14 }}>
        <Tab id="families" label="Families" count={familiesTotal}/>
        <Tab id="moments"  label="Moments"  count={momentsTotal}/>
        <Tab id="secrets"  label="Secrets"  count={secretsTotal}/>
      </div>

      {/* Content */}
      {tab === "families" && (
        <div style={{
          display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(360px, 1fr))",
          gap: 14,
        }}>
          {FAMILIES.map(fam => (
            <FamilyRow key={fam.id} family={fam} userId={userId} onSelect={setSelected}/>
          ))}
        </div>
      )}

      {tab === "moments" && (
        <div style={{
          display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
          gap: 12,
        }}>
          {BADGE_CATALOG.filter(b => b.kind === "moment").map(b => (
            <MomentCard key={b.id} badge={b} userId={userId} onSelect={setSelected}/>
          ))}
        </div>
      )}

      {tab === "secrets" && (
        <div style={{
          display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(180px, 1fr))",
          gap: 12,
        }}>
          {BADGE_CATALOG.filter(b => b.kind === "secret").map(b => (
            <MomentCard key={b.id} badge={b} userId={userId} onSelect={setSelected}/>
          ))}
        </div>
      )}

      <BadgeDetail badge={selected} userId={userId} onClose={() => setSelected(null)}/>
    </div>
  );
}

function SummaryStat({ label, cur, total, custom }) {
  return (
    <div>
      <div className="muted small" style={{ letterSpacing: "0.04em", textTransform: "uppercase", fontSize: 10.5 }}>{label}</div>
      <div className="display mono" style={{ fontSize: 16, fontWeight: 500, color: "var(--ink)" }}>
        {custom != null ? custom : <>{cur}<span style={{ color: "var(--muted)" }}> / {total}</span></>}
      </div>
    </div>
  );
}

function countTier(tier, userId) {
  return BADGE_CATALOG.filter(b => b.kind === "tier" && b.tier === tier && userEarnedBadge(b.id, userId)).length;
}

window.BadgesView = BadgesView;
window.BADGE_CATALOG = BADGE_CATALOG;
