           <div>
             ${numRow("Amount min ($)", "amount_min", 'type="number" step="0.01" min="0"')}
             ${numRow("Amount max ($)", "amount_max", 'type="number" step="0.01" min="0"')}
             ${numRow("Shipping min ($)", "shipping_min", 'type="number" step="0.01" min="0"')}
             ${numRow("Shipping max ($)", "shipping_max", 'type="number" step="0.01" min="0"')}
           </div>
         </div>`;
    } else if (step === 7) {
      b.innerHTML = H("Step 7 — Gmail accounts") + hint(`Select up to ${OPT.limits.max_accounts} sending accounts. Only authorized, active accounts are shown.`) +
        (OPT.accounts.length ? pickList("accounts", C.account_ids, a => ({ v: a.id, main: a.email, sub: `${a.sends_today}/${a.daily_limit} today · ${a.sending_method}` }), "account_ids")
          : `<div class="notice warn"><span class="n-ico">⚠</span><div>No authorized Gmail accounts. Connect one on the Gmail Accounts page first.</div></div>`);
    } else if (step === 8) {
      const strat = C.rotation_strategy;
      b.innerHTML = H("Step 8 — Account rotation") + hint("How senders rotate. Weighted lets you favor specific accounts; per-account caps and cooldowns are enforced regardless.") +
        `<div class="radio-row">
           <label class="chk"><input type="radio" name="rotStrat" value="sequential" ${strat === "sequential" ? "checked" : ""}> Sequential</label>
           <label class="chk"><input type="radio" name="rotStrat" value="weighted" ${strat === "weighted" ? "checked" : ""}> Weighted</label>
         </div>
         <div id="rotExtra"></div>`;
      bindRotExtra();
    } else if (step === 9) {
      b.innerHTML = H("Step 9 — Limits & pacing") + hint("Conservative pacing protects your accounts. Sends are throttled and retried with exponential backoff.") +
        `<div class="grid cols-2">
           <div>
             ${numRow("Max sends per account", "max_per_account", 'type="number" min="1" max="2000"')}
             ${numRow("Interval between sends (s)", "send_interval_seconds", 'type="number" step="0.5" min="0.5" max="3600"')}
           </div>
           <div>
             ${numRow("Rate cap (per minute)", "rate_per_minute", 'type="number" min="1" max="600"')}
             ${numRow("Max retries", "max_retries", 'type="number" min="0" max="10"')}
             ${numRow("Retry delay (s)", "retry_delay_seconds", 'type="number" min="5" max="3600"')}
           </div>
         </div>`;
    } else if (step === 10) {
      b.innerHTML = H("Step 10 — Company phone") + hint("Which active phone number appears as %CompanyPhone%.") +
        (OPT.phones.length ? pickList("phones", C.phone_selection === "fixed" ? (C.variable_config.phone_id ?? null) : null, p => ({ v: p.id, main: p.phone, sub: p.label || "" }), "phone_fixed", true)
          : `<div class="notice warn"><span class="n-ico">⚠</span><div>No active phone numbers. %CompanyPhone% will be blank unless numbers are added on the Company Phones page.</div></div>`) +
        `<label class="lab mt-2">Selection rule</label>
         <div class="radio-row">
           ${["round_robin", "random", "fixed"].map(m => `
             <label class="chk"><input type="radio" name="phSel" value="${m}" ${C.phone_selection === m ? "checked" : ""}>
             ${m === "round_robin" ? "Round robin" : m === "fixed" ? "Fixed (pick above)" : "Random"}</label>`).join("")}
         </div>`;
    } else if (step === 11) {
      b.innerHTML = H("Step 11 — Unsubscribe handling") + hint("Permission-based sending requires working opt-out. Disabling is not permitted.") +
        `<label class="chk"><input type="checkbox" id="w_unsub" ${C.unsubscribe_enabled ? "checked" : ""}> Append unsubscribe link (%UnsubscribeLink%) to every message</label>
         <div class="notice info mt-2"><span class="n-ico">ℹ</span><div>Suppression list is always checked before sending, regardless of this setting. Recipients who opt out are skipped automatically.</div></div>
         <label class="lab mt-2">Preview sample size</label>
         <input id="w_pss" type="number" min="1" max="20" value="${C.preview_sample_size}">`;
    } else if (step === 12) {
      const vc = C.variable_config;
      const list = OPT.lists.find(l => l.id === C.recipient_list_id);
      const accs = (OPT.accounts || []).filter(a => C.account_ids.includes(a.id));
      const tpls = (OPT.templates || []).filter(t => C.template_ids.includes(t.id));
      const subCount = (OPT.subjects || []).filter(s => C.subject_set_ids.includes(s.id)).length;
      const total = list ? list.valid_count : 0;
      const cap = Math.max(...(accs.map(a => C.max_per_account).concat([0])), 1);
      const capacity = accs.length * cap;
      b.innerHTML = H("Step 12 — Confirm and start") + hint("Review the full configuration. You can still edit any step, then create the campaign.") +
        `<div class="card" style="box-shadow:none"><div class="card-bd">
          <dl class="wsum">
            <dt>Campaign name</dt><dd>${esc(C.name) || "—"}</dd>
            <dt>Recipient list</dt><dd>${list ? esc(list.name) + ` (${list.valid_count} valid of ${list.row_count})` : "—"}</dd>
            <dt>Subjects</dt><dd>${subCount} selected · ${esc(C.subject_rotation)}</dd>
            <dt>Templates</dt><dd>${tpls.length ? tpls.map(t => esc(t.name)).join(", ") : "—"} · ${esc(C.template_sequence_mode)}</dd>
            <dt>Message type</dt><dd>${esc(C.message_type)}</dd>
            <dt>Attachments</dt><dd>${C.attach_mode === "none" ? "none" : esc(C.attach_mode) +
              (C.attach_mode === "pdf" && C.attach_pdf_template_id ? ` — template #${C.attach_pdf_template_id}` : "") +
              (C.attach_mode !== "none" && C.attach_mode !== "pdf" && C.attachment_id ? ` — attachment #${C.attachment_id}` : "")}</dd>
            <dt>Invoice format</dt><dd class="mono-s">${esc(vc.invoice_format || "{prefix}{R4}-{R5}-{R6}-{seq4}")} · prefix ${esc(vc.invoice_prefix || "INV-")}</dd>
            <dt>Amount range</dt><dd>${esc(vc.amount_min ?? 300)} – ${esc(vc.amount_max ?? 1500)} · shipping ${esc(vc.shipping_min ?? 5)} – ${esc(vc.shipping_max ?? 50)}</dd>
            <dt>Accounts</dt><dd>${accs.length ? accs.map(a => esc(a.email)).join(", ") : "—"} · ${esc(C.rotation_strategy)}${C.rotation_strategy === "weighted" ? ` (weights ${esc(JSON.stringify(C.rotation_weights))})` : ""}</dd>
            <dt>Per-account cap</dt><dd>${C.max_per_account} → capacity ${capacity} of ${total} recipients</dd>
            <dt>Pacing</dt><dd>${C.send_interval_seconds}s interval · ${C.rate_per_minute}/min · ${C.max_retries} retries @ ${C.retry_delay_seconds}s</dd>
            <dt>Phone</dt><dd>${esc(C.phone_selection)}</dd>
            <dt>Unsubscribe</dt><dd>${C.unsubscribe_enabled ? "enabled" : "disabled"}</dd>
          </dl>
          ${capacity < total ? `<div class="notice warn mt-2"><span class="n-ico">⚠</span><div>Account capacity (${capacity}) is below the recipient count (${total}). The campaign will stop when capacity is exhausted.</div></div>` : ""}
          <div class="notice info mt-2"><span class="n-ico">ℹ</span><div>After creating, the campaign opens in the live monitor where you press <strong>Start</strong>. No email leaves until you do.</div></div>
        </div></div>`;
    }
    b.scrollTop = 0;
    bindStep();
  }

  function pickList(kind, current, mapper, stateKey, radio = false) {
    const items = OPT[kind] || [];
    if (!items.length) return `<div class="empty-state"><div class="e-ico">◱</div><p>Nothing available yet.</p></div>`;
    const cur = Array.isArray(current) ? current : (current ? [current] : []);
    return `<div class="pick-list" id="pk_${stateKey}">` + items.map(it => {
      const m = mapper(it);
