/* Wizards — a marketplace of social-media experts. Users get free tips, best
   practices, ideas and short videos; experts publish profiles + bookable
   services (booked per job — simulated, no payment). Anyone can publish their
   own expert profile. Exposed as window.WizardsView. */
(function () {
  const S = window.CroprStore;
  const D = window.CROPR_DATA;
  const SV = D.WIZARD_SERVICES, CT = D.WIZARD_CONTENT_TYPES;
  const fieldStyle = { width: "100%", boxSizing: "border-box", fontFamily: "inherit", fontSize: 13.5, color: "var(--fg1)", background: "var(--surface)", border: "1px solid var(--border-strong)", borderRadius: 10, padding: "9px 11px", outline: "none" };
  const Label = ({ children }) => <span style={{ fontSize: 12, fontWeight: 600, color: "var(--fg2)", display: "block", marginBottom: 6 }}>{children}</span>;
  const svc = (id) => SV.find((s) => s.id === id) || { label: id, icon: "tag" };
  const ct = (id) => CT.find((t) => t.id === id) || { label: id, icon: "file-text", color: "var(--fg3)" };
  const wAvatar = (w, size) => <span style={{ width: size, height: size, borderRadius: size * 0.28, flex: "none", background: w.color, color: "#fff", display: "grid", placeItems: "center", fontSize: size * 0.42, fontWeight: 800 }}>{(w.name || "?").slice(0, 1).toUpperCase()}</span>;
  const Stars = ({ r }) => (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 3, fontSize: 12.5, fontWeight: 700, color: "var(--fg1)" }}>
      <Icon name="star" size={13} color="#F79009" style={{ fill: "#F79009" }} />{r ? r.toFixed(1) : "New"}
    </span>
  );
  const Verified = ({ on }) => on ? <Icon name="badge-check" size={15} color="var(--accent)" title="Verified" /> : null;
  const priceStr = (o) => `$${o.price.toLocaleString()}${o.unit ? " / " + o.unit : ""}`;
  const money = (n) => "$" + Number(n || 0).toLocaleString("en-US", { maximumFractionDigits: 2 });
  // proposal totals: subtotal (+ VAT when the expert enabled it)
  const propTotals = (b) => { const p = b.proposal; const sub = p ? (p.price || 0) : (b.price || 0); const on = !!(p && p.vatEnabled); const pct = p ? (p.vatPercent || 0) : 0; const vat = on ? sub * pct / 100 : 0; return { sub, vat, pct, vatEnabled: on, total: Math.round((sub + vat) * 100) / 100 }; };
  const isPdf = (name, url) => /\.pdf$/i.test(name || "") || /^data:application\/pdf/.test(url || "");
  const isImgDoc = (name, url) => /\.(png|jpe?g|gif|webp|svg)$/i.test(name || "") || /^data:image\//.test(url || "");

  function ServiceChips({ value, onPick }) {
    return (
      <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
        {[{ id: "all", label: "All services" }].concat(SV).map((s) => {
          const on = value === s.id;
          return <button key={s.id} onClick={() => onPick(s.id)} style={{ display: "inline-flex", alignItems: "center", gap: 6, border: `1px solid ${on ? "var(--leap-teal)" : "var(--border-strong)"}`, background: on ? "var(--accent-weak)" : "transparent", color: on ? "var(--accent)" : "var(--fg2)", borderRadius: 999, padding: "4px 11px", fontSize: 12, fontWeight: 600, cursor: "pointer", fontFamily: "inherit" }}>{s.icon && s.id !== "all" && <Icon name={s.icon} size={13} color={on ? "var(--accent)" : "var(--fg3)"} />}{s.label}</button>;
        })}
      </div>
    );
  }

  // ---- shared promo banner (Dashboard + Wizards) ------------------------
  function WizardBanner({ onExplore, onBecome, showExplore }) {
    return (
      <div style={{ position: "relative", overflow: "hidden", borderRadius: 20, padding: "22px 26px", color: "#fff", background: "linear-gradient(140deg,#0B3B42 0%,#0E6B78 52%,#0EA5B7 100%)" }}>
        <div style={{ position: "absolute", inset: 0, background: "radial-gradient(circle at 1px 1px, rgba(255,255,255,.14) 1px, transparent 0)", backgroundSize: "22px 22px", opacity: .5, pointerEvents: "none" }} />
        <div style={{ position: "relative", display: "flex", alignItems: "center", gap: 20, flexWrap: "wrap" }}>
          <div style={{ flex: 1, minWidth: 280 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 8 }}>
              <span style={{ width: 34, height: 34, borderRadius: 10, background: "rgba(255,255,255,.18)", display: "grid", placeItems: "center", flex: "none" }}><Icon name="wand-2" size={19} color="#fff" /></span>
              <span style={{ fontSize: 19, fontWeight: 700, fontFamily: "var(--font-display)" }}>Wizards give your social media engagement an even bigger leap.</span>
            </div>
            <div style={{ fontSize: 13.5, lineHeight: 1.6, opacity: .96, maxWidth: 720 }}>Discover valuable tips and tricks, best practice and video content from our experts, and find and book the experts you need to elevate your social media success — or become a Wizard yourself.</div>
          </div>
          <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
            {showExplore !== false && <Button variant="secondary" icon="wand-2" onClick={onExplore}>Explore Wizards</Button>}
            <button onClick={onBecome} style={{ border: "1px solid rgba(255,255,255,.5)", background: "rgba(255,255,255,.12)", color: "#fff", borderRadius: 11, padding: "9px 14px", cursor: "pointer", fontFamily: "inherit", fontSize: 13.5, fontWeight: 600, display: "inline-flex", alignItems: "center", gap: 7 }}><Icon name="star" size={16} color="#fff" />Become a Wizard</button>
          </div>
        </div>
      </div>
    );
  }
  window.WizardBanner = WizardBanner;

  // ---- Discover: free content feed --------------------------------------
  function ContentCard({ c, onOpen }) {
    const meta = ct(c.type);
    return (
      <Card pad={16} onClick={() => onOpen(c)} hover style={{ cursor: "pointer" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 8 }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 10.5, fontWeight: 700, textTransform: "uppercase", letterSpacing: ".05em", color: meta.color, background: meta.color + "1e", padding: "3px 8px", borderRadius: 999 }}><Icon name={meta.icon} size={12} color={meta.color} />{meta.label}</span>
          {c.type === "video" && c.minutes && <span style={{ fontSize: 11.5, color: "var(--fg3)" }}>{c.minutes} min</span>}
          <div style={{ flex: 1 }} />
          <span style={{ fontSize: 10.5, fontWeight: 700, color: "#0E8A50", background: "var(--success-bg)", padding: "2px 7px", borderRadius: 999 }}>FREE</span>
        </div>
        {c.url
          ? <div style={{ position: "relative", height: 110, borderRadius: 10, overflow: "hidden", marginBottom: 10 }}>{c.mediaKind === "video" || c.type === "video" ? <video src={c.url} muted style={{ width: "100%", height: "100%", objectFit: "cover" }} /> : <img src={c.url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />}{(c.mediaKind === "video" || c.type === "video") && <span style={{ position: "absolute", inset: 0, display: "grid", placeItems: "center" }}><Icon name="play" size={26} color="#fff" /></span>}</div>
          : c.type === "video" && <div style={{ height: 96, borderRadius: 10, background: "var(--gradient-core)", display: "grid", placeItems: "center", marginBottom: 10 }}><Icon name="play" size={26} color="#fff" /></div>}
        <div style={{ fontSize: 14.5, fontWeight: 700, marginBottom: 4 }}>{c.title}</div>
        <div style={{ fontSize: 12.5, color: "var(--fg2)", lineHeight: 1.5, display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{c.body}</div>
        <div style={{ display: "flex", alignItems: "center", gap: 7, marginTop: 12 }}>
          <span style={{ width: 22, height: 22, borderRadius: 999, background: c.wizardColor, color: "#fff", display: "grid", placeItems: "center", fontSize: 10, fontWeight: 800 }}>{c.wizardName.slice(0, 1)}</span>
          <span style={{ fontSize: 12, fontWeight: 600, color: "var(--fg2)" }}>{c.wizardName}</span><Verified on={c.verified} />
        </div>
      </Card>
    );
  }

  // ---- Experts directory ------------------------------------------------
  function ExpertCard({ w, onOpen }) {
    return (
      <Card pad={18} onClick={() => onOpen(w)} hover style={{ cursor: "pointer" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 11, marginBottom: 10 }}>
          {wAvatar(w, 44)}
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 6 }}><span style={{ fontSize: 15, fontWeight: 700, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{w.name}</span><Verified on={w.verified} />{w.isMe && <Badge color="var(--accent)" bg="var(--accent-weak)">You</Badge>}</div>
            <div style={{ fontSize: 12, color: "var(--fg3)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{w.headline}</div>
          </div>
        </div>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 5, marginBottom: 12, minHeight: 22 }}>
          {(w.specialties || []).slice(0, 3).map((s) => <span key={s} style={{ display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11, fontWeight: 600, color: "var(--fg2)", background: "var(--bg-muted)", padding: "3px 8px", borderRadius: 999 }}><Icon name={svc(s).icon} size={11} color="var(--fg3)" />{svc(s).label}</span>)}
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <Stars r={w.rating} />
          <span style={{ fontSize: 11.5, color: "var(--fg3)" }}>{w.jobs} jobs</span>
          <div style={{ flex: 1 }} />
          <span style={{ fontSize: 12.5, color: "var(--fg3)" }}>from <b style={{ color: "var(--fg1)" }}>${w.fromPrice}</b></span>
        </div>
      </Card>
    );
  }

  function ExpertModal({ w, onClose, onBook, onToast }) {
    if (!w) return null;
    return (
      <Modal open title={w.name} subtitle={w.headline} onClose={onClose} width={640}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14 }}>
          {wAvatar(w, 48)}
          <div style={{ flex: 1 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}><Stars r={w.rating} /><span style={{ fontSize: 12, color: "var(--fg3)" }}>· {w.jobs} jobs · {w.location}</span><Verified on={w.verified} /></div>
            {w.responseTime && <div style={{ fontSize: 12, color: "#0E8A50", fontWeight: 600, marginTop: 3, display: "flex", alignItems: "center", gap: 5 }}><Icon name="clock" size={13} color="#0E8A50" />Responds {w.responseTime}</div>}
          </div>
        </div>
        <p style={{ fontSize: 13.5, color: "var(--fg2)", lineHeight: 1.55, marginBottom: 14 }}>{w.bio}</p>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 18 }}>
          {(w.specialties || []).map((s) => <span key={s} style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, fontWeight: 600, color: "var(--accent)", background: "var(--accent-weak)", padding: "4px 10px", borderRadius: 999 }}><Icon name={svc(s).icon} size={12} color="var(--accent)" />{svc(s).label}</span>)}
        </div>
        <SectionTitle icon="briefcase">Services · book per job</SectionTitle>
        <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 18 }}>
          {(w.offerings || []).map((o) => (
            <div key={o.id} style={{ display: "flex", gap: 12, alignItems: "flex-start", padding: 14, border: "1px solid var(--border)", borderRadius: 14 }}>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 700 }}>{o.title}</div>
                <div style={{ fontSize: 12.5, color: "var(--fg2)", lineHeight: 1.5, margin: "3px 0 6px" }}>{o.desc}</div>
                <div style={{ fontSize: 12, color: "var(--fg3)", display: "flex", gap: 10 }}><span style={{ fontWeight: 700, color: "var(--fg1)" }}>{priceStr(o)}</span>{o.duration && <span>· {o.duration}</span>}</div>
              </div>
              {!w.isMe && <Button size="sm" variant="primary" icon="file-signature" onClick={() => onBook(w, o)}>Request service</Button>}
            </div>
          ))}
          {!(w.offerings || []).length && <div style={{ fontSize: 12.5, color: "var(--fg4)" }}>No bookable services listed yet.</div>}
        </div>
        {(w.content || []).length > 0 && (
          <React.Fragment>
            <SectionTitle icon="sparkles">Free content from {w.name.split(" ")[0]}</SectionTitle>
            <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
              {w.content.map((c) => (
                <div key={c.id} style={{ display: "flex", gap: 10, alignItems: "center", padding: "9px 12px", borderRadius: 10, background: "var(--bg-subtle)" }}>
                  <Icon name={ct(c.type).icon} size={16} color={ct(c.type).color} />
                  <span style={{ fontSize: 13, fontWeight: 600, flex: 1 }}>{c.title}</span>
                  <span style={{ fontSize: 10.5, fontWeight: 700, color: ct(c.type).color, textTransform: "uppercase" }}>{ct(c.type).label}</span>
                </div>
              ))}
            </div>
          </React.Fragment>
        )}
        {(w.showcases || []).length > 0 && (
          <div style={{ marginTop: 16 }}>
            <SectionTitle icon="image">Showcases</SectionTitle>
            <div style={{ display: "flex", gap: 8, overflowX: "auto", paddingBottom: 4 }}>
              {w.showcases.map((s) => <div key={s.id} style={{ width: 120, height: 84, borderRadius: 10, overflow: "hidden", flex: "none", border: "1px solid var(--border)" }}>{s.kind === "video" ? <video src={s.url} muted style={{ width: "100%", height: "100%", objectFit: "cover" }} /> : <img src={s.url} alt={s.name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />}</div>)}
            </div>
          </div>
        )}
        {(w.reviews || []).length > 0 && (
          <div style={{ marginTop: 16 }}>
            <SectionTitle icon="star" right={w.recommends ? <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, fontWeight: 700, color: "#0E8A50" }}><Icon name="thumbs-up" size={14} color="#0E8A50" />{w.recommends} recommend</span> : null}>Ratings &amp; reviews</SectionTitle>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              {w.reviews.map((r, i) => { const rm = (D.WIZARD_RATINGS || []).find((x) => x.choice === r.choice); return (
                <div key={i} style={{ padding: "10px 12px", borderRadius: 12, border: "1px solid var(--border)" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4, flexWrap: "wrap" }}>
                    {rm ? <span style={{ display: "inline-flex", alignItems: "center", gap: 5, fontSize: 12, fontWeight: 700, color: rm.color }}><Icon name={rm.icon} size={15} color={rm.color} />{rm.label}</span>
                      : <span style={{ display: "inline-flex", gap: 1 }}>{[1, 2, 3, 4, 5].map((n) => <Icon key={n} name="star" size={12} color={n <= r.stars ? "#F79009" : "var(--border-strong)"} style={{ fill: n <= r.stars ? "#F79009" : "none" }} />)}</span>}
                    <span style={{ fontSize: 12.5, fontWeight: 700 }}>{r.by}</span>
                    {r.offering && <span style={{ fontSize: 11.5, color: "var(--fg3)" }}>· {r.offering}</span>}
                    {r.recommended && <span style={{ display: "inline-flex", alignItems: "center", gap: 3, fontSize: 10.5, fontWeight: 700, color: "#0E8A50", background: "var(--success-bg)", padding: "1px 7px", borderRadius: 999 }}><Icon name="thumbs-up" size={11} color="#0E8A50" />Recommended</span>}
                  </div>
                  {r.comment && <div style={{ fontSize: 12.5, color: "var(--fg2)", lineHeight: 1.5 }}>{r.comment}</div>}
                </div>
              ); })}
            </div>
          </div>
        )}
      </Modal>
    );
  }

  function BookModal({ pair, onClose, onToast }) {
    const [notes, setNotes] = React.useState("");
    const [startDate, setStartDate] = React.useState("");
    const [deliveryDate, setDeliveryDate] = React.useState("");
    if (!pair) return null;
    const { w, o } = pair;
    const client = S.getActiveClient();
    const me = S.currentMember();
    const contact = (me && (me.fullName || me.name)) || S.getCurrentUser();
    const company = client ? client.name : ((me && me.company && me.company.name) || "Leap workspace");
    const send = () => { S.bookService(w.id, o.id, { jobNotes: notes, startDate, deliveryDate }); onToast(`Request sent to ${w.name} — they'll send an official proposal. (Simulated · no payment yet.)`); onClose(); };
    return (
      <Modal open title="Request a service" subtitle={`${o.title} · ${w.name}`} onClose={onClose} width={480}
        footer={<React.Fragment><Button variant="ghost" onClick={onClose}>Cancel</Button><Button variant="primary" icon="file-signature" onClick={send}>Send request</Button></React.Fragment>}>
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: 12, borderRadius: 12, background: "var(--bg-subtle)", marginBottom: 14 }}>
          {wAvatar(w, 36)}
          <div style={{ flex: 1 }}><div style={{ fontSize: 13.5, fontWeight: 700 }}>{o.title}</div><div style={{ fontSize: 12, color: "var(--fg3)" }}>{o.duration}</div></div>
          <div style={{ fontSize: 15, fontWeight: 700 }}>from {priceStr(o)}</div>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "9px 12px", borderRadius: 10, border: "1px solid var(--border)", marginBottom: 14, fontSize: 12.5 }}>
          <Icon name="building-2" size={15} color="var(--fg3)" />
          <span style={{ color: "var(--fg3)" }}>Requesting as</span>
          <span style={{ fontWeight: 700, color: "var(--fg1)" }}>{contact}</span>
          <span style={{ color: "var(--fg4)" }}>·</span>
          <span style={{ fontWeight: 600, color: "var(--fg2)" }}>{company}</span>
        </div>
        <div style={{ marginBottom: 12 }}><Label>What do you need? <span style={{ color: "var(--fg4)", fontWeight: 500 }}>· the brief</span></Label><TextArea value={notes} onChange={setNotes} rows={3} placeholder="Describe the job, goals, timelines and anything the expert should know." /></div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }} className="profile-grid">
          <div><Label>Preferred start date</Label><input type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} style={fieldStyle} /></div>
          <div><Label>Preferred delivery date</Label><input type="date" value={deliveryDate} onChange={(e) => setDeliveryDate(e.target.value)} style={fieldStyle} /></div>
        </div>
        <div style={{ fontSize: 11.5, color: "var(--fg4)", marginTop: 10, display: "flex", gap: 6, alignItems: "center" }}><Icon name="shield" size={13} color="var(--fg4)" />No payment now — the expert replies with an official proposal and terms. Payment (via Stripe) happens only when you accept it.</div>
      </Modal>
    );
  }

  function ContentModal({ c, onClose }) {
    if (!c) return null;
    return (
      <Modal open title={c.title} subtitle={`${ct(c.type).label} · by ${c.wizardName}`} onClose={onClose} width={520}>
        {c.url
          ? <div style={{ borderRadius: 12, overflow: "hidden", marginBottom: 14, maxHeight: 300 }}>{c.mediaKind === "video" || c.type === "video" ? <video src={c.url} controls style={{ width: "100%", display: "block" }} /> : <img src={c.url} alt={c.title} style={{ width: "100%", display: "block" }} />}</div>
          : c.type === "video" && <div style={{ height: 200, borderRadius: 12, background: "var(--gradient-core)", display: "grid", placeItems: "center", marginBottom: 14 }}><Icon name="play" size={34} color="#fff" /></div>}
        <p style={{ fontSize: 14, color: "var(--fg1)", lineHeight: 1.6 }}>{c.body}</p>
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginTop: 16 }}>
          <span style={{ width: 26, height: 26, borderRadius: 999, background: c.wizardColor, color: "#fff", display: "grid", placeItems: "center", fontSize: 11, fontWeight: 800 }}>{c.wizardName.slice(0, 1)}</span>
          <span style={{ fontSize: 13, fontWeight: 600 }}>{c.wizardName}</span><Verified on={c.verified} />
          <div style={{ flex: 1 }} /><span style={{ fontSize: 11, fontWeight: 700, color: "#0E8A50" }}>FREE</span>
        </div>
      </Modal>
    );
  }

  // published Wizards publish free content to Discover
  function AddContentModal({ onClose, onToast }) {
    const [type, setType] = React.useState("tip");
    const [title, setTitle] = React.useState("");
    const [body, setBody] = React.useState("");
    const [media, setMedia] = React.useState(null);
    const onFile = (e) => { const f = (e.target.files || [])[0]; if (!f) return; const r = new FileReader(); r.onload = () => setMedia({ url: r.result, kind: (f.type || "").startsWith("video") ? "video" : "image" }); r.readAsDataURL(f); e.target.value = ""; };
    const publish = () => { if (!title.trim()) { onToast("Add a title", "error"); return; } S.addMyContent({ type, title, body, url: media ? media.url : "", mediaKind: media ? media.kind : "" }); onToast("Published to Discover 🎉"); onClose(); };
    return (
      <Modal open title="Publish content" subtitle="Share a tip, idea or short video — free for everyone" onClose={onClose} width={520}
        footer={<React.Fragment><Button variant="ghost" onClick={onClose}>Cancel</Button><Button variant="primary" icon="upload" onClick={publish}>Publish</Button></React.Fragment>}>
        <div style={{ display: "flex", gap: 10, marginBottom: 12 }}>
          <div style={{ flex: "none" }}><Label>Type</Label><Select value={type} onChange={setType} options={CT.map((t) => ({ value: t.id, label: t.label }))} style={{ width: 150 }} /></div>
          <div style={{ flex: 1 }}><Label>Title</Label><TextInput value={title} onChange={setTitle} placeholder="e.g. 3 hooks that stop the scroll" /></div>
        </div>
        <div style={{ marginBottom: 12 }}><Label>Body</Label><TextArea value={body} onChange={setBody} rows={3} placeholder="The tip, best practice or idea in a few sentences." /></div>
        <Label>Media {type === "video" ? "· video" : "· optional image/video"}</Label>
        {media ? (
          <div style={{ position: "relative", borderRadius: 12, overflow: "hidden", maxHeight: 200 }}>
            {media.kind === "video" ? <video src={media.url} controls style={{ width: "100%", display: "block" }} /> : <img src={media.url} alt="" style={{ width: "100%", display: "block" }} />}
            <button onClick={() => setMedia(null)} style={{ position: "absolute", top: 6, right: 6, width: 22, height: 22, borderRadius: 999, border: 0, background: "rgba(11,59,66,.7)", cursor: "pointer", display: "grid", placeItems: "center" }}><Icon name="x" size={13} color="#fff" /></button>
          </div>
        ) : (
          <label style={{ display: "flex", alignItems: "center", gap: 10, border: "1.5px dashed var(--border-strong)", borderRadius: 12, padding: "14px 16px", cursor: "pointer", color: "var(--fg3)" }}>
            <Icon name="upload-cloud" size={20} color="var(--fg4)" /><span style={{ fontSize: 13 }}>Upload an image or video</span>
            <input type="file" accept="image/*,video/*" style={{ display: "none" }} onChange={onFile} />
          </label>
        )}
      </Modal>
    );
  }

  // ---- Bookings + workflow (offer · board · files · accept · rate) ------
  const BK_STATUS = { requested: { label: "Awaiting proposal", color: "#B25E09", bg: "var(--warning-bg)" }, offered: { label: "Proposal received", color: "#0EA5B7", bg: "var(--accent-weak)" }, confirmed: { label: "In progress", color: "#0EA5B7", bg: "var(--accent-weak)" }, accepted: { label: "Work accepted", color: "#7C3AED", bg: "#EEE9FE" }, completed: { label: "Completed", color: "#0E8A50", bg: "var(--success-bg)" } };
  const fmtD = (iso) => { try { return new Date(iso).toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" }); } catch (e) { return "—"; } };
  const readF = (f, cb) => { if (!f) return; const r = new FileReader(); r.onload = () => cb({ url: r.result, kind: (f.type || "").startsWith("video") ? "video" : "image", name: f.name }); r.readAsDataURL(f); };
  const iconBtn = { border: "1px solid var(--border-strong)", background: "var(--surface)", borderRadius: 9, width: 32, height: 32, cursor: "pointer", display: "grid", placeItems: "center", textDecoration: "none" };

  // a deliverable/reference file on the board — chat, accept, download, save-to-assets
  function FileItem({ b, f, persp, onToast }) {
    const [open, setOpen] = React.useState(false);
    const [c, setC] = React.useState("");
    const isExpert = persp === "expert";
    const mineFrom = isExpert ? "expert" : "you";
    const mineFile = isExpert ? f.uploadedBy === "expert" : f.uploadedBy !== "expert";
    const uploaderLabel = mineFile ? "You" : (f.uploadedBy === "expert" ? b.wizardName.split(" ")[0] : (b.requestor ? b.requestor.company : "Client"));
    const sendComment = () => { if (c.trim()) { S.bookingFileComment(b.id, f.id, c, mineFrom); setC(""); } };
    return (
      <div style={{ border: "1px solid var(--border)", borderRadius: 12, overflow: "hidden" }}>
        <div style={{ display: "flex", gap: 10, alignItems: "center", padding: 10 }}>
          <div style={{ width: 58, height: 44, borderRadius: 8, overflow: "hidden", flex: "none", background: "var(--bg-muted)" }}>{f.kind === "video" ? <video src={f.url} muted style={{ width: "100%", height: "100%", objectFit: "cover" }} /> : <img src={f.url} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13, fontWeight: 700, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{f.name}</div>
            <div style={{ fontSize: 11, color: "var(--fg3)" }}>{uploaderLabel}{f.accepted && <span style={{ color: "#0E8A50", fontWeight: 700 }}> · Accepted</span>}</div>
          </div>
          <button title="Discuss / request changes" onClick={() => setOpen((o) => !o)} style={{ ...iconBtn, width: "auto", padding: "0 9px", gap: 4, display: "inline-flex", alignItems: "center", fontFamily: "inherit", fontSize: 12, color: "var(--fg2)" }}><Icon name="message-square" size={15} color="var(--fg3)" />{(f.comments || []).length || ""}</button>
          <a href={f.url} download={f.name} title="Download" style={iconBtn}><Icon name="download" size={15} color="var(--fg3)" /></a>
          <button title="Save to Assets" onClick={() => { S.addAsset({ name: f.name, url: f.url, kind: f.kind, category: "other", keywords: [], platforms: [] }); onToast(`Saved “${f.name}” to Assets`); }} style={iconBtn}><Icon name="image-plus" size={15} color="var(--fg3)" /></button>
          {!isExpert && !f.accepted && b.status !== "completed" && f.uploadedBy === "expert" && <Button size="sm" variant="primary" icon="check" onClick={() => { S.bookingAcceptFile(b.id, f.id); onToast("File accepted"); }}>Accept</Button>}
        </div>
        {open && (
          <div style={{ borderTop: "1px solid var(--border)", padding: 10, background: "var(--bg-subtle)" }}>
            <div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 8 }}>
              {(f.comments || []).map((cm, i) => { const mine = cm.from === mineFrom; return <div key={i} style={{ alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "85%", fontSize: 12.5, lineHeight: 1.4, background: mine ? "var(--gradient-core)" : cm.from === "system" ? "transparent" : "var(--surface)", border: !mine && cm.from !== "system" ? "1px solid var(--border)" : 0, color: mine ? "#fff" : "var(--fg1)", padding: "6px 10px", borderRadius: 10 }}>{cm.from === "system" ? <span style={{ fontStyle: "italic", color: "var(--fg3)" }}>{cm.text}</span> : cm.text}</div>; })}
              {!(f.comments || []).length && <div style={{ fontSize: 12, color: "var(--fg4)" }}>{isExpert ? "Reply to the client's change requests here." : "Comment to request a change, or accept the file above."}</div>}
            </div>
            {b.status !== "completed" && (
              <div style={{ display: "flex", gap: 6 }}>
                <TextInput value={c} onChange={setC} placeholder={isExpert ? "Reply to the client…" : "Comment or request a change…"} style={{ flex: 1 }} onKeyDown={(e) => { if (e.key === "Enter") sendComment(); }} />
                <Button size="sm" variant="secondary" icon="send" onClick={sendComment}>Send</Button>
              </div>
            )}
          </div>
        )}
      </div>
    );
  }

  function RatingBlock({ b, onToast }) {
    const [choice, setChoice] = React.useState(1);
    const [comment, setComment] = React.useState("");
    const [rec, setRec] = React.useState(true);
    return (
      <Card pad={18} style={{ marginBottom: 14, border: "1.5px solid var(--leap-teal)" }}>
        <SectionTitle icon="star">How was working with {b.wizardName.split(" ")[0]}?</SectionTitle>
        <div style={{ display: "flex", flexWrap: "wrap", gap: 8, marginBottom: 12 }}>
          {(D.WIZARD_RATINGS || []).map((r) => { const on = choice === r.choice; return (
            <button key={r.choice} onClick={() => setChoice(r.choice)} style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 6, width: 104, padding: "12px 6px", borderRadius: 14, cursor: "pointer", fontFamily: "inherit", border: `1.5px solid ${on ? r.color : "var(--border)"}`, background: on ? r.color + "16" : "var(--surface)" }}>
              <Icon name={r.icon} size={26} color={on ? r.color : "var(--fg3)"} /><span style={{ fontSize: 11.5, fontWeight: 700, color: on ? r.color : "var(--fg2)", textAlign: "center", lineHeight: 1.25 }}>{r.label}</span>
            </button>
          ); })}
        </div>
        <TextArea value={comment} onChange={setComment} rows={2} placeholder="Add a comment (shown on their profile)…" />
        <label style={{ display: "flex", alignItems: "center", gap: 10, margin: "12px 0" }}>
          <button onClick={(e) => { e.preventDefault(); setRec(!rec); }} style={{ width: 42, height: 24, borderRadius: 999, border: 0, cursor: "pointer", padding: 3, background: rec ? "var(--success)" : "var(--border-strong)", display: "flex", justifyContent: rec ? "flex-end" : "flex-start", transition: "background 160ms" }}><span style={{ width: 18, height: 18, borderRadius: 999, background: "#fff", boxShadow: "var(--shadow-sm)" }} /></button>
          <span style={{ fontSize: 13.5, fontWeight: 600, display: "flex", alignItems: "center", gap: 6 }}><Icon name="thumbs-up" size={16} color={rec ? "#0E8A50" : "var(--fg4)"} />Recommend {b.wizardName.split(" ")[0]} to others</span>
        </label>
        <Button variant="primary" icon="check" onClick={() => { S.bookingRate(b.id, choice, comment, rec); onToast("Thanks — your rating is on their profile"); }}>Submit rating</Button>
      </Card>
    );
  }

  // EXPERT feature — compose & send an official proposal with terms + a document
  function ProposalComposer({ b, onClose, onToast }) {
    const [price, setPrice] = React.useState(b.price ? String(b.price) : "");
    const [deliverables, setDeliverables] = React.useState("");
    const [startDate, setStartDate] = React.useState(b.startDate || "");
    const [endDate, setEndDate] = React.useState(b.deliveryDate || "");
    const [vatOn, setVatOn] = React.useState(false);
    const [vatPct, setVatPct] = React.useState("20");
    const [terms, setTerms] = React.useState("");
    const [doc, setDoc] = React.useState(null);
    const onFile = (e) => { const f = (e.target.files || [])[0]; if (!f) return; const r = new FileReader(); r.onload = () => setDoc({ name: f.name, url: r.result }); r.readAsDataURL(f); e.target.value = ""; };
    const sub = +price || 0; const vat = vatOn ? sub * (+vatPct || 0) / 100 : 0; const total = Math.round((sub + vat) * 100) / 100;
    const send = () => {
      if (!(+price > 0)) { onToast("Set a price for the proposal", "error"); return; }
      S.bookingSendProposal(b.id, { price: +price, deliverables, startDate, endDate, vatEnabled: vatOn, vatPercent: +vatPct || 0, terms, docName: doc ? doc.name : "", docUrl: doc ? doc.url : "" });
      onToast("Proposal sent to the client"); onClose();
    };
    return (
      <Modal open title="Prepare official proposal" subtitle={`${b.offeringTitle} · for ${b.requestor ? b.requestor.company : "the client"}`} width={560} onClose={onClose}
        footer={<React.Fragment><Button variant="ghost" onClick={onClose}>Cancel</Button><Button variant="primary" icon="send" onClick={send}>Send proposal</Button></React.Fragment>}>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 12 }} className="profile-grid">
          <div><Label>Price ($)</Label><input type="number" min="0" value={price} onChange={(e) => setPrice(e.target.value)} style={fieldStyle} placeholder="0" /></div>
          <div style={{ display: "flex", flexDirection: "column", justifyContent: "flex-end" }}>
            <label style={{ display: "flex", alignItems: "center", gap: 8, fontSize: 13, fontWeight: 600, marginBottom: 6 }}>
              <input type="checkbox" checked={vatOn} onChange={(e) => setVatOn(e.target.checked)} style={{ width: 16, height: 16, accentColor: "var(--accent)" }} />Add VAT
            </label>
            {vatOn && <div style={{ display: "flex", alignItems: "center", gap: 6 }}><input type="number" min="0" max="100" value={vatPct} onChange={(e) => setVatPct(e.target.value)} style={{ ...fieldStyle, width: 84 }} /><span style={{ fontSize: 13, color: "var(--fg3)" }}>% VAT</span></div>}
          </div>
        </div>
        <div style={{ marginBottom: 12 }}><Label>Deliverables</Label><TextArea value={deliverables} onChange={setDeliverables} rows={3} placeholder="What the client receives — e.g. a 90-day strategy deck, content pillars and a posting calendar." /></div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12, marginBottom: 12 }} className="profile-grid">
          <div><Label>Start date</Label><input type="date" value={startDate} onChange={(e) => setStartDate(e.target.value)} style={fieldStyle} /></div>
          <div><Label>End date</Label><input type="date" value={endDate} onChange={(e) => setEndDate(e.target.value)} style={fieldStyle} /></div>
        </div>
        <div style={{ marginBottom: 12 }}><Label>Terms <span style={{ color: "var(--fg4)", fontWeight: 500 }}>· optional</span></Label><TextArea value={terms} onChange={setTerms} rows={2} placeholder="Payment terms, revisions, cancellation, etc." /></div>
        <Label>Proposal document</Label>
        {doc ? (
          <div style={{ display: "flex", alignItems: "center", gap: 10, border: "1px solid var(--border)", borderRadius: 10, padding: "9px 12px", marginBottom: 4 }}>
            <Icon name="file-text" size={18} color="var(--accent)" /><span style={{ flex: 1, fontSize: 13, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{doc.name}</span>
            <button onClick={() => setDoc(null)} style={{ border: 0, background: "none", cursor: "pointer" }}><Icon name="x" size={16} color="var(--fg3)" /></button>
          </div>
        ) : (
          <label style={{ display: "flex", alignItems: "center", gap: 10, border: "1.5px dashed var(--border-strong)", borderRadius: 10, padding: "12px 14px", cursor: "pointer", color: "var(--fg3)" }}>
            <Icon name="upload-cloud" size={18} color="var(--fg4)" /><span style={{ fontSize: 13 }}>Upload the official proposal (PDF, DOC or image)</span>
            <input type="file" accept=".pdf,.doc,.docx,image/*" style={{ display: "none" }} onChange={onFile} />
          </label>
        )}
        <div style={{ display: "flex", justifyContent: "space-between", marginTop: 14, paddingTop: 12, borderTop: "1px solid var(--border)", fontSize: 13 }}>
          <span style={{ color: "var(--fg3)" }}>Total{vatOn ? ` (incl. ${+vatPct || 0}% VAT)` : ""}</span>
          <span style={{ fontSize: 16, fontWeight: 700 }}>{money(total)}</span>
        </div>
      </Modal>
    );
  }

  // CLIENT view — the proposal as a pop-up, with the attached document to view/download
  function ProposalModal({ b, onClose }) {
    if (!b || !b.proposal) return null;
    const p = b.proposal; const t = propTotals(b);
    const row = (l, v) => <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "3px 0" }}><span style={{ color: "var(--fg3)" }}>{l}</span><span style={{ fontWeight: 600 }}>{v}</span></div>;
    return (
      <Modal open title="Official proposal" subtitle={`${b.offeringTitle} · from ${b.wizardName}`} width={560} onClose={onClose}
        footer={<Button variant="ghost" onClick={onClose}>Close</Button>}>
        {p.deliverables && <div style={{ marginBottom: 14 }}><Label>Deliverables</Label><div style={{ fontSize: 13, color: "var(--fg1)", lineHeight: 1.55, whiteSpace: "pre-wrap" }}>{p.deliverables}</div></div>}
        <div style={{ display: "flex", gap: 16, marginBottom: 14, flexWrap: "wrap" }}>
          {p.startDate && <div><Label>Start</Label><div style={{ fontSize: 13, fontWeight: 600 }}>{fmtD(p.startDate)}</div></div>}
          {p.endDate && <div><Label>End</Label><div style={{ fontSize: 13, fontWeight: 600 }}>{fmtD(p.endDate)}</div></div>}
        </div>
        {p.terms && <div style={{ marginBottom: 14 }}><Label>Terms</Label><div style={{ fontSize: 12.5, color: "var(--fg2)", lineHeight: 1.55, whiteSpace: "pre-wrap" }}>{p.terms}</div></div>}
        <div style={{ border: "1px solid var(--border)", borderRadius: 12, padding: "10px 14px", marginBottom: 14 }}>
          {row("Service", money(t.sub))}
          {t.vatEnabled && row(`VAT (${t.pct}%)`, money(t.vat))}
          <div style={{ display: "flex", justifyContent: "space-between", borderTop: "1px solid var(--border)", marginTop: 6, paddingTop: 8, fontSize: 15 }}><span style={{ fontWeight: 700 }}>Total</span><span style={{ fontWeight: 700 }}>{money(t.total)}</span></div>
        </div>
        {p.docUrl ? (
          <div>
            <Label>Attached document</Label>
            {isImgDoc(p.docName, p.docUrl) && <div style={{ borderRadius: 10, overflow: "hidden", border: "1px solid var(--border)", marginBottom: 8, maxHeight: 320 }}><img src={p.docUrl} alt={p.docName} style={{ width: "100%", display: "block" }} /></div>}
            {isPdf(p.docName, p.docUrl) && <embed src={p.docUrl} type="application/pdf" style={{ width: "100%", height: 320, borderRadius: 10, border: "1px solid var(--border)", marginBottom: 8 }} />}
            <div style={{ display: "flex", alignItems: "center", gap: 10, border: "1px solid var(--border)", borderRadius: 10, padding: "9px 12px" }}>
              <Icon name="file-text" size={18} color="var(--accent)" /><span style={{ flex: 1, fontSize: 13, fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{p.docName || "Proposal document"}</span>
              <a href={p.docUrl} target="_blank" rel="noreferrer" style={{ ...iconBtn, width: "auto", padding: "0 10px", gap: 5, display: "inline-flex", alignItems: "center", fontSize: 12, fontWeight: 600, color: "var(--fg2)" }}><Icon name="eye" size={15} color="var(--fg3)" />View</a>
              <a href={p.docUrl} download={p.docName || "proposal"} style={{ ...iconBtn, width: "auto", padding: "0 10px", gap: 5, display: "inline-flex", alignItems: "center", fontSize: 12, fontWeight: 600, color: "var(--fg2)" }}><Icon name="download" size={15} color="var(--fg3)" />Download</a>
            </div>
          </div>
        ) : <div style={{ fontSize: 12.5, color: "var(--fg4)", display: "flex", gap: 6, alignItems: "center" }}><Icon name="paperclip" size={13} color="var(--fg4)" />No document attached.</div>}
      </Modal>
    );
  }

  // Accept & confirm → payment. SIMULATED Stripe seam — no real charge is made.
  function PaymentModal({ b, onClose, onToast }) {
    if (!b) return null;
    const t = propTotals(b);
    const pay = () => { S.bookingPay(b.id); onToast("Payment confirmed (simulated) — your booking is now in progress"); onClose(); };
    return (
      <Modal open title="Confirm & pay" subtitle={`${b.offeringTitle} · ${b.wizardName}`} width={460} onClose={onClose}
        footer={<React.Fragment><Button variant="ghost" onClick={onClose}>Cancel</Button><Button variant="primary" icon="lock" onClick={pay}>Pay {money(t.total)}</Button></React.Fragment>}>
        <div style={{ border: "1px solid var(--border)", borderRadius: 12, padding: "10px 14px", marginBottom: 14 }}>
          <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "3px 0" }}><span style={{ color: "var(--fg3)" }}>Service</span><span style={{ fontWeight: 600 }}>{money(t.sub)}</span></div>
          {t.vatEnabled && <div style={{ display: "flex", justifyContent: "space-between", fontSize: 13, padding: "3px 0" }}><span style={{ color: "var(--fg3)" }}>VAT ({t.pct}%)</span><span style={{ fontWeight: 600 }}>{money(t.vat)}</span></div>}
          <div style={{ display: "flex", justifyContent: "space-between", borderTop: "1px solid var(--border)", marginTop: 6, paddingTop: 8, fontSize: 15 }}><span style={{ fontWeight: 700 }}>Total due</span><span style={{ fontWeight: 700 }}>{money(t.total)}</span></div>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 10, border: "1px solid var(--border)", borderRadius: 12, padding: "12px 14px", background: "var(--bg-subtle)" }}>
          <span style={{ fontWeight: 800, fontStyle: "italic", color: "#635BFF", fontSize: 16, fontFamily: "var(--font-display)" }}>stripe</span>
          <span style={{ fontSize: 12.5, color: "var(--fg2)" }}>You'll continue to Stripe's secure checkout to pay.</span>
        </div>
        <div style={{ fontSize: 11.5, color: "var(--fg4)", marginTop: 10, display: "flex", gap: 6, alignItems: "flex-start" }}><Icon name="shield" size={13} color="var(--fg4)" /><span><b>Simulated</b> — no real charge is made. Stripe is wired as a seam; add live keys in Settings → Integrations to process real payments.</span></div>
      </Modal>
    );
  }

  function BookingDetail({ b, onBack, onToast, onOpenWizard }) {
    const [msg, setMsg] = React.useState("");
    const [persp, setPersp] = React.useState("client");
    const [showComposer, setShowComposer] = React.useState(false);
    const [showProposal, setShowProposal] = React.useState(false);
    const [showPay, setShowPay] = React.useState(false);
    const sm = BK_STATUS[b.status] || BK_STATUS.requested;
    const rmeta = (D.WIZARD_RATINGS || []).find((r) => r.choice === b.ratingChoice) || {};
    const boardOpen = ["confirmed", "accepted", "completed"].includes(b.status);
    const isExpert = persp === "expert";
    const isClient = persp === "client";
    const mineFrom = isExpert ? "expert" : "you";
    const expertFirst = b.wizardName.split(" ")[0];
    const clientName = b.requestor ? b.requestor.company : "the client";
    const t = b.proposal ? propTotals(b) : null;
    const sendMsg = () => { if (msg.trim()) { S.bookingSendMessage(b.id, msg, mineFrom); setMsg(""); } };
    const waiting = (text) => <Card pad={16} style={{ marginBottom: 14, background: "var(--bg-subtle)", border: "1px dashed var(--border-strong)" }}><div style={{ fontSize: 12.5, color: "var(--fg2)", display: "flex", alignItems: "center", gap: 8 }}><Icon name="clock" size={15} color="var(--fg3)" />{text}</div></Card>;
    return (
      <div style={{ maxWidth: 640, margin: "0 auto" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 12 }}>
          <Button variant="ghost" icon="arrow-left" onClick={onBack}>Bookings</Button><div style={{ flex: 1 }} /><Badge color={sm.color} bg={sm.bg} dot>{sm.label}</Badge>
        </div>

        {/* perspective switcher — act as either side of the contract & fulfilment */}
        <Card pad={12} style={{ marginBottom: 14 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
            <Icon name="repeat" size={16} color="var(--accent)" />
            <span style={{ fontSize: 12.5, fontWeight: 700 }}>Test as</span>
            <Segmented value={persp} onChange={setPersp} options={[{ value: "client", label: "Client", icon: "building-2" }, { value: "expert", label: "Expert", icon: "wand-2" }]} />
            <span style={{ fontSize: 11.5, color: "var(--fg3)" }}>{isExpert ? `You're ${b.wizardName} — the expert` : `You're ${clientName} — the client`}</span>
          </div>
        </Card>

        <Card pad={18} style={{ marginBottom: 14 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <span onClick={() => onOpenWizard(S.getWizard(b.wizardId))} style={{ width: 42, height: 42, borderRadius: 11, background: b.wizardColor, color: "#fff", display: "grid", placeItems: "center", fontSize: 16, fontWeight: 800, flex: "none", cursor: "pointer" }}>{b.wizardName.slice(0, 1)}</span>
            <div style={{ flex: 1 }}><div style={{ fontSize: 15, fontWeight: 700 }}>{b.offeringTitle}</div><div style={{ fontSize: 12.5, color: "var(--fg3)" }}>{b.wizardName}</div></div>
            <div style={{ fontSize: 15, fontWeight: 700 }}>${b.price.toLocaleString()}{b.unit ? " / " + b.unit : ""}</div>
          </div>
          <div style={{ display: "flex", gap: 16, marginTop: 12, fontSize: 12, color: "var(--fg3)", flexWrap: "wrap" }}>
            {b.startDate && <span><b style={{ color: "var(--fg2)" }}>Start</b> {fmtD(b.startDate)}</span>}
            {b.deliveryDate && <span><b style={{ color: "var(--fg2)" }}>Delivery</b> {fmtD(b.deliveryDate)}</span>}
          </div>
          {b.jobNotes && <div style={{ fontSize: 12.5, color: "var(--fg2)", marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--border)" }}><b>Brief:</b> {b.jobNotes}</div>}
          {b.requestor && <div style={{ fontSize: 12.5, color: "var(--fg2)", marginTop: 10, paddingTop: 10, borderTop: "1px solid var(--border)", display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
            <Icon name="building-2" size={15} color="var(--fg3)" />
            <span><b style={{ color: "var(--fg1)" }}>Requested by</b> {b.requestor.contact} · {b.requestor.company}{b.requestor.email ? " · " + b.requestor.email : ""}</span>
          </div>}
        </Card>

        {/* proposal — expert composes it (requested), client reviews & pays (offered) */}
        {b.status === "requested" && isExpert && (
          <Card pad={18} style={{ marginBottom: 14, border: "1.5px solid var(--leap-teal)" }}>
            <SectionTitle icon="file-text">Official proposal</SectionTitle>
            <div style={{ fontSize: 12.5, color: "var(--fg2)", lineHeight: 1.5, marginBottom: 12 }}>Prepare an official proposal for {clientName} — price, deliverables, dates, VAT and an attached document.</div>
            <Button variant="primary" icon="file-plus-2" onClick={() => setShowComposer(true)}>Prepare &amp; send proposal</Button>
          </Card>
        )}
        {b.status === "requested" && isClient && waiting(`Waiting for ${expertFirst} to send the official proposal.`)}
        {b.status === "offered" && b.proposal && isClient && (
          <Card pad={18} style={{ marginBottom: 14, border: "1.5px solid var(--leap-teal)" }}>
            <SectionTitle icon="file-text" right={<Button size="sm" variant="secondary" icon="eye" onClick={() => setShowProposal(true)}>View proposal</Button>}>Proposal received</SectionTitle>
            <div style={{ display: "flex", gap: 16, alignItems: "baseline", flexWrap: "wrap", marginBottom: 10 }}>
              <div><span style={{ fontSize: 20, fontWeight: 700, fontFamily: "var(--font-display)" }}>{money(t.total)}</span>{t.vatEnabled && <span style={{ fontSize: 12, color: "var(--fg3)" }}> incl. {t.pct}% VAT</span>}</div>
              {b.proposal.endDate && <div style={{ fontSize: 12.5, color: "var(--fg3)" }}>Delivery by <b style={{ color: "var(--fg1)" }}>{fmtD(b.proposal.endDate)}</b></div>}
              {b.proposal.docName && <div style={{ fontSize: 12, color: "var(--fg3)", display: "inline-flex", alignItems: "center", gap: 5 }}><Icon name="paperclip" size={13} color="var(--fg3)" />{b.proposal.docName}</div>}
            </div>
            {b.proposal.deliverables && <div style={{ fontSize: 12.5, color: "var(--fg2)", marginBottom: 12, display: "-webkit-box", WebkitLineClamp: 2, WebkitBoxOrient: "vertical", overflow: "hidden" }}>{b.proposal.deliverables}</div>}
            <Button variant="primary" icon="check" onClick={() => setShowPay(true)}>Accept &amp; pay {money(t.total)}</Button>
          </Card>
        )}
        {b.status === "offered" && b.proposal && isExpert && (
          <Card pad={18} style={{ marginBottom: 14 }}>
            <SectionTitle icon="file-text" right={<Button size="sm" variant="secondary" icon="eye" onClick={() => setShowProposal(true)}>View proposal</Button>}>Proposal sent</SectionTitle>
            <div style={{ fontSize: 12.5, color: "var(--fg2)", display: "flex", alignItems: "center", gap: 8 }}><Icon name="clock" size={15} color="var(--fg3)" />Waiting for {clientName} to accept &amp; pay {money(t.total)}.</div>
          </Card>
        )}

        {/* message thread — attributed to the current perspective */}
        <Card pad={18} style={{ marginBottom: 14 }}>
          <SectionTitle icon="messages-square">Messages</SectionTitle>
          <div style={{ display: "flex", flexDirection: "column", gap: 8, maxHeight: 280, overflow: "auto", marginBottom: 12 }}>
            {(b.messages || []).map((m, i) => { const mine = m.from === mineFrom; return (
              <div key={i} style={{ alignSelf: mine ? "flex-end" : "flex-start", maxWidth: "82%", background: mine ? "var(--gradient-core)" : m.from === "system" ? "var(--bg-muted)" : "var(--surface)", border: !mine && m.from !== "system" ? "1px solid var(--border)" : 0, color: mine ? "#fff" : "var(--fg1)", padding: "8px 12px", borderRadius: 12, fontSize: 13, lineHeight: 1.45 }}>
                {m.from === "system" ? <span style={{ fontSize: 12, color: "var(--fg3)", fontStyle: "italic" }}>{m.text}</span> : m.text}
              </div>
            ); })}
          </div>
          {b.status !== "completed" && (
            <div style={{ display: "flex", gap: 8 }}>
              <TextInput value={msg} onChange={setMsg} placeholder={isExpert ? `Message ${clientName}…` : `Message ${expertFirst}…`} style={{ flex: 1 }} onKeyDown={(e) => { if (e.key === "Enter") sendMsg(); }} />
              <Button variant="primary" icon="send" onClick={sendMsg}>Send</Button>
            </div>
          )}
        </Card>

        {/* board — files, per-file chat, accept, download, save-to-assets */}
        {boardOpen && (
          <Card pad={18} style={{ marginBottom: 14 }}>
            <SectionTitle icon="folder" right={b.status !== "completed" ? <label style={{ display: "inline-flex", alignItems: "center", gap: 6, border: "1px solid var(--border-strong)", background: "var(--surface)", borderRadius: 999, padding: "5px 11px", cursor: "pointer", fontSize: 12, fontWeight: 600, color: "var(--fg2)" }}><Icon name="upload" size={14} color="var(--fg3)" />Upload {isExpert ? "deliverable" : "reference"}<input type="file" accept="image/*,video/*" style={{ display: "none" }} onChange={(e) => { readF((e.target.files || [])[0], (m) => S.bookingAddFile(b.id, { ...m, uploadedBy: mineFrom })); e.target.value = ""; }} /></label> : null}>Deliverables &amp; files</SectionTitle>
            <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
              {(b.files || []).map((f) => <FileItem key={f.id} b={b} f={f} persp={persp} onToast={onToast} />)}
              {!(b.files || []).length && <div style={{ fontSize: 12.5, color: "var(--fg4)" }}>{isExpert ? "No files yet — upload the deliverable for the client." : "No files yet — upload references, or wait for the deliverable."}</div>}
            </div>
          </Card>
        )}

        {/* confirmed → client accepts the work; expert waits */}
        {b.status === "confirmed" && isClient && (
          <Card pad={18} style={{ marginBottom: 14, border: "1.5px solid var(--leap-teal)" }}>
            <div style={{ fontSize: 13, color: "var(--fg2)", marginBottom: 10 }}>Happy with the delivery? Accept the work, then rate the collaboration.</div>
            <Button variant="primary" icon="check-check" onClick={() => { S.bookingAcceptWork(b.id); onToast("Work accepted — leave a rating"); }}>Accept the work</Button>
          </Card>
        )}
        {b.status === "confirmed" && isExpert && waiting(`Deliverables shared — waiting for ${clientName} to accept the work.`)}

        {/* accepted → client rates; expert waits */}
        {b.status === "accepted" && isClient && <RatingBlock b={b} onToast={onToast} />}
        {b.status === "accepted" && isExpert && waiting(`Work accepted — waiting for ${clientName}'s rating.`)}

        {b.status === "completed" && (
          <Card pad={18} style={{ marginBottom: 14, background: "var(--success-bg)", border: 0 }}>
            <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}><Icon name={rmeta.icon || "check-circle"} size={20} color={rmeta.color || "#0E8A50"} /><span style={{ fontSize: 14, fontWeight: 700 }}>Completed · “{b.ratingLabel || "rated"}”</span>{b.recommended && <span style={{ display: "inline-flex", alignItems: "center", gap: 4, fontSize: 11.5, fontWeight: 700, color: "#0E8A50", background: "rgba(255,255,255,.6)", padding: "2px 8px", borderRadius: 999 }}><Icon name="thumbs-up" size={12} color="#0E8A50" />Recommended</span>}</div>
            {b.ratingComment && <div style={{ fontSize: 12.5, color: "var(--fg2)", marginTop: 6 }}>"{b.ratingComment}"</div>}
          </Card>
        )}

        {showComposer && <ProposalComposer b={b} onClose={() => setShowComposer(false)} onToast={onToast} />}
        {showProposal && <ProposalModal b={b} onClose={() => setShowProposal(false)} />}
        {showPay && <PaymentModal b={b} onClose={() => setShowPay(false)} onToast={onToast} />}
      </div>
    );
  }

  function Bookings({ onToast, onBrowse, onOpenWizard }) {
    const [sel, setSel] = React.useState(null);
    const bookings = S.getBookings();
    const current = sel && bookings.find((b) => b.id === sel);
    if (current) return <BookingDetail b={current} onBack={() => setSel(null)} onToast={onToast} onOpenWizard={onOpenWizard} />;
    if (!bookings.length) return (
      <Card pad={44} style={{ textAlign: "center", maxWidth: 560, margin: "0 auto" }}>
        <span style={{ width: 54, height: 54, borderRadius: 15, background: "var(--accent-weak)", display: "inline-grid", placeItems: "center" }}><Icon name="calendar-check" size={24} color="var(--accent)" /></span>
        <div style={{ fontSize: 16, fontWeight: 700, marginTop: 12 }}>No bookings yet</div>
        <div style={{ fontSize: 13, color: "var(--fg3)", marginTop: 4, marginBottom: 16 }}>Browse experts and book a service per job.</div>
        <Button variant="primary" icon="users" onClick={onBrowse}>Browse experts</Button>
      </Card>
    );
    return (
      <div style={{ maxWidth: 720, margin: "0 auto", display: "flex", flexDirection: "column", gap: 10 }}>
        {bookings.map((b) => { const sm = BK_STATUS[b.status] || BK_STATUS.requested; const unread = (b.messages || []).length; return (
          <Card key={b.id} pad={16} onClick={() => setSel(b.id)} hover style={{ cursor: "pointer" }}>
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <span style={{ width: 38, height: 38, borderRadius: 11, background: b.wizardColor, color: "#fff", display: "grid", placeItems: "center", fontSize: 15, fontWeight: 800, flex: "none" }}>{b.wizardName.slice(0, 1)}</span>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 14, fontWeight: 700 }}>{b.offeringTitle}</div>
                <div style={{ fontSize: 12, color: "var(--fg3)" }}>{b.wizardName}{b.deliveryDate ? " · deliver by " + fmtD(b.deliveryDate) : ""}</div>
              </div>
              <div style={{ textAlign: "right" }}>
                <div style={{ fontSize: 14, fontWeight: 700 }}>${b.price.toLocaleString()}{b.unit ? " / " + b.unit : ""}</div>
                <Badge color={sm.color} bg={sm.bg} dot>{sm.label}</Badge>
              </div>
              <button onClick={(e) => { e.stopPropagation(); if (confirm("Cancel this booking?")) { S.cancelBooking(b.id); onToast("Booking cancelled"); } }} title="Cancel" style={{ border: 0, background: "none", cursor: "pointer", marginLeft: 4 }}><Icon name="x" size={18} color="var(--fg3)" /></button>
            </div>
          </Card>
        ); })}
      </div>
    );
  }

  function WizardsView({ onToast, onNav }) {
    const [tab, setTab] = React.useState("discover");
    const [ctFilter, setCtFilter] = React.useState("all");
    const [svcFilter, setSvcFilter] = React.useState("all");
    const [openWizard, setOpenWizard] = React.useState(null);
    const [pair, setPair] = React.useState(null);
    const [openContent, setOpenContent] = React.useState(null);
    const [addContent, setAddContent] = React.useState(false);
    const myWiz = S.getMyWizard();
    const bookingCount = S.getBookings().length;

    const feed = S.getWizardFeed().filter((c) => ctFilter === "all" || c.type === ctFilter);
    const experts = S.getWizards().filter((w) => svcFilter === "all" || (w.specialties || []).includes(svcFilter));

    return (
      <div style={{ maxWidth: "var(--page-w)", margin: "0 auto" }}>
        <div style={{ marginBottom: 18 }}><WizardBanner onExplore={() => setTab("experts")} onBecome={() => onNav && onNav("settings")} /></div>

        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 18, flexWrap: "wrap" }}>
          <Segmented value={tab} onChange={setTab} options={[
            { value: "discover", label: "Discover", icon: "sparkles" },
            { value: "experts", label: "Experts", icon: "users" },
            { value: "bookings", label: bookingCount ? `Bookings · ${bookingCount}` : "Bookings", icon: "calendar-check" },
          ]} />
        </div>

        {tab === "discover" && (
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 14, flexWrap: "wrap" }}>
              <div style={{ fontSize: 13, color: "var(--fg3)", flex: 1 }}>Free tips, best practices, ideas and short videos from social-media experts.</div>
              {myWiz
                ? <Button variant="primary" icon="plus" onClick={() => setAddContent(true)}>Add content</Button>
                : <span style={{ fontSize: 12, color: "var(--fg4)", display: "flex", gap: 6, alignItems: "center" }}><Icon name="lock" size={13} color="var(--fg4)" />Publish a Wizard profile to add content</span>}
            </div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 6, marginBottom: 18 }}>
              {[{ id: "all", label: "All" }].concat(CT).map((t) => { const on = ctFilter === t.id; return <button key={t.id} onClick={() => setCtFilter(t.id)} style={{ display: "inline-flex", alignItems: "center", gap: 5, border: `1px solid ${on ? "var(--leap-teal)" : "var(--border-strong)"}`, background: on ? "var(--accent-weak)" : "transparent", color: on ? "var(--accent)" : "var(--fg2)", borderRadius: 999, padding: "5px 12px", fontSize: 12.5, fontWeight: 600, cursor: "pointer", fontFamily: "inherit" }}>{t.icon && t.id !== "all" && <Icon name={t.icon} size={13} color={on ? "var(--accent)" : (t.color || "var(--fg3)")} />}{t.label}</button>; })}
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(250px,1fr))", gap: 16 }}>
              {feed.map((c) => <ContentCard key={c.wizardId + c.id} c={c} onOpen={setOpenContent} />)}
            </div>
          </div>
        )}

        {tab === "experts" && (
          <div>
            <div style={{ marginBottom: 18 }}><ServiceChips value={svcFilter} onPick={setSvcFilter} /></div>
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill,minmax(280px,1fr))", gap: 16 }}>
              {experts.map((w) => <ExpertCard key={w.id} w={w} onOpen={setOpenWizard} />)}
              {!experts.length && <Card pad={30} style={{ gridColumn: "1 / -1", textAlign: "center", color: "var(--fg3)" }}>No experts in this category yet.</Card>}
            </div>
          </div>
        )}

        {tab === "bookings" && <Bookings onToast={onToast} onBrowse={() => setTab("experts")} onOpenWizard={setOpenWizard} />}

        <ExpertModal w={openWizard} onClose={() => setOpenWizard(null)} onBook={(w, o) => { setOpenWizard(null); setPair({ w, o }); }} onToast={onToast} />
        <BookModal pair={pair} onClose={() => setPair(null)} onToast={onToast} />
        <ContentModal c={openContent} onClose={() => setOpenContent(null)} />
        {addContent && <AddContentModal onClose={() => setAddContent(false)} onToast={onToast} />}
      </div>
    );
  }
  window.WizardsView = WizardsView;
})();
