// Lucide-style icons inline as React components (single-stroke, 16x16 default)
const Icon = ({ d, size = 16, fill, stroke = "currentColor", sw = 1.6, children, ...rest }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill={fill || "none"} stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round" {...rest}>
    {d && <path d={d} />}
    {children}
  </svg>;


const I = {
  Cursor: (p) => <Icon {...p} d="M5 3l6 16 2.5-6.5L20 10z" />,
  Move: (p) => <Icon {...p}><path d="M12 2v20M2 12h20M5 9l-3 3 3 3M19 9l3 3-3 3M9 5l3-3 3 3M9 19l3 3 3-3" /></Icon>,
  Image: (p) => <Icon {...p}><rect x="3" y="3" width="18" height="18" rx="2" style={{ stroke: "rgb(30, 30, 30)" }} /><circle cx="9" cy="9" r="1.6" style={{ stroke: "rgb(30, 30, 30)" }} /><path d="M21 16l-5-5L5 21" style={{ stroke: "rgb(30, 30, 30)" }} /></Icon>,
  Text: (p) => <Icon {...p}><path d="M4 6V4h16v2M9 20h6M12 4v16" /></Icon>,
  Shape: (p) => <Icon {...p}><rect x="3" y="3" width="14" height="14" rx="1.5" /><circle cx="17" cy="17" r="4" /></Icon>,
  Mask: (p) => <Icon {...p}><rect x="3" y="3" width="18" height="18" rx="2" /><circle cx="12" cy="12" r="5" fill="currentColor" stroke="none" /></Icon>,
  Frame: (p) => <Icon {...p}><path d="M22 6H2M22 18H2M6 2v20M18 2v20" style={{ stroke: "rgb(30, 30, 30)" }} /></Icon>,
  Hand: (p) => <Icon {...p}><path d="M18 11V6.5a1.5 1.5 0 0 0-3 0v4M15 10.5V4.5a1.5 1.5 0 0 0-3 0V11M12 11V5.5a1.5 1.5 0 0 0-3 0V12M9 12V8.5a1.5 1.5 0 0 0-3 0v6.5a7 7 0 0 0 7 7c3.5 0 5-2 5-4.5" /></Icon>,
  Logo: (p) => <Icon {...p}><path d="M12 3l3 3-3 3-3-3z" style={{ stroke: "rgb(30, 30, 30)" }} /><path d="M12 15l3 3-3 3-3-3z" style={{ stroke: "rgb(30, 30, 30)" }} /><path d="M6 9l3 3-3 3-3-3z" style={{ stroke: "rgb(30, 30, 30)" }} /><path d="M18 9l3 3-3 3-3-3z" style={{ stroke: "rgb(30, 30, 30)" }} /></Icon>,
  Eye: (p) => <Icon {...p}><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z" /><circle cx="12" cy="12" r="3" /></Icon>,
  EyeOff: (p) => <Icon {...p}><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a17.7 17.7 0 0 1-3.66 4.93M14.12 14.12A3 3 0 1 1 9.88 9.88M2 2l20 20M6.61 6.61A14.7 14.7 0 0 0 1 12s4 8 11 8a9.74 9.74 0 0 0 5.39-1.61" /></Icon>,
  Lock: (p) => <Icon {...p}><rect x="3" y="11" width="18" height="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></Icon>,
  Unlock: (p) => <Icon {...p}><rect x="3" y="11" width="18" height="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 9.9-1" /></Icon>,
  Plus: (p) => <Icon {...p}><path d="M12 5v14M5 12h14" /></Icon>,
  Minus: (p) => <Icon {...p}><path d="M5 12h14" /></Icon>,
  Trash: (p) => <Icon {...p}><path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" /></Icon>,
  Copy: (p) => <Icon {...p}><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></Icon>,
  Up: (p) => <Icon {...p}><path d="M18 15l-6-6-6 6" /></Icon>,
  Down: (p) => <Icon {...p}><path d="M6 9l6 6 6-6" /></Icon>,
  Left: (p) => <Icon {...p}><path d="M15 18l-6-6 6-6" /></Icon>,
  Right: (p) => <Icon {...p}><path d="M9 6l6 6-6 6" /></Icon>,
  Layers: (p) => <Icon {...p}><path d="M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5" /></Icon>,
  Grid: (p) => <Icon {...p}><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="14" y="14" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /></Icon>,
  Sparkles: (p) => <Icon {...p}><path d="M12 3l1.9 4.6L18.5 9.5 13.9 11.4 12 16l-1.9-4.6L5.5 9.5l4.6-1.9zM19 14l.8 2 2 .8-2 .8L19 20l-.8-2-2-.8 2-.8zM5 14l.6 1.5 1.5.6-1.5.6L5 18.2l-.6-1.5L2.9 16l1.5-.6z" /></Icon>,
  Wand: (p) => <Icon {...p}><path d="M15 4V2M15 16v-2M8 9h2M20 9h2M17.8 11.8l1.4 1.4M17.8 6.2l1.4-1.4M3 21l9-9M12.2 6.2l-1.4-1.4" /></Icon>,
  Upload: (p) => <Icon {...p}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M17 8l-5-5-5 5M12 3v12" /></Icon>,
  Download: (p) => <Icon {...p}><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3" /></Icon>,
  Check: (p) => <Icon {...p}><path d="M20 6L9 17l-5-5" /></Icon>,
  Close: (p) => <Icon {...p}><path d="M18 6L6 18M6 6l12 12" /></Icon>,
  Chevron: (p) => <Icon {...p}><path d="M6 9l6 6 6-6" /></Icon>,
  Settings: (p) => <Icon {...p}><circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" /></Icon>,
  Share: (p) => <Icon {...p}><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8M16 6l-4-4-4 4M12 2v13" /></Icon>,
  Play: (p) => <Icon {...p}><path d="M5 3l14 9-14 9V3z" fill="currentColor" /></Icon>,
  Folder: (p) => <Icon {...p}><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" /></Icon>,
  Type: (p) => <Icon {...p}><path d="M4 7V4h16v3M9 20h6M12 4v16" style={{ stroke: "rgb(30, 30, 30)" }} /></Icon>,
  Square: (p) => <Icon {...p}><rect x="3" y="3" width="18" height="18" rx="2" style={{ stroke: "rgb(30, 30, 30)" }} /></Icon>,
  Sort: (p) => <Icon {...p}><path d="M3 6h13M3 12h9M3 18h5M17 8l4-4 4 4M21 4v16" /></Icon>,
  Star: (p) => <Icon {...p}><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01z" /></Icon>,
  Refresh: (p) => <Icon {...p}><path d="M23 4v6h-6M1 20v-6h6M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15" /></Icon>,
  Grip: (p) => <Icon {...p}><circle cx="9" cy="6" r="1" fill="currentColor" /><circle cx="15" cy="6" r="1" fill="currentColor" /><circle cx="9" cy="12" r="1" fill="currentColor" /><circle cx="15" cy="12" r="1" fill="currentColor" /><circle cx="9" cy="18" r="1" fill="currentColor" /><circle cx="15" cy="18" r="1" fill="currentColor" /></Icon>,
  Bold: (p) => <Icon {...p}><path d="M6 4h8a4 4 0 0 1 0 8H6zM6 12h9a4 4 0 0 1 0 8H6z" /></Icon>,
  Align: {
    Left: (p) => <Icon {...p}><path d="M17 10H3M21 6H3M21 14H3M17 18H3" /></Icon>,
    Center: (p) => <Icon {...p}><path d="M18 10H6M21 6H3M21 14H3M18 18H6" /></Icon>,
    Right: (p) => <Icon {...p}><path d="M21 10H7M21 6H3M21 14H3M21 18H7" /></Icon>
  },
  Zap: (p) => <Icon {...p}><path d="M13 2 3 14h9l-1 8 10-12h-9z" /></Icon>,
  Scissors: (p) => <Icon {...p}><circle cx="6" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M20 4 8.12 15.88M14.47 14.48 20 20M8.12 8.12 12 12" /></Icon>,
  Edit2: (p) => <Icon {...p}><path d="M17 3a2.85 2.85 0 0 1 4 4L7.5 20.5 2 22l1.5-5.5z" /></Icon>,
  AlertCircle: (p) => <Icon {...p}><circle cx="12" cy="12" r="10" /><path d="M12 8v4M12 16h.01" /></Icon>,
  Palette: (p) => <Icon {...p}><path d="M12 2a10 10 0 0 0 0 20c1.1 0 2-.9 2-2 0-.5-.2-.95-.5-1.3-.3-.34-.5-.79-.5-1.2 0-1.1.9-2 2-2h2.5A4.5 4.5 0 0 0 22 11c0-4.97-4.48-9-10-9z" /><circle cx="7.5" cy="11.5" r="1.2" fill="currentColor" /><circle cx="12" cy="7.5" r="1.2" fill="currentColor" /><circle cx="16.5" cy="11.5" r="1.2" fill="currentColor" /></Icon>
};

// Bannerly brand mark — white banner bar + shorter translucent bar, on the gradient chip
const BannerMark = ({ size = 16 }) =>
<svg width={size} height={size} viewBox="0 0 24 24" fill="none">
    <rect x="3" y="5" width="18" height="9" rx="2" fill="#fff" opacity="0.95" />
    <rect x="6" y="16" width="12" height="3" rx="1.5" fill="#fff" opacity="0.6" />
  </svg>;

Object.assign(window, { Icon, I, BannerMark });

// Shared dark dropdown (replaces native <select>) — matches the color-format menu UI.
// options: array of { value, label } or plain strings. onChange returns the original typed value.
function DSelect({ value, options, onChange, className, style, menuWidth }) {
  const [open, setOpen] = React.useState(false);
  const [pos, setPos] = React.useState(null);
  const btnRef = React.useRef(null);
  const menuRef = React.useRef(null);
  const opts = options.map((o) => o && typeof o === "object" ? o : { value: o, label: String(o) });
  const current = opts.find((o) => String(o.value) === String(value)) || opts[0];

  const toggle = () => {
    if (open) {setOpen(false);return;}
    const r = btnRef.current.getBoundingClientRect();
    setPos({ left: r.left, top: r.bottom + 4, width: r.width });
    setOpen(true);
  };

  // After the menu mounts, flip it above the trigger when it would overflow the
  // viewport bottom (so the dropdown direction adapts to available space / resolution).
  React.useLayoutEffect(() => {
    if (!open || !menuRef.current || !btnRef.current) return;
    const menuH = menuRef.current.offsetHeight;
    const r = btnRef.current.getBoundingClientRect();
    const margin = 6;
    const fitsBelow = r.bottom + 4 + menuH + margin <= window.innerHeight;
    const fitsAbove = r.top - 4 - menuH - margin >= 0;
    const top = !fitsBelow && fitsAbove ? r.top - menuH - 4 : r.bottom + 4;
    setPos((p) => p && top !== p.top ? { ...p, top } : p);
  }, [open]);

  return (
    <React.Fragment>
      <button
        ref={btnRef}
        type="button"
        className={"dsel" + (className ? " " + className : "")}
        style={{ ...style, height: "24px" }}
        onClick={toggle}>
        <span className="dsel-val">{current ? current.label : ""}</span>
        <span className="dsel-caret"><I.Chevron size={12} /></span>
      </button>
      {open && pos && ReactDOM.createPortal(
        <React.Fragment>
          <div className="dsel-backdrop" onMouseDown={() => setOpen(false)} />
          <div
            ref={menuRef}
            className="dsel-menu"
            style={{ left: pos.left, top: pos.top, minWidth: menuWidth || pos.width }}>
            {opts.map((o) => {
              const active = String(o.value) === String(value);
              return (
                <button
                  key={String(o.value)}
                  type="button"
                  className={"dsel-opt" + (active ? " is-active" : "")}
                  onClick={() => {onChange(o.value);setOpen(false);}} style={{ fontSize: "12px" }}>
                  <span className="dsel-check">{active && <I.Check size={13} stroke="#fff" />}</span>
                  {o.label}
                </button>);
            })}
          </div>
        </React.Fragment>,
        document.body)}
    </React.Fragment>);
}

const FONT_OPTIONS = ["Pretendard", "Noto Sans KR", "Nanum Gothic", "SUIT"];
const WEIGHT_OPTIONS = [
{ value: 300, label: "Light" },
{ value: 400, label: "Regular" },
{ value: 500, label: "Medium" },
{ value: 600, label: "SemiBold" },
{ value: 700, label: "Bold" },
{ value: 800, label: "ExtraBold" },
{ value: 900, label: "Black" }];

Object.assign(window, { DSelect, FONT_OPTIONS, WEIGHT_OPTIONS });

// A color chip keeps its outline only when it would otherwise be invisible:
// empty/transparent ("배경없음") or any near-white from #ededed up to #ffffff.
function chipNeedsBorder(v) {
  if (!v) return true;
  const h = String(v).trim().toLowerCase().replace(/^#/, "");
  const full = h.length === 3 ? h.split("").map((c) => c + c).join("") : h.slice(0, 6);
  if (!/^[0-9a-f]{6}$/.test(full)) return false;
  const r = parseInt(full.slice(0, 2), 16);
  const g = parseInt(full.slice(2, 4), 16);
  const b = parseInt(full.slice(4, 6), 16);
  // 0xeb = 235 — every channel must be at least this light (ebebeb → ffffff).
  return r >= 0xeb && g >= 0xeb && b >= 0xeb;
}

Object.assign(window, { chipNeedsBorder });