// Shared visual building blocks for Rbac46

// ──────────────────────────────────────────────
// Icons — hand-drawn, paper-stamp feel, 1.6 stroke
// ──────────────────────────────────────────────
function Icon({ name, size = 22, stroke = "currentColor", fill = "none", thick = 1.6 }) {
  const p = { fill, stroke, strokeWidth: thick, strokeLinecap: "round", strokeLinejoin: "round" };
  const paths = {
    home:    <><path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-7H9v7H4a1 1 0 01-1-1z" {...p}/></>,
    book:    <><path d="M4 4h7a4 4 0 014 4v12H8a4 4 0 01-4-4z" {...p}/><path d="M20 4h-7a4 4 0 00-4 4v12h7a4 4 0 004-4z" {...p}/></>,
    photo:   <><rect x="3" y="5" width="18" height="14" rx="2" {...p}/><circle cx="9" cy="11" r="2" {...p}/><path d="M3 17l5-4 4 3 3-2 6 4" {...p}/></>,
    user:    <><circle cx="12" cy="8" r="4" {...p}/><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6" {...p}/></>,
    search:  <><circle cx="11" cy="11" r="7" {...p}/><path d="M20 20l-3.5-3.5" {...p}/></>,
    bell:    <><path d="M6 17V11a6 6 0 0112 0v6l1.5 2h-15z" {...p}/><path d="M10 21a2 2 0 004 0" {...p}/></>,
    chat:    <><path d="M4 5h16v11H9l-5 4z" {...p}/></>,
    phone:   <><path d="M5 4h4l2 5-2.5 1.5a11 11 0 005 5L15 13l5 2v4a1 1 0 01-1 1A15 15 0 014 5a1 1 0 011-1z" {...p}/></>,
    mail:    <><rect x="3" y="5" width="18" height="14" rx="2" {...p}/><path d="M3 7l9 6 9-6" {...p}/></>,
    pin:     <><path d="M12 22s7-7 7-12a7 7 0 10-14 0c0 5 7 12 7 12z" {...p}/><circle cx="12" cy="10" r="2.5" {...p}/></>,
    chev:    <><path d="M9 6l6 6-6 6" {...p}/></>,
    back:    <><path d="M15 6l-6 6 6 6" {...p}/></>,
    plus:    <><path d="M12 5v14M5 12h14" {...p}/></>,
    check:   <><path d="M5 12l5 5 9-10" {...p}/></>,
    lock:    <><rect x="5" y="11" width="14" height="9" rx="2" {...p}/><path d="M8 11V8a4 4 0 018 0v3" {...p}/></>,
    eye:     <><path d="M2 12s4-7 10-7 10 7 10 7-4 7-10 7S2 12 2 12z" {...p}/><circle cx="12" cy="12" r="3" {...p}/></>,
    eyeoff:  <><path d="M4 4l16 16" {...p}/><path d="M9.5 5.5A10 10 0 0112 5c6 0 10 7 10 7a18 18 0 01-3.2 3.7M6.2 6.2C3.5 8.2 2 12 2 12s4 7 10 7c1.6 0 3-.4 4.2-1" {...p}/></>,
    filter:  <><path d="M3 5h18l-7 9v6l-4-2v-4z" {...p}/></>,
    settings:<><circle cx="12" cy="12" r="3" {...p}/><path d="M19 12a7 7 0 00-.1-1.2l2-1.5-2-3.4-2.4.8a7 7 0 00-2.1-1.2L14 3h-4l-.4 2.5a7 7 0 00-2.1 1.2l-2.4-.8-2 3.4 2 1.5A7 7 0 005 12a7 7 0 00.1 1.2l-2 1.5 2 3.4 2.4-.8a7 7 0 002.1 1.2L10 21h4l.4-2.5a7 7 0 002.1-1.2l2.4.8 2-3.4-2-1.5c0-.4.1-.8.1-1.2z" {...p}/></>,
    map:     <><path d="M9 4L3 6v14l6-2 6 2 6-2V4l-6 2z" {...p}/><path d="M9 4v14M15 6v14" {...p}/></>,
    grid:    <><rect x="3" y="3" width="7" height="7" rx="1" {...p}/><rect x="14" y="3" width="7" height="7" rx="1" {...p}/><rect x="3" y="14" width="7" height="7" rx="1" {...p}/><rect x="14" y="14" width="7" height="7" rx="1" {...p}/></>,
    list:    <><path d="M4 6h16M4 12h16M4 18h16" {...p}/></>,
    edit:    <><path d="M4 20l4-1 11-11-3-3L5 16l-1 4z" {...p}/></>,
    heart:   <><path d="M12 20s-7-4.5-7-10a4 4 0 017-2.7A4 4 0 0119 10c0 5.5-7 10-7 10z" {...p}/></>,
    spark:   <><path d="M12 3l1.5 4.5L18 9l-4.5 1.5L12 15l-1.5-4.5L6 9l4.5-1.5z" {...p}/></>,
    line:    <><rect x="3" y="4" width="18" height="14" rx="4" {...p}/><path d="M7 9v4M7 9h2.5M11 9v4M14 9v4M14 9l2.5 4M16.5 9v4" {...p}/></>,
    share:   <><circle cx="6" cy="12" r="2.5" {...p}/><circle cx="18" cy="6" r="2.5" {...p}/><circle cx="18" cy="18" r="2.5" {...p}/><path d="M8 11l8-4M8 13l8 4" {...p}/></>,
    close:   <><path d="M6 6l12 12M18 6L6 18" {...p}/></>,
    sparkle: <><path d="M12 2v6M12 16v6M2 12h6M16 12h6M5 5l4 4M15 15l4 4M19 5l-4 4M9 15l-4 4" {...p}/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" style={{ display: "block" }}>
      {paths[name]}
    </svg>
  );
}

// ──────────────────────────────────────────────
// Photo placeholder — striped paper with monospace label
// ──────────────────────────────────────────────
function Photo({ hue = 30, label, year, kind = "portrait", style = {}, sepia = false }) {
  const a = `oklch(0.88 0.06 ${hue})`;
  const b = `oklch(0.78 0.09 ${hue})`;
  const c = `oklch(0.62 0.12 ${hue})`;
  return (
    <div style={{
      position: "relative", width: "100%", height: "100%",
      background: `repeating-linear-gradient(135deg, ${a} 0 12px, ${b} 12px 24px)`,
      overflow: "hidden",
      filter: sepia ? "sepia(0.45) saturate(0.7) contrast(1.05)" : "none",
      ...style,
    }}>
      <div style={{
        position: "absolute", inset: 0,
        background: `radial-gradient(circle at 30% 30%, ${c}66 0%, transparent 55%)`,
      }} />
      {kind === "portrait" && (
        <div style={{
          position: "absolute", left: "50%", bottom: 0, transform: "translateX(-50%)",
          width: "55%", height: "70%", borderRadius: "50% 50% 0 0 / 60% 60% 0 0",
          background: `oklch(0.55 0.10 ${hue})`, opacity: 0.55,
        }} />
      )}
      {label && (
        <div style={{
          position: "absolute", left: 8, bottom: 6, right: 8,
          fontFamily: "'IBM Plex Mono', monospace", fontSize: 8.5, letterSpacing: 0.6,
          color: "rgba(255,255,255,0.92)", textShadow: "0 1px 2px rgba(0,0,0,0.35)",
          textTransform: "uppercase", lineHeight: 1.1,
          display: "flex", justifyContent: "space-between", gap: 6,
        }}>
          <span>{label}</span>
          {year && <span>{year}</span>}
        </div>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────
// Avatar — circular Photo
// ──────────────────────────────────────────────
function Avatar({ person, size = 44, sepia = false, ring }) {
  const initials = (person.nick || person.name || "?").slice(0, 2);
  return (
    <div style={{
      width: size, height: size, borderRadius: "50%", overflow: "hidden", flexShrink: 0,
      position: "relative", boxShadow: ring ? `0 0 0 2px ${ring}, 0 0 0 4px var(--paper)` : "none",
    }}>
      <Photo hue={person.hue} kind="portrait" sepia={sepia} />
      <div style={{
        position: "absolute", inset: 0, display: "flex", alignItems: "center", justifyContent: "center",
        fontFamily: "'Newsreader', serif", fontWeight: 600, fontSize: size * 0.34,
        color: "rgba(255,255,255,0.94)", textShadow: "0 1px 2px rgba(0,0,0,0.4)",
        letterSpacing: -0.5,
      }}>
        {initials}
      </div>
      {person.online && (
        <div style={{
          position: "absolute", right: 1, bottom: 1, width: size * 0.22, height: size * 0.22,
          background: "#4b9d54", borderRadius: "50%", border: "2px solid var(--paper)",
        }}/>
      )}
    </div>
  );
}

// ──────────────────────────────────────────────
// Chip
// ──────────────────────────────────────────────
function Chip({ children, active = false, onClick, count, size = "md" }) {
  const pad = size === "sm" ? "5px 10px" : "7px 12px";
  const fs  = size === "sm" ? 12 : 13;
  return (
    <button onClick={onClick} style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      padding: pad, borderRadius: 999,
      border: `1px solid ${active ? "var(--ink)" : "var(--border)"}`,
      background: active ? "var(--ink)" : "transparent",
      color: active ? "var(--paper)" : "var(--ink)",
      fontSize: fs, fontFamily: "var(--ui)", whiteSpace: "nowrap", cursor: "pointer",
      transition: "all .15s",
    }}>
      {children}
      {count != null && (
        <span style={{
          fontFamily: "'IBM Plex Mono', monospace", fontSize: fs - 2,
          opacity: 0.65, fontWeight: 500,
        }}>{count}</span>
      )}
    </button>
  );
}

// ──────────────────────────────────────────────
// Yearbook stamp — small badge with serial
// ──────────────────────────────────────────────
function YearStamp({ children, serial }) {
  return (
    <div style={{
      display: "inline-flex", alignItems: "center", gap: 8,
      padding: "3px 9px 3px 8px", borderRadius: 4,
      border: "1px dashed var(--ink-muted)",
      fontFamily: "'IBM Plex Mono', monospace", fontSize: 10,
      letterSpacing: 1, textTransform: "uppercase", color: "var(--ink-muted)",
    }}>
      <span>{children}</span>
      {serial && <span style={{ color: "var(--ink)" }}>{serial}</span>}
    </div>
  );
}

// ──────────────────────────────────────────────
// Sheet — bottom sheet
// ──────────────────────────────────────────────
function Sheet({ open, onClose, children, height = "80%" }) {
  return (
    <div style={{
      position: "absolute", inset: 0, zIndex: 80,
      pointerEvents: open ? "auto" : "none",
    }}>
      <div onClick={onClose} style={{
        position: "absolute", inset: 0, background: "rgba(35,28,22,0.45)",
        opacity: open ? 1 : 0, transition: "opacity .25s",
      }}/>
      <div style={{
        position: "absolute", left: 0, right: 0, bottom: 0,
        height, background: "var(--paper)",
        borderRadius: "20px 20px 0 0",
        boxShadow: "0 -20px 50px rgba(35,28,22,0.18)",
        transform: open ? "translateY(0)" : "translateY(100%)",
        transition: "transform .35s cubic-bezier(.2,.8,.2,1)",
        display: "flex", flexDirection: "column", overflow: "hidden",
      }}>
        <div style={{
          width: 38, height: 4, borderRadius: 2, background: "var(--border)",
          margin: "8px auto 4px",
        }}/>
        {children}
      </div>
    </div>
  );
}

// ──────────────────────────────────────────────
// Province → coords for the schematic map
// ──────────────────────────────────────────────
window.PROVINCE_COORDS = {
  "กรุงเทพมหานคร": [50, 62],
  "นนทบุรี":       [48, 60],
  "เชียงใหม่":     [29, 22],
  "เชียงราย":     [33, 14],
  "ขอนแก่น":      [55, 40],
  "อุดรธานี":     [56, 33],
  "ภูเก็ต":        [33, 90],
  "ตรัง":         [38, 88],
  "เลย":          [48, 32],
  "สงขลา":        [44, 92],
};

Object.assign(window, {
  Icon, Photo, Avatar, Chip, YearStamp, Sheet,
});
