// Full-page "create" flows: NewProjectPage, InviteMemberPage, NewApiKeyPage,
// NewSshKeyPage, UploadFilePage. Each renders inside the main content area
// with a back link to the listing page.

// ---------- Shared "create page" wrapper ----------
const CreatePage = ({ icon, title, subtitle, backTo, backLabel, children, footer }) => (
  <div className="hx-screen hx-create">
    <button className="hx-back" onClick={() => window.__nav(backTo)}>
      <IconArrowL size={14}/> Back to {backLabel}
    </button>
    <header className="hx-sh">
      <div className="hx-sh-left">
        <div className="hx-sh-title">{icon}<h1>{title}</h1></div>
        {subtitle && <div className="hx-sh-sub">{subtitle}</div>}
      </div>
    </header>
    <Card>{children}</Card>
    <div className="hx-create-foot">{footer}</div>
    <style>{`
      .hx-create { max-width: 760px; }
      .hx-back {
        display: inline-flex; align-items: center; gap: 6px;
        background: transparent; border: none; cursor: pointer;
        color: var(--muted); font: inherit; font-size: 13px; padding: 4px 0;
        margin-bottom: 4px; align-self: flex-start;
      }
      .hx-back:hover { color: var(--ink); }
      .hx-create-foot { display: flex; gap: 10px; justify-content: flex-end; }
      @media (max-width: 640px) {
        .hx-create-foot { flex-direction: column-reverse; }
        .hx-create-foot > button { width: 100%; justify-content: center; }
      }
    `}</style>
  </div>
);

// ============================================================
// New Workspace
// ============================================================
const NewProjectPage = ({ data, setData }) => {
  const [name, setName] = React.useState("");
  const [desc, setDesc] = React.useState("");
  const [defaultScript, setDefaultScript] = React.useState("catalogue-extractor");
  const [makeCurrent, setMakeCurrent] = React.useState(true);
  const slugify = (s) => s.toLowerCase().trim().replace(/[^a-z0-9-]+/g, "-").replace(/^-|-$/g, "");
  const slug = slugify(name) || "new-workspace";

  const onCreate = () => {
    setData(d => ({
      ...d,
      projects: [...d.projects, { id: "p"+Math.random().toString(36).slice(2,6), name: slug, created: "Just now", cost: 0, collab: 1 }],
      currentProject: makeCurrent ? slug : d.currentProject,
      projectOptions: [...d.projectOptions, slug],
    }));
    window.__toast(`Workspace "${slug}" created`);
    window.__nav("clients");
  };

  return (
    <CreatePage icon={<IconFolder size={20}/>} title="New workspace"
      subtitle="Workspaces isolate API keys, members, credits, and script usage."
      backTo="clients" backLabel="Clients"
      footer={<>
        <Btn kind="secondary" onClick={() => window.__nav("clients")}>Cancel</Btn>
        <Btn kind="primary" disabled={!name.trim()} onClick={onCreate}>Create workspace</Btn>
      </>}>
      <FormField label="Workspace name" hint={name ? <>Resource slug: <code style={{fontFamily:"var(--mono)",fontSize:12}}>{slug}</code></> : "Lowercase letters, numbers, and dashes."}>
        <Input value={name} onChange={e=>setName(e.target.value)} placeholder="e.g. sheetal-furniture"/>
      </FormField>
      <FormField label="Description" hint="Optional — shown on the client list and in invites.">
        <textarea className="hx-ta" value={desc} onChange={e=>setDesc(e.target.value)} rows={3} placeholder="What is this workspace for?"/>
      </FormField>
      <FormField label="Default script" hint="Used when this workspace opens the run-script flow.">
        <Input value={defaultScript} onChange={e=>setDefaultScript(e.target.value)}/>
      </FormField>
      <div className="hx-toggle-row">
        <Toggle checked={makeCurrent} onChange={setMakeCurrent}/>
        <div>
          <div style={{fontSize:13.5,fontWeight:500}}>Switch to this workspace</div>
          <div style={{fontSize:12.5,color:"var(--muted)"}}>Make the new workspace active immediately after creation.</div>
        </div>
      </div>
      <CreatePageStyles/>
    </CreatePage>
  );
};

// ============================================================
// Invite member — with redesigned role section
// ============================================================
const ROLE_DEFS = [
  { id: "Member", title: "Member",
    desc: "Run approved scripts, upload inputs, download artifacts, and view own usage.",
    icon: IconUser },
  { id: "Admin", title: "Admin",
    desc: "Everything a Member can do, plus manage workspaces, members, scripts, and usage.",
    icon: IconSettings },
  { id: "Billing", title: "Billing manager",
    desc: "Manage payment methods, view invoices, and review credit usage. No package approval access.",
    icon: IconCard },
];

const InviteMemberPage = ({ data, setData }) => {
  const [emails, setEmails] = React.useState("");
  const [role, setRole] = React.useState("Member");
  const [project, setProject] = React.useState("All workspaces");
  const [message, setMessage] = React.useState("");

  const emailList = emails.split(/[\s,]+/).map(s => s.trim()).filter(s => s.includes("@"));

  const onInvite = async () => {
    const newMembers = emailList.map(email => ({
      id: "m"+Math.random().toString(36).slice(2,6),
      name: email.split("@")[0],
      email, role,
      lastActive: "—",
      status: "Pending",
    }));
    try {
      for (const email of emailList) {
        await window.api.call("inviteMember", { id: data.org.id }, { email, roleKey: role, message });
      }
    } catch (e) {
      window.__toast(e.message || "Invite API failed", "warn");
      return;
    }
    setData(d => ({...d, members: [...d.members, ...newMembers]}));
    window.__toast(`${newMembers.length} invite${newMembers.length===1?"":"s"} sent`);
    window.__nav("members");
  };

  return (
    <CreatePage icon={<IconUsers size={20}/>} title="Invite member"
      subtitle="Invite teammates to your organization. They'll get an email link to join."
      backTo="members" backLabel="Members"
      footer={<>
        <Btn kind="secondary" onClick={() => window.__nav("members")}>Cancel</Btn>
        <Btn kind="primary" disabled={emailList.length === 0} onClick={onInvite}>
          {emailList.length > 1 ? `Send ${emailList.length} invites` : "Send invite"}
        </Btn>
      </>}>
      <FormField label="Email addresses" hint={emailList.length > 0 ? `${emailList.length} valid email${emailList.length===1?"":"s"} detected. Separate multiple with commas or spaces.` : "Paste one or more emails, separated by commas or spaces."}>
        <textarea className="hx-ta" value={emails} onChange={e=>setEmails(e.target.value)} rows={2} placeholder="alice@example.com, bob@example.com"/>
      </FormField>

      <FormField label="Role">
        <div className="hx-role-cards">
          {ROLE_DEFS.map(r => {
            const IconC = r.icon;
            const active = role === r.id;
            return (
              <label key={r.id} className={`hx-role-card ${active ? "on" : ""}`}>
                <input type="radio" name="role" checked={active} onChange={() => setRole(r.id)}/>
                <span className="hx-role-icon"><IconC size={16}/></span>
                <span className="hx-role-meta">
                  <span className="hx-role-name">{r.title}</span>
                  <span className="hx-role-desc">{r.desc}</span>
                </span>
                <span className="hx-role-radio" aria-hidden="true">
                  <span className="hx-role-radio-dot"/>
                </span>
              </label>
            );
          })}
        </div>
      </FormField>

      <FormField label="Access" hint="Restrict the new member to a single workspace, or grant access to all.">
        <select className="hx-select" value={project} onChange={e=>setProject(e.target.value)}>
          <option>All workspaces</option>
          {data.projectOptions.map(p => <option key={p}>{p}</option>)}
        </select>
      </FormField>

      <FormField label="Personal message" hint="Optional — included in the invitation email.">
        <textarea className="hx-ta" value={message} onChange={e=>setMessage(e.target.value)} rows={3} placeholder="Welcome to the team! Let me know if you have questions."/>
      </FormField>

      <CreatePageStyles/>
    </CreatePage>
  );
};

// ============================================================
// New API Key
// ============================================================
const NewApiKeyPage = ({ data, setData }) => {
  const [name, setName] = React.useState("");
  const [env, setEnv] = React.useState("live");
  const [project, setProject] = React.useState(data.currentProject);
  const [scopes, setScopes] = React.useState({ jobs: true, files: false, scripts: false, billing: false });
  const [created, setCreated] = React.useState(null);

  const onCreate = async () => {
    let key = `cm-${env}-${Math.random().toString(36).slice(2,12)}${Math.random().toString(36).slice(2,12)}`;
    try {
      const result = await window.api.call("createApiKey", { id: data.org.id }, {
        name,
        environment: env,
        workspace: project,
        scopes: Object.entries(scopes).filter(([, enabled]) => enabled).map(([scope]) => scope),
      });
      key = result?.apiKey?.key || result?.key || key;
    } catch (e) {
      window.__toast(e.message || "API-key create failed", "warn");
      return;
    }
    setData(d => ({...d, apiKeys: [
      { id:"k"+Math.random().toString(36).slice(2,6), name, key, created: "Just now", lastUsed: "—", revealed: true }, ...d.apiKeys
    ]}));
    setCreated(key);
  };

  if (created) {
    return (
      <CreatePage icon={<IconKey size={20}/>} title="API key created"
        subtitle="Copy this key now — it won't be shown in full again."
        backTo="api-keys" backLabel="API Keys"
        footer={<Btn kind="primary" onClick={() => window.__nav("api-keys")}>Done</Btn>}>
        <div className="hx-key-result">
          <Pill tone="good">✓ Key ready</Pill>
          <div className="hx-key-box">
            <span className="hx-key-text">{created}</span>
            <Btn kind="secondary" size="sm" icon={<IconCopy size={13}/>}
              onClick={() => { navigator.clipboard.writeText(created); window.__toast("Key copied to clipboard"); }}>Copy</Btn>
          </div>
          <Banner tone="warn" icon={<IconInfo size={16}/>}>
            Store this key in a secret manager. Never commit it to source control.
          </Banner>
        </div>
        <CreatePageStyles/>
      </CreatePage>
    );
  }

  return (
    <CreatePage icon={<IconKey size={20}/>} title="New API key"
      subtitle={`API keys authenticate your applications when calling ${window.APP_CONFIG.brand.productName}.`}
      backTo="api-keys" backLabel="API Keys"
      footer={<>
        <Btn kind="secondary" onClick={() => window.__nav("api-keys")}>Cancel</Btn>
        <Btn kind="primary" disabled={!name.trim()} onClick={onCreate}>Create key</Btn>
      </>}>
      <FormField label="Name" hint="A descriptive label so you can identify this key later.">
        <Input value={name} onChange={e=>setName(e.target.value)} placeholder="e.g. prod-server, ci-pipeline"/>
      </FormField>

      <FormField label="Environment">
        <div className="hx-env-grid">
          {[
            { v: "live", label: "Live", desc: "Production traffic. Billed to your account." },
            { v: "test", label: "Test", desc: "Sandboxed. Free. Rate-limited." },
          ].map(opt => (
            <button key={opt.v} type="button" className={`hx-env-card ${env===opt.v ? "on" : ""}`} onClick={() => setEnv(opt.v)}>
              <div className="hx-env-h">
                <span className="hx-env-label">{opt.label}</span>
                <span className={`hx-env-tag ${opt.v==="live"?"live":"test"}`}>{opt.v.toUpperCase()}</span>
              </div>
              <div className="hx-env-desc">{opt.desc}</div>
            </button>
          ))}
        </div>
      </FormField>

      <FormField label="Workspace" hint="Credits, rate limits, and usage roll up to this workspace.">
        <select className="hx-select" value={project} onChange={e=>setProject(e.target.value)}>
          {data.projectOptions.map(p => <option key={p}>{p}</option>)}
        </select>
      </FormField>

      <FormField label="Scopes" hint="Restrict what this key can do.">
        <div className="hx-scope-list">
          {[
            { id: "jobs",      label: "Jobs",      desc: "Create, start, and read script jobs" },
            { id: "files",     label: "Files",     desc: "Upload inputs and download artifacts" },
            { id: "scripts",   label: "Scripts",   desc: "Read available scripts and versions" },
            { id: "billing",   label: "Billing",   desc: "Read invoices and spend (read-only)" },
          ].map(s => (
            <label key={s.id} className="hx-scope-row">
              <input type="checkbox" checked={scopes[s.id]} onChange={e => setScopes({...scopes, [s.id]: e.target.checked})}/>
              <div>
                <div style={{fontSize:13.5,fontWeight:500}}>{s.label}</div>
                <div style={{fontSize:12.5,color:"var(--muted)"}}>{s.desc}</div>
              </div>
            </label>
          ))}
        </div>
      </FormField>

      <CreatePageStyles/>
    </CreatePage>
  );
};

// ============================================================
// New SSH Key
// ============================================================
const NewSshKeyPage = ({ data, setData }) => {
  const [label, setLabel] = React.useState("");
  const [pub, setPub] = React.useState("");
  const valid = pub.trim().startsWith("ssh-") && pub.trim().split(/\s+/).length >= 2;
  const onCreate = () => {
    const fp = "SHA256:" + Array.from({length:16}, () => Math.floor(Math.random()*256).toString(16).padStart(2,"0")).join(":");
    setData(d => ({...d, sshKeys: [...d.sshKeys, { id:"s"+Math.random().toString(36).slice(2,6), label, fp, added: "Just now" }]}));
    window.__toast(`SSH key "${label}" added`);
    window.__nav("ssh-key");
  };

  return (
    <CreatePage icon={<IconKey size={20}/>} title="Add SSH key"
      subtitle="This legacy route is retained for compatibility. Package upload is handled in Package Manager."
      backTo="ssh-key" backLabel="SSH Keys"
      footer={<>
        <Btn kind="secondary" onClick={() => window.__nav("ssh-key")}>Cancel</Btn>
        <Btn kind="primary" disabled={!label.trim() || !valid} onClick={onCreate}>Add SSH key</Btn>
      </>}>
      <FormField label="Label" hint="A name for this key (usually the machine it's on).">
        <Input value={label} onChange={e=>setLabel(e.target.value)} placeholder="e.g. work-macbook"/>
      </FormField>
      <FormField label="Public key" hint={pub && !valid ? <span style={{color:"var(--bad)"}}>Doesn't look like a valid public key. Should start with "ssh-rsa", "ssh-ed25519", etc.</span> : "Paste the contents of your .pub file. Begins with 'ssh-rsa' or 'ssh-ed25519'."}>
        <textarea className="hx-ta hx-ta-mono" value={pub} onChange={e=>setPub(e.target.value)} rows={6} placeholder="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... user@host"/>
      </FormField>
      <details className="hx-help-details">
        <summary>How do I get my public key?</summary>
        <div style={{padding: "8px 0", fontSize: 13, color: "var(--ink-2)", lineHeight: 1.6}}>
          <p style={{margin: "4px 0"}}>On macOS or Linux, run:</p>
          <pre className="hx-code">cat ~/.ssh/id_ed25519.pub</pre>
          <p style={{margin: "4px 0"}}>If the file doesn't exist, generate one with:</p>
          <pre className="hx-code">ssh-keygen -t ed25519 -C "your-email@example.com"</pre>
        </div>
      </details>
      <CreatePageStyles/>
    </CreatePage>
  );
};

// ============================================================
// Upload File — with real file input + progress
// ============================================================
const UploadFilePage = ({ data, setData }) => {
  const [files, setFiles] = React.useState([]);     // [{file, progress, done, error}]
  const [purpose, setPurpose] = React.useState("script-input");
  const inputRef = React.useRef();
  const [dragOver, setDragOver] = React.useState(false);

  const fmt = (n) => n < 1024 ? `${n} B` : n < 1024*1024 ? `${(n/1024).toFixed(1)} KB` : n < 1024*1024*1024 ? `${(n/(1024*1024)).toFixed(1)} MB` : `${(n/(1024*1024*1024)).toFixed(2)} GB`;

  const addFiles = (fileList) => {
    const arr = Array.from(fileList);
    setFiles(prev => [...prev, ...arr.map(file => ({ file, progress: 0, done: false }))]);
    // Simulate upload progress
    arr.forEach((file, j) => {
      const start = files.length + j;
      const interval = setInterval(() => {
        setFiles(prev => {
          const copy = [...prev];
          const t = copy[start];
          if (!t || t.done) { clearInterval(interval); return prev; }
          const next = Math.min(100, t.progress + Math.random()*18 + 4);
          copy[start] = { ...t, progress: next, done: next >= 100 };
          if (next >= 100) clearInterval(interval);
          return copy;
        });
      }, 220);
    });
  };

  const onDrop = (e) => {
    e.preventDefault(); setDragOver(false);
    if (e.dataTransfer.files?.length) addFiles(e.dataTransfer.files);
  };

  const allDone = files.length > 0 && files.every(f => f.done);

  const onCommit = () => {
    const purposeLabel = ({ "script-input": "script input", "artifact": "artifact", "package": "package", "reference": "reference" })[purpose];
    const today = new Date().toLocaleDateString("en-US", { month:"short", day:"2-digit", year:"numeric" });
    const newRows = files.map(f => ({
      id: "f"+Math.random().toString(36).slice(2,6),
      name: f.file.name,
      purpose: purposeLabel,
      size: fmt(f.file.size),
      created: today,
    }));
    setData(d => ({...d, files: [...newRows, ...d.files]}));
    window.__toast(`${files.length} file${files.length===1?"":"s"} uploaded`);
    window.__nav("files");
  };

  return (
    <CreatePage icon={<IconUpload size={20}/>} title="Upload file"
      subtitle="Upload script inputs, generated artifacts, package files, or reference documents."
      backTo="files" backLabel="Files"
      footer={<>
        <Btn kind="secondary" onClick={() => window.__nav("files")}>Cancel</Btn>
        <Btn kind="primary" disabled={!allDone} onClick={onCommit}>
          {files.length === 0 ? "Upload" : allDone ? `Add ${files.length} file${files.length===1?"":"s"}` : "Uploading…"}
        </Btn>
      </>}>
      <FormField label="Purpose" hint="How this file will be used.">
        <select className="hx-select" value={purpose} onChange={e=>setPurpose(e.target.value)}>
          <option value="script-input">Script input</option>
          <option value="artifact">Generated artifact</option>
          <option value="package">Script package</option>
          <option value="reference">Reference / docs</option>
        </select>
      </FormField>

      <FormField label="Files" hint="JSONL, TXT, or CSV. Up to 5 GB per file.">
        <div
          className={`hx-drop ${dragOver ? "on" : ""}`}
          onDragOver={(e)=>{e.preventDefault(); setDragOver(true);}}
          onDragLeave={()=>setDragOver(false)}
          onDrop={onDrop}
          onClick={() => inputRef.current?.click()}
          role="button" tabIndex={0}
          onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && inputRef.current?.click()}
        >
          <IconUpload size={26} className="hx-drop-icon"/>
          <div className="hx-drop-title">Drop files here, or <span className="hx-link">browse</span></div>
          <div className="hx-drop-hint">JSONL · TXT · CSV — up to 5 GB</div>
          <input ref={inputRef} type="file" multiple style={{ display: "none" }}
            onChange={e => e.target.files && addFiles(e.target.files)} />
        </div>
      </FormField>

      {files.length > 0 && (
        <div className="hx-upload-list">
          {files.map((f, i) => (
            <div key={i} className="hx-upload-row">
              <IconFile size={16} style={{color:"var(--muted)",flexShrink:0}}/>
              <div className="hx-upload-meta">
                <div className="hx-upload-name">{f.file.name}</div>
                <div className="hx-upload-sub">
                  <span>{fmt(f.file.size)}</span>
                  <span>·</span>
                  {f.done ? <span style={{color:"var(--good)"}}>✓ Uploaded</span> : <span>{Math.round(f.progress)}%</span>}
                </div>
                <div className="hx-upload-bar"><div className="hx-upload-bar-fill" style={{width: f.progress + "%"}}/></div>
              </div>
              <button className="hx-icon-btn" onClick={(e) => { e.stopPropagation(); setFiles(prev => prev.filter((_, j) => j !== i)); }} aria-label="Remove">
                <IconClose size={14}/>
              </button>
            </div>
          ))}
        </div>
      )}

      <CreatePageStyles/>
    </CreatePage>
  );
};

// ---------- Shared form/page styles ----------
const CreatePageStyles = () => (
  <style>{`
    .hx-ta { width: 100%; font: inherit; padding: 10px 12px; border: 1px solid var(--line); border-radius: 8px; resize: vertical; background: var(--panel); color: var(--ink); font-size: 14px; }
    .hx-ta:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent); }
    .hx-ta-mono { font-family: var(--mono); font-size: 12.5px; line-height: 1.5; }
    .hx-select { width: 100%; height: var(--row); padding: 0 10px; font: inherit; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); color: var(--ink); }
    .hx-select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent) 18%, transparent); }

    .hx-toggle-row { display: flex; gap: 12px; align-items: center; padding: 12px 14px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 10px; margin-top: 8px; }

    /* Role cards */
    .hx-role-cards { display: flex; flex-direction: column; gap: 8px; }
    .hx-role-card {
      display: grid;
      grid-template-columns: auto 1fr auto;
      gap: 14px; align-items: flex-start;
      padding: 14px; cursor: pointer;
      background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
      transition: border-color .12s, background .12s;
    }
    .hx-role-card:hover { border-color: color-mix(in oklab, var(--ink) 30%, transparent); }
    .hx-role-card.on { border-color: var(--accent); background: var(--accent-soft); }
    .hx-role-card input { position: absolute; opacity: 0; pointer-events: none; }
    .hx-role-icon {
      width: 34px; height: 34px; border-radius: 8px;
      background: var(--panel-2); border: 1px solid var(--line);
      display: inline-flex; align-items: center; justify-content: center; color: var(--ink-2);
      flex-shrink: 0;
    }
    .hx-role-card.on .hx-role-icon { background: var(--panel); color: var(--accent); border-color: color-mix(in oklab, var(--accent) 35%, transparent); }
    .hx-role-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
    .hx-role-name { font-size: 14px; font-weight: 600; color: var(--ink); }
    .hx-role-desc { font-size: 13px; color: var(--muted); line-height: 1.5; }
    .hx-role-radio {
      width: 18px; height: 18px; border-radius: 50%;
      border: 1.5px solid var(--line);
      display: inline-flex; align-items: center; justify-content: center;
      flex-shrink: 0; margin-top: 8px;
      background: var(--panel);
    }
    .hx-role-card.on .hx-role-radio { border-color: var(--accent); background: var(--accent); }
    .hx-role-radio-dot { width: 6px; height: 6px; border-radius: 50%; background: white; opacity: 0; }
    .hx-role-card.on .hx-role-radio-dot { opacity: 1; }

    /* Env cards (for API key) */
    .hx-env-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
    @media (max-width: 640px) { .hx-env-grid { grid-template-columns: 1fr; } }
    .hx-env-card {
      text-align: left; padding: 14px; cursor: pointer;
      background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
      font: inherit; color: var(--ink);
    }
    .hx-env-card:hover { border-color: color-mix(in oklab, var(--ink) 30%, transparent); }
    .hx-env-card.on { border-color: var(--accent); background: var(--accent-soft); }
    .hx-env-h { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
    .hx-env-label { font-size: 14px; font-weight: 600; }
    .hx-env-tag { font-family: var(--mono); font-size: 10.5px; padding: 2px 6px; border-radius: 4px; font-weight: 500; }
    .hx-env-tag.live { background: #fee9e0; color: #b04a14; }
    .hx-env-tag.test { background: var(--line-2); color: var(--muted); }
    .hx-env-desc { font-size: 13px; color: var(--muted); line-height: 1.4; }

    /* Scope list */
    .hx-scope-list { display: flex; flex-direction: column; gap: 4px; }
    .hx-scope-row { display: flex; gap: 12px; align-items: flex-start; padding: 10px; border-radius: 8px; cursor: pointer; }
    .hx-scope-row:hover { background: var(--hover); }
    .hx-scope-row input { margin-top: 3px; accent-color: var(--accent); }

    /* SSH help */
    .hx-help-details { margin-top: 4px; }
    .hx-help-details summary { color: var(--muted); cursor: pointer; font-size: 13px; user-select: none; padding: 4px 0; }
    .hx-help-details summary:hover { color: var(--ink-2); }
    .hx-code { background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px; font-family: var(--mono); font-size: 12.5px; margin: 4px 0; overflow-x: auto; }

    /* API key result */
    .hx-key-result { display: flex; flex-direction: column; gap: 14px; }
    .hx-key-box { display: flex; gap: 10px; align-items: center; padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2); font-family: var(--mono); font-size: 13px; flex-wrap: wrap; }
    .hx-key-text { flex: 1; min-width: 0; word-break: break-all; }

    /* File drop zone */
    .hx-drop {
      display: flex; flex-direction: column; gap: 6px; align-items: center; justify-content: center;
      padding: 36px 20px; cursor: pointer;
      border: 1.5px dashed var(--line); border-radius: 12px;
      background: var(--panel-2);
      transition: border-color .12s, background .12s;
    }
    .hx-drop:hover, .hx-drop.on {
      border-color: var(--accent);
      background: var(--accent-soft);
    }
    .hx-drop-icon { color: var(--muted); }
    .hx-drop:hover .hx-drop-icon, .hx-drop.on .hx-drop-icon { color: var(--accent); }
    .hx-drop-title { font-size: 14px; font-weight: 500; color: var(--ink); }
    .hx-drop-hint { font-size: 12.5px; color: var(--muted); }

    .hx-upload-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
    .hx-upload-row {
      display: flex; gap: 12px; align-items: center;
      padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px;
      background: var(--panel-2);
    }
    .hx-upload-meta { flex: 1; min-width: 0; }
    .hx-upload-name { font-size: 13.5px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .hx-upload-sub { font-size: 12px; color: var(--muted); display: flex; gap: 6px; margin-top: 2px; }
    .hx-upload-bar { height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; margin-top: 6px; }
    .hx-upload-bar-fill { height: 100%; background: var(--accent); transition: width .2s ease; }
  `}</style>
);

Object.assign(window, {
  NewProjectPage, InviteMemberPage, NewApiKeyPage, NewSshKeyPage, UploadFilePage,
});
