// Shared UI primitives

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

// === Avatar ===
const Avatar = ({ hue = 200, glyph = "?", size = 32, ring = false }) => {
  const bg = `oklch(82% 0.09 ${hue})`;
  const fg = `oklch(30% 0.08 ${hue})`;
  return (
    <div style={{
      width: size, height: size, borderRadius: "50%",
      background: bg, color: fg,
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      fontSize: size * 0.42, fontWeight: 600, flexShrink: 0,
      boxShadow: ring ? "0 0 0 2px var(--surface), 0 0 0 3px var(--border-strong)" : "none",
      fontFamily: "var(--font-sans)",
    }}>{glyph}</div>
  );
};

// === Badge ===
const Badge = ({ tone = "default", children, dot = false, size = "md" }) => {
  const tones = {
    default: { bg: "var(--surface-2)", fg: "var(--ink-2)", bd: "var(--border)" },
    accent:  { bg: "var(--accent-soft)", fg: "var(--accent-ink)", bd: "#F5D5CB" },
    success: { bg: "var(--success-soft)", fg: "#1E6B40", bd: "#C8E3D4" },
    warn:    { bg: "var(--warn-soft)", fg: "#8C5A14", bd: "#EBD6A8" },
    danger:  { bg: "var(--danger-soft)", fg: "#8C2525", bd: "#E8C4C4" },
    info:    { bg: "var(--info-soft)", fg: "#2B4D8F", bd: "#CBD8EF" },
    ink:     { bg: "var(--ink)", fg: "#fff", bd: "var(--ink)" },
    ghost:   { bg: "transparent", fg: "var(--ink-3)", bd: "var(--border)" },
  };
  const t = tones[tone] || tones.default;
  const pad = size === "sm" ? "2px 7px" : "3px 9px";
  const fs = size === "sm" ? 11 : 12;
  return (
    <span style={{
      display: "inline-flex", alignItems: "center", gap: 6,
      background: t.bg, color: t.fg, border: `1px solid ${t.bd}`,
      padding: pad, borderRadius: 999, fontSize: fs, fontWeight: 500,
      lineHeight: 1.3, whiteSpace: "nowrap",
    }}>
      {dot && <span style={{ width: 6, height: 6, borderRadius: 999, background: t.fg }}/>}
      {children}
    </span>
  );
};

// === Button ===
const Button = ({ variant = "secondary", size = "md", icon, iconRight, children, onClick, disabled, danger, style = {}, ...rest }) => {
  const base = {
    display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6,
    fontWeight: 500, fontSize: 14, lineHeight: 1,
    borderRadius: 8, transition: "all .15s ease",
    whiteSpace: "nowrap",
    userSelect: "none",
    ...(disabled ? { opacity: 0.5, cursor: "not-allowed" } : {}),
  };
  const sizes = {
    sm: { padding: "6px 10px", fontSize: 13, height: 30 },
    md: { padding: "8px 14px", height: 36 },
    lg: { padding: "10px 18px", fontSize: 15, height: 42 },
    icon: { width: 34, height: 34, padding: 0 },
  };
  const variants = {
    primary: { background: danger ? "var(--danger)" : "var(--ink)", color: "#fff", border: "1px solid " + (danger ? "var(--danger)" : "var(--ink)") },
    secondary: { background: "var(--surface)", color: "var(--ink)", border: "1px solid var(--border-strong)" },
    ghost: { background: "transparent", color: "var(--ink-2)", border: "1px solid transparent" },
    danger: { background: "var(--danger)", color: "#fff", border: "1px solid var(--danger)" },
    accent: { background: "var(--accent)", color: "#fff", border: "1px solid var(--accent)" },
    link: { background: "transparent", color: "var(--accent-ink)", border: "1px solid transparent", padding: 0, height: "auto" },
  };
  return (
    <button
      onClick={disabled ? undefined : onClick}
      onMouseEnter={e => {
        if (disabled) return;
        if (variant === "secondary") e.currentTarget.style.background = "var(--surface-2)";
        if (variant === "ghost") e.currentTarget.style.background = "var(--surface-2)";
        if (variant === "primary") e.currentTarget.style.background = "#2A2620";
        if (variant === "accent") e.currentTarget.style.background = "#D14F2D";
        if (variant === "danger") e.currentTarget.style.background = "#A82F2F";
      }}
      onMouseLeave={e => {
        if (variant === "secondary") e.currentTarget.style.background = "var(--surface)";
        if (variant === "ghost") e.currentTarget.style.background = "transparent";
        if (variant === "primary") e.currentTarget.style.background = danger ? "var(--danger)" : "var(--ink)";
        if (variant === "accent") e.currentTarget.style.background = "var(--accent)";
        if (variant === "danger") e.currentTarget.style.background = "var(--danger)";
      }}
      style={{ ...base, ...sizes[size], ...variants[variant], ...style }}
      {...rest}
    >
      {icon && <Icon name={icon} size={size === "sm" ? 14 : 16} />}
      {children}
      {iconRight && <Icon name={iconRight} size={size === "sm" ? 14 : 16} />}
    </button>
  );
};

// === Input ===
const Input = ({ icon, value, onChange, placeholder, type = "text", style = {}, ...rest }) => {
  const [focused, setFocused] = useState(false);
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 8,
      background: "var(--surface)",
      border: "1px solid " + (focused ? "var(--ink)" : "var(--border-strong)"),
      borderRadius: 8, padding: "0 12px", height: 36,
      transition: "border-color .15s",
      boxShadow: focused ? "0 0 0 3px rgba(26,24,20,0.06)" : "none",
      ...style,
    }}>
      {icon && <Icon name={icon} size={16} style={{ color: "var(--ink-3)" }}/>}
      <input
        value={value} onChange={onChange} placeholder={placeholder} type={type}
        onFocus={() => setFocused(true)} onBlur={() => setFocused(false)}
        style={{ flex: 1, border: 0, outline: 0, background: "transparent", fontSize: 14, minWidth: 0 }}
        {...rest}
      />
    </div>
  );
};

// === Card ===
const Card = ({ children, padding = 20, style = {}, interactive = false, onClick }) => (
  <div
    onClick={onClick}
    style={{
      background: "var(--surface)",
      border: "1px solid var(--border)",
      borderRadius: 12,
      padding,
      transition: "border-color .15s, box-shadow .15s, transform .15s",
      cursor: interactive ? "pointer" : "default",
      ...style,
    }}
    onMouseEnter={interactive ? e => {
      e.currentTarget.style.borderColor = "var(--border-strong)";
      e.currentTarget.style.boxShadow = "var(--shadow)";
    } : undefined}
    onMouseLeave={interactive ? e => {
      e.currentTarget.style.borderColor = "var(--border)";
      e.currentTarget.style.boxShadow = "none";
    } : undefined}
  >
    {children}
  </div>
);

// === Modal ===
const Modal = ({ open, onClose, children, width = 480 }) => {
  useEffect(() => {
    if (!open) return;
    const onKey = e => { if (e.key === "Escape") onClose?.(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  if (!open) return null;
  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 100,
      background: "rgba(26,24,20,0.45)", backdropFilter: "blur(3px)",
      display: "flex", alignItems: "center", justifyContent: "center",
      padding: 20, animation: "overlayIn .18s ease-out",
    }} onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{
        background: "var(--surface)", borderRadius: 16,
        width: "100%", maxWidth: width, maxHeight: "88vh",
        overflow: "auto", boxShadow: "var(--shadow-lg)",
        animation: "modalIn .22s ease-out",
      }}>
        {children}
      </div>
    </div>
  );
};

// === Confirm Dialog (critical actions) ===
const ConfirmDialog = ({
  open, onClose, onConfirm, title, description,
  requireText, requireTextHint, requireOtp,
  requireReason = true, reasonLabel = "操作原因", reasonPlaceholder = "說明此次操作的原因,將記錄到審計日誌…",
  extraField, extraField2,
  variant = "danger", icon = "alert", confirmText = "確認",
}) => {
  const [text, setText] = useState("");
  const [otp, setOtp] = useState("");
  const [reason, setReason] = useState("");
  const [extraVal, setExtraVal] = useState(extraField?.defaultValue || "");
  const [extraVal2, setExtraVal2] = useState(extraField2?.defaultValue || "");
  const [loading, setLoading] = useState(false);
  useEffect(() => { if (open) { setText(""); setOtp(""); setReason(""); setExtraVal(extraField?.defaultValue || ""); setExtraVal2(extraField2?.defaultValue || ""); setLoading(false); } }, [open]);
  const textValid = !requireText || text.trim() === requireText;
  const otpValid = !requireOtp || /^\d{6}$/.test(otp);
  const reasonValid = !requireReason || reason.trim().length >= 4;
  const canConfirm = textValid && otpValid && reasonValid && !loading;
  const toneColor = variant === "danger" ? "var(--danger)" : variant === "warn" ? "var(--warn)" : variant === "info" ? "var(--info)" : "var(--accent)";
  const toneBg = variant === "danger" ? "var(--danger-soft)" : variant === "warn" ? "var(--warn-soft)" : variant === "info" ? "var(--info-soft)" : "var(--accent-soft)";
  const btnVariant = variant === "danger" ? "danger" : "primary";

  return (
    <Modal open={open} onClose={loading ? undefined : onClose} width={480}>
      <div style={{ padding: 24 }}>
        <div style={{ display: "flex", gap: 14 }}>
          <div style={{
            width: 40, height: 40, borderRadius: 10,
            background: toneBg, color: toneColor,
            display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
          }}><Icon name={icon} size={20}/></div>
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 17, fontWeight: 600, marginBottom: 4 }}>{title}</div>
            <div style={{ fontSize: 13.5, color: "var(--ink-2)", lineHeight: 1.55 }}>{description}</div>
          </div>
        </div>

        <div style={{ marginTop: 20, display: "flex", flexDirection: "column", gap: 14 }}>
          {requireReason && (
            <div>
              <label style={labelStyle}>{reasonLabel} <span style={{ color: "var(--danger)" }}>*</span></label>
              <textarea
                value={reason} onChange={e => setReason(e.target.value)}
                placeholder={reasonPlaceholder}
                rows={2}
                style={{
                  width: "100%", padding: "8px 12px", fontSize: 14,
                  border: "1px solid var(--border-strong)", borderRadius: 8,
                  fontFamily: "var(--font-sans)", resize: "vertical", outline: 0,
                }}
              />
            </div>
          )}

          {extraField && (
            <div>
              <label style={labelStyle}>{extraField.label}</label>
              {extraField.type === "select" ? (
                <Select value={extraVal} onChange={setExtraVal} options={extraField.options}/>
              ) : (
                <Input value={extraVal} onChange={e => setExtraVal(e.target.value)} placeholder={extraField.placeholder}/>
              )}
            </div>
          )}

          {extraField2 && (
            <div>
              <label style={labelStyle}>{extraField2.label}</label>
              {extraField2.type === "select" ? (
                <Select value={extraVal2} onChange={setExtraVal2} options={extraField2.options}/>
              ) : (
                <Input value={extraVal2} onChange={e => setExtraVal2(e.target.value)} placeholder={extraField2.placeholder}/>
              )}
            </div>
          )}

          {requireText && (
            <div>
              <label style={labelStyle}>{requireTextHint || <>請輸入 <code style={{ background: "var(--surface-2)", padding: "1px 6px", borderRadius: 4, fontFamily: "var(--font-mono)" }}>{requireText}</code> 以確認</>}</label>
              <Input value={text} onChange={e => setText(e.target.value)} placeholder={requireText}/>
            </div>
          )}

          {requireOtp && (
            <div>
              <label style={labelStyle}>Email 驗證碼 <span style={{ color: "var(--ink-3)", fontWeight: 400 }}>(已發送至 you@duidui.com)</span></label>
              <Input value={otp} onChange={e => setOtp(e.target.value.replace(/\D/g, "").slice(0, 6))} placeholder="6 位數字" icon="mail"/>
            </div>
          )}

        </div>

        <div style={{
          marginTop: 18, padding: "10px 12px", background: "var(--surface-2)",
          borderRadius: 8, fontSize: 12, color: "var(--ink-2)",
          display: "flex", alignItems: "flex-start", gap: 8,
        }}>
          <Icon name="info" size={14} style={{ marginTop: 1, flexShrink: 0, color: "var(--ink-3)" }}/>
          <span>此操作將被完整記錄到 <b>審計日誌</b>,包含操作人、IP、時間、原因。</span>
        </div>

        <div style={{ display: "flex", gap: 8, marginTop: 20, justifyContent: "flex-end" }}>
          <Button variant="secondary" onClick={onClose} disabled={loading}>取消</Button>
          <Button
            variant={btnVariant}
            disabled={!canConfirm}
            onClick={() => {
              setLoading(true);
              setTimeout(() => { onConfirm?.({ reason, otp, text, extra: extraVal, extra2: extraVal2 }); setLoading(false); }, 600);
            }}
          >{loading ? "處理中…" : confirmText}</Button>
        </div>
      </div>
    </Modal>
  );
};

const labelStyle = {
  display: "block", fontSize: 12.5, fontWeight: 500,
  color: "var(--ink-2)", marginBottom: 6,
};

// === Toast ===
const ToastContext = React.createContext(null);
const ToastProvider = ({ children }) => {
  const [toasts, setToasts] = useState([]);
  const push = useCallback((toast) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { id, ...toast }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), toast.duration || 3400);
  }, []);
  return (
    <ToastContext.Provider value={push}>
      {children}
      <div style={{ position: "fixed", top: 20, right: 20, zIndex: 200, display: "flex", flexDirection: "column", gap: 8 }}>
        {toasts.map(t => (
          <div key={t.id} style={{
            background: "var(--ink)", color: "#fff", padding: "10px 14px",
            borderRadius: 10, fontSize: 13.5, boxShadow: "var(--shadow-lg)",
            minWidth: 260, maxWidth: 380, display: "flex", alignItems: "flex-start", gap: 10,
            animation: "modalIn .2s ease-out",
          }}>
            <Icon name={t.icon || "check"} size={16} style={{ marginTop: 2, color: t.tone === "danger" ? "#FF8C8C" : t.tone === "warn" ? "#FFC87A" : "#7FE2B6", flexShrink: 0 }}/>
            <div style={{ flex: 1, lineHeight: 1.45 }}>
              {t.title && <div style={{ fontWeight: 600, marginBottom: 2 }}>{t.title}</div>}
              <div style={{ opacity: 0.85 }}>{t.message}</div>
            </div>
          </div>
        ))}
      </div>
    </ToastContext.Provider>
  );
};
const useToast = () => React.useContext(ToastContext);

// === Masked Value (sensitive data) ===
const MaskedValue = ({ value, type = "phone", onReveal }) => {
  const [revealed, setRevealed] = useState(false);
  const masked = useMemo(() => {
    if (type === "phone") return value.slice(0, 4) + "•••" + value.slice(-3);
    if (type === "bank") return value.replace(/\d(?=\d{4})/g, "•");
    if (type === "email") {
      const [n, d] = value.split("@");
      return n.slice(0, 2) + "•••@" + d;
    }
    return "•••";
  }, [value, type]);
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontFamily: "var(--font-mono)", fontSize: 13 }}>
      {revealed ? value : masked}
      <button
        onClick={() => {
          if (!revealed) onReveal?.(() => setRevealed(true));
          else setRevealed(false);
        }}
        style={{ color: "var(--ink-3)", padding: 2, display: "inline-flex" }}
        title={revealed ? "重新遮蔽" : "查看明碼"}
      >
        <Icon name={revealed ? "eye-off" : "eye"} size={14}/>
      </button>
    </span>
  );
};

// === Table ===
const Table = ({ columns, rows, onRowClick, selectable, selected, onSelect, empty }) => {
  const allSelected = selectable && rows.length > 0 && rows.every(r => selected?.has(r.id));
  return (
    <div style={{ border: "1px solid var(--border)", borderRadius: 12, overflow: "hidden", background: "var(--surface)" }}>
      <table style={{ width: "100%", borderCollapse: "collapse", tableLayout: "auto" }}>
        <thead>
          <tr style={{ background: "var(--surface-2)" }}>
            {selectable && (
              <th style={{ ...thStyle, width: 44 }}>
                <Checkbox checked={allSelected} onChange={v => onSelect?.(v ? new Set(rows.map(r=>r.id)) : new Set())}/>
              </th>
            )}
            {columns.map((c, i) => (
              <th key={i} style={{ ...thStyle, textAlign: c.align || "left", width: c.width }}>{c.title}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {rows.length === 0 ? (
            <tr><td colSpan={columns.length + (selectable?1:0)} style={{ padding: 60, textAlign: "center", color: "var(--ink-3)" }}>{empty || "沒有資料"}</td></tr>
          ) : rows.map((row, i) => (
            <tr key={row.id || i}
              onClick={onRowClick ? () => onRowClick(row) : undefined}
              style={{
                borderTop: "1px solid var(--border)",
                cursor: onRowClick ? "pointer" : "default",
                background: "var(--surface)",
                transition: "background .12s",
              }}
              onMouseEnter={e => e.currentTarget.style.background = "#FCFBF8"}
              onMouseLeave={e => e.currentTarget.style.background = "var(--surface)"}
            >
              {selectable && (
                <td style={tdStyle} onClick={e => e.stopPropagation()}>
                  <Checkbox
                    checked={selected?.has(row.id)}
                    onChange={v => {
                      const s = new Set(selected); v ? s.add(row.id) : s.delete(row.id);
                      onSelect?.(s);
                    }}
                  />
                </td>
              )}
              {columns.map((c, j) => (
                <td key={j} style={{ ...tdStyle, textAlign: c.align || "left" }}>
                  {c.render ? c.render(row) : row[c.key]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};
const thStyle = { padding: "12px 16px", fontSize: 12, fontWeight: 500, color: "var(--ink-3)", textTransform: "none", letterSpacing: 0.2, textAlign: "left" };
const tdStyle = { padding: "14px 16px", fontSize: 13.5, color: "var(--ink)", verticalAlign: "middle" };

// === Checkbox ===
const Checkbox = ({ checked, onChange, size = 16 }) => (
  <button
    onClick={e => { e.stopPropagation(); onChange?.(!checked); }}
    style={{
      width: size, height: size, borderRadius: 4,
      border: "1.5px solid " + (checked ? "var(--ink)" : "var(--border-strong)"),
      background: checked ? "var(--ink)" : "var(--surface)",
      display: "inline-flex", alignItems: "center", justifyContent: "center",
      transition: "all .12s", padding: 0, flexShrink: 0,
    }}
  >
    {checked && <Icon name="check" size={size - 4} style={{ color: "#fff", strokeWidth: 3 }}/>}
  </button>
);

// === Tabs ===
const Tabs = ({ tabs, active, onChange }) => (
  <div style={{ display: "flex", gap: 4, borderBottom: "1px solid var(--border)" }}>
    {tabs.map(t => (
      <button key={t.value} onClick={() => onChange(t.value)} style={{
        padding: "10px 14px", fontSize: 13.5, fontWeight: active === t.value ? 600 : 500,
        color: active === t.value ? "var(--ink)" : "var(--ink-3)",
        borderBottom: "2px solid " + (active === t.value ? "var(--ink)" : "transparent"),
        marginBottom: -1, display: "inline-flex", alignItems: "center", gap: 6,
      }}>
        {t.label}
        {t.count != null && (
          <span style={{
            background: t.tone === "danger"
              ? "var(--danger)"
              : active === t.value ? "var(--ink)" : "var(--surface-2)",
            color: (t.tone === "danger" || active === t.value) ? "#fff" : "var(--ink-3)",
            fontSize: 11, padding: "1px 7px", borderRadius: 999, fontWeight: 500,
          }}>{t.count}</span>
        )}
      </button>
    ))}
  </div>
);

// === Select (light) ===
const Select = ({ value, onChange, options, placeholder = "選擇…", icon, style = {} }) => {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    const onClick = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, []);
  const cur = options.find(o => o.value === value);
  return (
    <div ref={ref} style={{ position: "relative", ...style }}>
      <button onClick={() => setOpen(o => !o)} style={{
        display: "inline-flex", alignItems: "center", gap: 8,
        padding: "0 12px", height: 36, borderRadius: 8,
        border: "1px solid var(--border-strong)", background: "var(--surface)",
        fontSize: 14, minWidth: 140, justifyContent: "space-between",
      }}>
        <span style={{ display: "inline-flex", alignItems: "center", gap: 8 }}>
          {icon && <Icon name={icon} size={14} style={{ color: "var(--ink-3)" }}/>}
          <span style={{ color: cur ? "var(--ink)" : "var(--ink-3)" }}>{cur?.label || placeholder}</span>
        </span>
        <Icon name="chevron-down" size={14} style={{ color: "var(--ink-3)" }}/>
      </button>
      {open && (
        <div style={{
          position: "absolute", top: "calc(100% + 4px)", left: 0, minWidth: "100%",
          background: "var(--surface)", border: "1px solid var(--border)",
          borderRadius: 8, padding: 4, boxShadow: "var(--shadow-lg)", zIndex: 10,
        }}>
          {options.map(o => (
            <button key={o.value} onClick={() => { onChange(o.value); setOpen(false); }} style={{
              display: "flex", alignItems: "center", justifyContent: "space-between", width: "100%",
              padding: "7px 10px", fontSize: 13.5, borderRadius: 6, textAlign: "left",
              background: value === o.value ? "var(--surface-2)" : "transparent",
            }}
              onMouseEnter={e => { if (value !== o.value) e.currentTarget.style.background = "var(--surface-2)"; }}
              onMouseLeave={e => { if (value !== o.value) e.currentTarget.style.background = "transparent"; }}
            >
              <span>{o.label}</span>
              {value === o.value && <Icon name="check" size={14}/>}
            </button>
          ))}
        </div>
      )}
    </div>
  );
};

// === Drawer ===
const Drawer = ({ open, onClose, children, width = 560 }) => {
  useEffect(() => {
    if (!open) return;
    const onKey = e => { if (e.key === "Escape") onClose?.(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);
  return (
    <div style={{
      position: "fixed", inset: 0, zIndex: 90,
      pointerEvents: open ? "auto" : "none",
    }}>
      <div onClick={onClose} style={{
        position: "absolute", inset: 0, background: "rgba(26,24,20,0.35)",
        opacity: open ? 1 : 0, transition: "opacity .2s",
      }}/>
      <div style={{
        position: "absolute", top: 0, right: 0, bottom: 0,
        width, maxWidth: "92vw",
        background: "var(--surface)", boxShadow: "var(--shadow-lg)",
        transform: open ? "translateX(0)" : "translateX(100%)",
        transition: "transform .28s cubic-bezier(.2,.8,.2,1)",
        display: "flex", flexDirection: "column", overflow: "hidden",
      }}>
        {children}
      </div>
    </div>
  );
};

// === Switch ===
const Switch = ({ checked, onChange }) => (
  <button onClick={() => onChange?.(!checked)} style={{
    width: 34, height: 20, borderRadius: 999,
    background: checked ? "var(--ink)" : "var(--border-strong)",
    position: "relative", padding: 0, transition: "background .15s",
  }}>
    <div style={{
      position: "absolute", top: 2, left: checked ? 16 : 2,
      width: 16, height: 16, borderRadius: 999, background: "#fff",
      transition: "left .15s", boxShadow: "0 1px 2px rgba(0,0,0,0.15)",
    }}/>
  </button>
);

// === PageHeader ===
const PageHeader = ({ title, subtitle, actions, breadcrumb }) => (
  <div style={{ marginBottom: 24 }}>
    {breadcrumb && (
      <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 12.5, color: "var(--ink-3)", marginBottom: 10 }}>
        {breadcrumb.map((b, i) => (
          <React.Fragment key={i}>
            {i > 0 && <Icon name="chevron-right" size={12}/>}
            <span style={{ color: i === breadcrumb.length - 1 ? "var(--ink-2)" : "var(--ink-3)", cursor: b.onClick ? "pointer" : "default" }} onClick={b.onClick}>{b.label}</span>
          </React.Fragment>
        ))}
      </div>
    )}
    <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 16 }}>
      <div>
        <h1 style={{ fontSize: 24, fontWeight: 600, letterSpacing: -0.3 }}>{title}</h1>
        {subtitle && <div style={{ fontSize: 13.5, color: "var(--ink-3)", marginTop: 4 }}>{subtitle}</div>}
      </div>
      {actions && <div style={{ display: "flex", gap: 8, flexShrink: 0 }}>{actions}</div>}
    </div>
  </div>
);

// Simple sparkline (svg)
const Sparkline = ({ data, width = 120, height = 32, color = "var(--ink)", fill = true }) => {
  const max = Math.max(...data), min = Math.min(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / range) * (height - 4) - 2;
    return [x, y];
  });
  const d = pts.map(([x,y], i) => `${i===0?"M":"L"}${x.toFixed(1)},${y.toFixed(1)}`).join(" ");
  const fillD = d + ` L${width},${height} L0,${height} Z`;
  return (
    <svg width={width} height={height} style={{ display: "block" }}>
      {fill && <path d={fillD} fill={color} opacity={0.08}/>}
      <path d={d} fill="none" stroke={color} strokeWidth={1.5} strokeLinecap="round" strokeLinejoin="round"/>
    </svg>
  );
};

// Format currency TWD
const fmtCurrency = (n, showSymbol = true) => (showSymbol ? "NT$ " : "") + n.toLocaleString("en-US");
const fmtNum = n => n.toLocaleString("en-US");

const SEVERITY_COLORS = {
  low:      { bg: "var(--success)", label: "低" },
  medium:   { bg: "var(--warn)",    label: "中" },
  high:     { bg: "var(--danger)",  label: "高" },
  critical: { bg: "#9b1c1c",        label: "嚴重" },
};
const SeverityDot = ({ severity }) => {
  const c = SEVERITY_COLORS[severity] ?? SEVERITY_COLORS.low;
  return (
    <span style={{
      display: "inline-block", width: 8, height: 8, borderRadius: "50%",
      background: c.bg, flexShrink: 0,
    }} title={c.label}/>
  );
};

Object.assign(window, {
  Avatar, Badge, Button, Input, Card, Modal, ConfirmDialog,
  ToastProvider, useToast, MaskedValue, Table, Checkbox, Tabs, Select,
  Drawer, Switch, PageHeader, Sparkline, fmtCurrency, fmtNum, labelStyle,
  SeverityDot,
});
