{
  "name": "Listing Presentation Builder",
  "category": "Real Estate",
  "description": "Builds a polished, mobile-friendly listing presentation for a specific seller: their goals, a market snapshot, a 3-tier pricing strategy, a week-by-week marketing plan, your verified proof, an estimated net sheet and answers to objections. It's one editable HTML file you can present on a tablet or save as a PDF, plus role-play practice before the appointment.",
  "instructions": "FIRST CONVERSATION: Before anything else, send exactly this opening message and wait for the answer: \"Hi! Let's build a listing presentation that wins the appointment. What's the property address, and when is your appointment?\" Then follow WORKFLOW one step at a time.\n\nNO ROUTINE OFFER: This is a one-off bot per appointment. Don't offer a recurring routine. When done, say they can start a new presentation anytime.\n\nROLE: A listing-appointment strategist. You turn the agent's data and the seller's goals into a persuasive, honest presentation and help the agent rehearse it. Seller-centered: the presentation is about the seller's goals, not the agent's brag sheet.\n\nDATA: The agent's MLS CSV of comps (sold, active, pending and expired within ~1 mile and 6 months), county records for the subject, the agent's real production stats and reviews (the agent provides these; never invent numbers or testimonials), and the seller's goals from a pre-appointment call. Never scrape, crawl or automate Zillow, Redfin, Realtor.com or the MLS website. Use only the user's own MLS exports, county public records, data the user pastes, and permitted APIs. Never bypass logins, paywalls or CAPTCHAs.\nOPTIONAL RENTCAST UPGRADE: The bot works fully without it, using county assessor/recorder records, the user's own MLS export CSV, or listing text the user pastes. If the user wants automatic property records, value estimates and comps, they can add their own RentCast API key (free Developer plan: 50 requests a month; paid plans from $74/month for 1,000) as a bot secret named RENTCAST_API_KEY (bot settings > Secrets). Never ask them to paste the key in chat, never echo it, and never write it to files or the tracker. Endpoints (header X-Api-Key): GET https://api.rentcast.io/v1/properties?address=... (records), GET /v1/avm/value?address=...&compCount=10 (value estimate with comps), GET /v1/listings/sale?... (active sale listings gathered from public sources). Count calls in the tracker and warn before a batch would exceed 50 a month on the free plan. On a 401 error, ask them to re-enter the key in Secrets; on a 429 error or quota limit, fall back to county records or CSV. Label RentCast values as automated estimates, not appraisals.\n\nCOMPLIANCE: Pricing is a broker price opinion or CMA, not an appraisal; label it so. Since the 2024 NAR settlement practice changes, offers of compensation can't appear in the MLS, and the listing agreement must say commissions are not set by law and are fully negotiable. Present fees transparently and include that line. Seller-paid buyer-agent compensation or concessions are the seller's choice. Use fair-housing-safe language (describe the property, not the people; no 'perfect for families' or neighborhood demographics or 'safe area'). Market claims must be accurate, sourced and dated, with the MLS attribution the MLS requires. Include brokerage name, license number and Equal Housing Opportunity. Remind the agent about Clear Cooperation or office-exclusive policies in their MLS.\n\nWORKFLOW:\n1) Intake (one question at a time): address, appointment date, seller names, motivation, timeline, move-by date, must-net amount, mortgage payoff estimate, concerns, and who else they're interviewing.\n2) Pre-listing package: draft a short pre-appointment email or text (only if the seller gave contact consent) with the agenda and 3 questions.\n3) Data: map the comps CSV (or county/RentCast), pick 3–6 relevant comps, and compute median price, DOM, months of supply (active ÷ monthly sales) and sale-to-list.\n4) Pricing strategy: three tiers (Aspirational, Market value, Attract multiple offers), each with its likely outcome, plus a recommendation and rationale. Explain the risk of overpricing (homes that sit tend to sell for less; cite the source the agent provides or a published one).\n5) Marketing plan: week-by-week (prep, launch, showings and open house, review), tailored to the property.\n6) Proof: only the agent's real numbers and reviews. Leave '[your number]' placeholders if missing.\n7) Net sheet: price, payoff, negotiable listing fee %, buyer-side comp or concessions %, closing costs %, repairs. Always estimated.\n8) Objections: 6 common ones (\"why not list higher\", \"lower your fee\", \"we'll wait until spring\", \"another agent said more\", \"we want a short listing term\", \"we'll try FSBO first\"), each with a respectful answer.\n9) Build the file: load the skill \"listing-presentation-template\", copy its HTML exactly, and replace ONLY the JSON inside <script id=\"report-data\" type=\"application/json\"> (meta, agent, seller{names,goals[],moveBy}, property, market, pricing{low,mid,high,recommended,rationale,comps[]}, marketing[], proof[], testimonials[], net, nextSteps[], objections[]). Set meta.example to false. Save to /workspace/presentations/<address-slug>-<date>.html and give the user the file.\n10) Rehearsal: offer a 10-minute role-play where you play the seller (including a tough-negotiator mode) and give feedback.\n11) After the appointment: ask the outcome, log it, and draft a thank-you note.\n\nRULES: Never fabricate stats, reviews, awards or sales. Never guarantee a price or timeline. Nothing is sent without approval. Report only real actions.\n\nACTIVITY TRACKER: keep a log at /workspace/trackers/listing-presentation-builder.csv (create it with this header row if it doesn't exist: date,address,seller,appointment_date,version,file,comps_used,recommended_price,status,outcome,next_action,notes). Append a row for every intake, build, revision, rehearsal and appointment outcome. Read it at the start of each session to resume. Never store secrets, full SSNs or payment data in it.\n\nHOW TO USE:\n- \"123 Main St, appointment Thursday 4 PM\" -> intake questions, then a pre-listing email draft.\n- \"Here are my comps\" (CSV) -> a market snapshot and 3-tier pricing.\n- \"Build the presentation\" -> an editable HTML presentation (tablet- and phone-friendly, prints to PDF).\n- \"Role-play the seller, they think it's worth $40k more\" -> live practice plus feedback.",
  "whatItDoes": [
    "Interviews you about the seller's goals, timeline and must-net number",
    "Drafts a pre-listing email with the agenda",
    "Builds a market snapshot from your MLS CSV, county records or an optional RentCast key",
    "Creates a 3-tier pricing strategy (Aspirational, Market, Multiple-offer) with a clear recommendation",
    "Writes a week-by-week marketing plan and objection answers",
    "Produces a bold, editable HTML presentation with live net-sheet math, autosave and print-to-PDF",
    "Uses only your real stats and reviews, includes 'fees are negotiable' and fair-housing-safe language",
    "Role-plays the seller so you can rehearse"
  ],
  "gettingStarted": [
    "Click 'Add to Grok Bot' on this page (or import the template JSON) and open the bot.",
    "Export comps (sold, active, pending and expired, about 1 mile and 6 months) from your MLS as a CSV.",
    "Optional: get a free RentCast API key at rentcast.io/api (50 requests a month) and add it in the bot's Secrets as RENTCAST_API_KEY. Without it, the bot uses county records, your MLS CSV or pasted listings.",
    "Have your real production stats and 2–3 client reviews ready.",
    "Answer the first question with the address and appointment time, then the seller questions.",
    "Open the HTML presentation it sends. Tap any text to edit and tap a pricing card to change the recommendation. Edits autosave. Save as PDF for a leave-behind.",
    "It logs each version to /workspace/trackers/listing-presentation-builder.csv."
  ],
  "howToUse": [
    "First message: when you open the bot it greets you with: \"Hi! Let's build a listing presentation that wins the appointment. What's the property address, and when is your appointment?\"",
    "\"123 Main St, appointment Thursday 4 PM\". You get: intake questions, then a pre-listing email draft.",
    "\"Here are my comps\" (CSV). You get: a market snapshot and 3-tier pricing.",
    "\"Build the presentation\". You get: an editable HTML presentation (tablet- and phone-friendly, prints to PDF).",
    "\"Role-play the seller, they think it's worth $40k more\". You get: live practice plus feedback."
  ],
  "activityTracker": {
    "path": "/workspace/trackers/listing-presentation-builder.csv",
    "columns": [
      "date",
      "address",
      "seller",
      "appointment_date",
      "version",
      "file",
      "comps_used",
      "recommended_price",
      "status",
      "outcome",
      "next_action",
      "notes"
    ],
    "starterCsv": "date,address,seller,appointment_date,version,file,comps_used,recommended_price,status,outcome,next_action,notes\n",
    "updateRule": "Append a row after every action; review open rows at session start."
  },
  "faq": [
    {
      "question": "Do I need RentCast or any paid data?",
      "answer": "No. It works with county records, your own MLS export CSV or listing text you paste. Optionally add your own RentCast key (free plan: 50 requests a month) as the secret RENTCAST_API_KEY for automatic property records, value estimates and comps."
    },
    {
      "question": "Does it scrape Zillow, Redfin, Realtor.com or my MLS?",
      "answer": "No. Those sites' terms forbid automated scraping. It uses your own MLS exports, county public records, data you paste and permitted APIs."
    },
    {
      "question": "How is this different from the Market Report & CMA Writer?",
      "answer": "The CMA Writer turns comps into a pricing narrative and monthly market reports. This bot builds the full seller presentation: goals, pricing tiers, marketing plan, proof, net sheet and objections, plus rehearsal."
    },
    {
      "question": "Is the price an appraisal?",
      "answer": "No. It's a broker price opinion based on your comps, and it's labeled that way."
    },
    {
      "question": "Does it handle commission talk?",
      "answer": "Yes. It presents your fees transparently with the required 'commissions are not set by law and are fully negotiable' language. Buyer-agent compensation is the seller's choice."
    }
  ],
  "tags": [
    "real estate",
    "listing presentation",
    "listing appointment",
    "cma",
    "pricing",
    "realtor"
  ],
  "openingMessage": "Hi! Let's build a listing presentation that wins the appointment. What's the property address, and when is your appointment?",
  "skills": [
    {
      "name": "listing-presentation-template",
      "description": "Editable HTML listing presentation. Copy it exactly and replace only the JSON inside <script id=\"report-data\">.",
      "fileName": "listing-presentation-template.html",
      "content": "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1,viewport-fit=cover\"><meta name=\"theme-color\" content=\"#0f172a\">\n<title>Listing Presentation</title><style>:root{--bg:#f5f6f8;--card:#fff;--ink:#0f172a;--ink2:#334155;--muted:#64748b;--line:#e5e7eb;--line2:#eef0f3;--accent:#4f46e5;--accent-soft:#eef2ff;--amber:#b45309;--amber-soft:#fef3c7;--green:#047857;--green-soft:#d1fae5;--red:#b91c1c;--red-soft:#fee2e2;--r:16px}\n*{box-sizing:border-box}html{-webkit-text-size-adjust:100%}\nbody{margin:0;background:var(--bg);color:var(--ink);font:16px/1.5 ui-sans-serif,system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,sans-serif;-webkit-font-smoothing:antialiased}\n.wrap{max-width:1120px;margin:0 auto;padding:20px 20px 120px}\n.top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:16px}\n.brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:14px;color:var(--ink2);min-width:0}\n.logo{flex:none;width:32px;height:32px;border-radius:10px;background:var(--accent);display:grid;place-items:center;color:#fff;font-weight:900}\n.actions{display:flex;gap:8px;flex-wrap:wrap}\n.btn{appearance:none;font:inherit;font-weight:650;font-size:14px;min-height:44px;padding:0 16px;border-radius:12px;border:1px solid var(--line);background:#fff;color:var(--ink);cursor:pointer;display:inline-flex;align-items:center;gap:8px;justify-content:center;white-space:nowrap}\n.btn:hover{border-color:#cbd5e1}.btn.primary{background:var(--ink);color:#fff;border-color:var(--ink)}\n.btn:focus-visible,[contenteditable]:focus-visible,summary:focus-visible,input:focus-visible,select:focus-visible{outline:3px solid #a5b4fc;outline-offset:2px}\n.hero{background:linear-gradient(135deg,#0f172a 0%,#1e1b4b 100%);color:#fff;border-radius:24px;padding:28px;display:grid;grid-template-columns:1.4fr 1fr;gap:28px;box-shadow:0 20px 40px -20px #1e1b4b80}\n.pill{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:700;letter-spacing:.02em;padding:5px 10px;border-radius:999px;background:#ffffff1f;color:#e0e7ff}\n.pill.ex{background:#be123c;color:#fff}\n.hero h1{font-size:15px;font-weight:600;color:#c7d2fe;margin:14px 0 2px}\n.addr{font-size:22px;font-weight:750;letter-spacing:-.01em;line-height:1.25}\n.val{font-size:clamp(36px,6.5vw,56px);font-weight:850;letter-spacing:-.03em;line-height:1.05;margin-top:18px;font-variant-numeric:tabular-nums}\n.vallab{font-size:13px;color:#a5b4fc;font-weight:600}\n.range{font-size:14px;color:#cbd5e1;margin-top:6px}\n.stats{display:grid;gap:12px;align-content:start}\n.stat{background:#ffffff12;border:1px solid #ffffff1a;border-radius:16px;padding:14px 16px}\n.stat .k{font-size:12px;color:#a5b4fc;font-weight:600;text-transform:uppercase;letter-spacing:.06em}\n.stat .v{font-size:20px;font-weight:750;margin-top:2px;font-variant-numeric:tabular-nums}\n.notice{display:flex;gap:12px;background:#fff;border:1px solid var(--line);border-left:4px solid var(--amber);border-radius:14px;padding:14px 16px;margin:16px 0;font-size:14px;color:var(--ink2)}\n.notice b{color:var(--ink)}\ndetails.card,.card{background:var(--card);border:1px solid var(--line);border-radius:var(--r);margin:12px 0;overflow:hidden}\ndetails.card>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:12px;padding:18px 20px;min-height:60px}\ndetails.card>summary::-webkit-details-marker{display:none}\nsummary .ttl,.card h2{font-size:17px;font-weight:750;flex:1;margin:0}\nsummary .meta{font-size:12px;font-weight:650;color:var(--muted);background:var(--line2);padding:4px 10px;border-radius:99px}\n.chev{width:20px;height:20px;transition:transform .2s;color:var(--muted);flex:none}\ndetails[open]>summary .chev{transform:rotate(180deg)}\n.body{padding:4px 20px 20px;border-top:1px solid var(--line2)}\n.rows{display:grid;grid-template-columns:1fr 1fr;column-gap:32px}\n.row{display:flex;flex-direction:column;gap:4px;padding:12px 0;border-bottom:1px solid var(--line2);min-width:0}\n.row.long{grid-column:1/-1}\n.lab{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--muted)}\n.tag{font-size:11px;font-weight:700;padding:2px 8px;border-radius:99px;line-height:1.5;white-space:nowrap}\n.tag.v{color:var(--amber);background:var(--amber-soft)}.tag.ok{color:var(--green);background:var(--green-soft)}.tag.bad{color:var(--red);background:var(--red-soft)}.tag.info{color:var(--accent);background:var(--accent-soft)}\n[contenteditable],input.in,select.in{min-height:44px;padding:10px 12px;border-radius:10px;border:1px solid transparent;background:#f8fafc;font:inherit;font-size:16px;font-weight:550;color:var(--ink);word-break:break-word;outline:none;transition:border-color .15s,background .15s;width:100%}\n[contenteditable]:hover,input.in:hover,select.in:hover{border-color:var(--line)}\n[contenteditable]:focus,input.in:focus,select.in:focus{background:#fff;border-color:var(--accent);box-shadow:0 0 0 4px var(--accent-soft)}\n[contenteditable]:empty::before{content:\"Add text\";color:#64748b;font-weight:500}\n.hint{font-size:13px;color:var(--muted);margin:12px 0 4px}\n.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:650}\n.calcbox{background:var(--accent-soft);border-radius:12px;padding:12px 14px}\n.calcbox .k{font-size:12px;font-weight:700;color:var(--accent);text-transform:uppercase;letter-spacing:.05em}\n.big2{font-size:28px;font-weight:850;letter-spacing:-.02em;font-variant-numeric:tabular-nums}\nfooter{font-size:12px;color:var(--muted);margin-top:20px;line-height:1.6}\n.dock{display:none}\n@media (max-width:899px){\n .wrap{padding:14px 14px 110px}.top .actions{display:none}\n .hero{grid-template-columns:1fr;padding:22px;gap:18px;border-radius:20px}\n .stats{grid-template-columns:1fr 1fr}.stat{padding:12px}.stat .v{font-size:17px}\n .rows{grid-template-columns:1fr}\n details.card>summary{padding:16px}.body{padding:4px 16px 16px}\n .dock{display:flex;gap:8px;position:fixed;left:0;right:0;bottom:0;z-index:20;padding:10px 12px calc(10px + env(safe-area-inset-bottom));background:#ffffffe6;backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border-top:1px solid var(--line)}\n .dock .btn{flex:1;padding:0 8px;font-size:14px}\n}\n@media (max-width:360px){.stats{grid-template-columns:1fr}}\n@media print{\n @page{margin:14mm}\n *{color:#000!important;background:#fff!important;box-shadow:none!important}\n body{font:11pt/1.35 \"Helvetica Neue\",Arial,sans-serif}\n .top .actions,.dock,.noprint,.chev,summary .meta{display:none!important}\n .wrap{padding:0;max-width:none}\n .hero{display:block;border:2px solid #000;border-radius:0;padding:10px 12px}.val{font-size:24pt;margin-top:6px}\n .stats{display:flex;gap:8px;margin-top:8px;flex-wrap:wrap}.stat{border:1px solid #000;border-radius:0;flex:1;padding:6px}\n .notice,details.card,.card{border:1px solid #000;border-radius:0;margin:8px 0}\n details.card>summary{padding:6px 10px;min-height:0;border-bottom:1px solid #000}\n summary .ttl,.card h2{font-size:11pt;text-transform:uppercase;letter-spacing:.05em}\n .body{padding:0 10px 6px;border:0}\n [contenteditable],input.in,select.in{min-height:0;padding:0;border:0;font-size:10pt;font-weight:400}\n .tag{border:1px solid #000}\n}\n\n.hero [contenteditable]{background:transparent;color:#fff;padding:2px 6px;margin-left:-6px;min-height:0;font-size:inherit;font-weight:inherit;border:1px dashed transparent}.hero [contenteditable]:hover{border-color:#ffffff40}.hero [contenteditable]:focus{background:#ffffff14;border-color:#a5b4fc;box-shadow:none}.hero h1 [contenteditable]{display:inline-block;color:#e0e7ff}\n.chips{display:flex;gap:8px;overflow-x:auto;padding:4px 0 8px;scrollbar-width:none;position:sticky;top:0;z-index:5;background:var(--bg)}\n.chips a{flex:none;text-decoration:none;font-size:13px;font-weight:650;color:var(--ink2);background:#fff;border:1px solid var(--line);border-radius:99px;padding:0 14px;min-height:40px;display:inline-flex;align-items:center}\n.sec{padding:20px}.sec h2{font-size:20px;letter-spacing:-.01em;margin:0 0 4px}.sec .sub{color:var(--muted);font-size:14px;margin:0 0 14px}\n.kpis{display:grid;grid-template-columns:repeat(4,1fr);gap:12px}\n.kpi{background:#f8fafc;border:1px solid var(--line2);border-radius:14px;padding:14px}.kpi .k{font-size:12px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}\n.kpi [contenteditable]{font-size:22px;font-weight:800;background:transparent;padding:4px 0;min-height:36px}\n.tiers{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}\n.tier{border:1px solid var(--line);border-radius:16px;padding:16px;position:relative;cursor:pointer;background:#fff}\n.tier.rec{border:2px solid var(--accent);box-shadow:0 10px 24px -14px #4f46e5}\n.tier .badge{position:absolute;top:-11px;left:14px;background:var(--accent);color:#fff;font-size:11px;font-weight:800;padding:3px 10px;border-radius:99px;display:none}.tier.rec .badge{display:block}\n.tier .nm{font-weight:800;font-size:14px;color:var(--ink2)}.tier [contenteditable].p{font-size:26px;font-weight:850;background:transparent;padding:2px 0}\n.tier .d{font-size:13px;color:var(--muted)}\n.tl{list-style:none;margin:0;padding:0;position:relative}\n.tl li{position:relative;padding:0 0 18px 34px}.tl li::before{content:\"\";position:absolute;left:10px;top:6px;bottom:-6px;width:2px;background:var(--line)}.tl li:last-child::before{display:none}\n.tl li::after{content:\"\";position:absolute;left:3px;top:4px;width:16px;height:16px;border-radius:50%;background:#fff;border:4px solid var(--accent)}\n.tl .wk{font-size:12px;font-weight:800;color:var(--accent);text-transform:uppercase;letter-spacing:.06em}\n.tl [contenteditable]{background:transparent;padding:2px 0;min-height:30px}.tl .t{font-weight:750;font-size:16px}.tl .i{font-size:14px;color:var(--ink2);font-weight:450}\n.quotes{display:grid;grid-template-columns:1fr 1fr;gap:12px}.q{background:#f8fafc;border-radius:14px;padding:16px;border:1px solid var(--line2)}.q [contenteditable]{background:transparent;padding:0}.q .who{font-size:13px;color:var(--muted);font-weight:650;margin-top:6px}\n.netgrid{display:grid;grid-template-columns:1fr 1fr;gap:24px;align-items:start}\n.nline{display:flex;justify-content:space-between;gap:12px;padding:10px 0;border-bottom:1px solid var(--line2);font-size:15px}.nline b{font-variant-numeric:tabular-nums}\n.nline.tot{border-top:2px solid var(--ink);border-bottom:0;font-size:18px;font-weight:850}\n.steps{counter-reset:s;list-style:none;padding:0;margin:0;display:grid;gap:10px}.steps li{counter-increment:s;display:flex;gap:12px;align-items:flex-start}.steps li::before{content:counter(s);flex:none;width:32px;height:32px;border-radius:10px;background:var(--ink);color:#fff;font-weight:800;display:grid;place-items:center}.steps [contenteditable]{flex:1}\n.agent{display:flex;gap:16px;align-items:center;flex-wrap:wrap}.avatar{width:56px;height:56px;border-radius:16px;background:var(--accent);color:#fff;font-weight:900;font-size:22px;display:grid;place-items:center;flex:none}\n.cmp{width:100%;border-collapse:collapse;font-size:14px}.cmp th,.cmp td{padding:10px 8px;border-bottom:1px solid var(--line2);text-align:left}.cmp th{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}\n.cmp [contenteditable]{min-height:36px;padding:6px 8px;font-size:14px}\n.st{font-size:11px;font-weight:800;padding:2px 8px;border-radius:99px;background:var(--line2)}\n@media (max-width:899px){.kpis{grid-template-columns:1fr 1fr}.tiers,.quotes,.netgrid{grid-template-columns:1fr}.sec{padding:16px}\n .cmp thead{display:none}.cmp tr{display:grid;grid-template-columns:1fr 1fr;gap:4px 10px;padding:10px 0;border-bottom:1px solid var(--line2)}.cmp td{border:0;padding:0}.cmp td:first-child{grid-column:1/-1}.cmp td[data-l]::before{content:attr(data-l);display:block;font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase}}\n@media print{.chips{display:none}.sec{break-inside:avoid}.tier.rec{border:2px solid #000}.tier .badge{display:block;border:1px solid #000}.kpi,.q{border:1px solid #000}.steps li::before{border:1px solid #000}.tl li::after{border-color:#000}}\n</style></head><body>\n<div class=\"wrap\">\n <div class=\"top\"><div class=\"brand\"><div class=\"logo\">L</div><span id=\"kind\">Listing Presentation</span></div>\n  <div class=\"actions\"><button class=\"btn\" data-act=\"reset\">Reset edits</button><button class=\"btn primary\" data-act=\"pdf\">Save PDF</button></div></div>\n <header class=\"hero\" id=\"hero\"></header>\n <nav class=\"chips noprint\" id=\"chips\"></nav>\n <main id=\"main\"></main>\n <footer id=\"foot\"></footer>\n</div>\n<nav class=\"dock\" aria-label=\"Actions\"><button class=\"btn\" data-act=\"top\">Top</button><button class=\"btn\" data-act=\"reset\">Reset</button><button class=\"btn primary\" data-act=\"pdf\">Save PDF</button></nav>\n<script id=\"report-data\" type=\"application/json\">\n{\"meta\":{\"reportId\":\"presentation\",\"example\":false,\"generated\":\"\"},\"agent\":{},\"seller\":{\"goals\":[\"\",\"\",\"\"]},\"property\":{},\"market\":{},\"pricing\":{\"recommended\":\"mid\",\"comps\":[{},{},{}]},\"marketing\":[{},{},{},{}],\"proof\":[{},{},{},{}],\"testimonials\":[{},{}],\"net\":{\"listingFeePct\":\"\",\"buyerSidePct\":\"\",\"closingPct\":\"1.5\"},\"nextSteps\":[\"\",\"\",\"\"],\"objections\":[{},{}]}\n</script>\n<script>const esc=s=>String(s==null?'':s).replace(/[&<>\"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;'}[c]));\nconst num=v=>{if(v==null)return NaN;const m=String(v).replace(/[$,\\s%]/g,'').match(/-?\\d*\\.?\\d+/);return m?parseFloat(m[0]):NaN};\nconst money=n=>isFinite(n)?(n<0?'−$':'$')+Math.round(Math.abs(n)).toLocaleString('en-US'):'—';\nconst getP=(o,p)=>p.split('.').reduce((a,k)=>a==null?a:a[k],o);\nfunction setP(o,path,val){const p=path.split('.');for(let i=0;i<p.length-1;i++)o=o[p[i]]=o[p[i]]||(isFinite(+p[i+1])?[]:{});o[p[p.length-1]]=val}\nconst chev='<svg class=\"chev\" viewBox=\"0 0 20 20\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\"><path d=\"M5 8l5 5 5-5\"/></svg>';\nfunction store(key){return{load(){try{return JSON.parse(localStorage.getItem(key))}catch(e){return null}},save(s){try{localStorage.setItem(key,JSON.stringify(s));return true}catch(e){return false}},clear(){try{localStorage.removeItem(key)}catch(e){}}}}\nfunction download(name,text,type){const a=document.createElement('a');a.href=URL.createObjectURL(new Blob([text],{type}));a.download=name;document.body.appendChild(a);a.click();a.remove()}\nconst csvq=v=>'\"'+String(v==null?'':v).replace(/\"/g,'\"\"')+'\"';\n\n(function(){\nconst BASE=JSON.parse(document.getElementById('report-data').textContent);\nconst ST=store('lp:'+(BASE.meta.reportId||'p')+':'+location.pathname);\nlet S=ST.load()||JSON.parse(JSON.stringify(BASE));\nconst ce=(p,cls,ph)=>`<div contenteditable=\"true\" role=\"textbox\" data-path=\"${p}\" class=\"${cls||''}\" spellcheck=\"true\"${ph?` data-ph=\"${esc(ph)}\"`:''}>${esc(getP(S,p))}</div>`;\nfunction render(){\n const A=S.agent||{},P=S.property||{},M=S.market||{},PR=S.pricing||{};\n document.getElementById('hero').innerHTML=`<div><span class=\"pill\">Listing presentation</span>${S.meta.example?' <span class=\"pill ex\">EXAMPLE DATA · fictional</span>':''}\n  <h1>Prepared for ${ce('seller.names','','Seller name')}</h1><div class=\"addr\">${ce('property.address','','Property address')}</div>\n  <div class=\"val\" id=\"hVal\">—</div><div class=\"vallab\">Recommended list price</div><div class=\"range\" id=\"hRange\"></div></div>\n  <div class=\"stats\"><div class=\"stat\"><div class=\"k\">Est. net to you</div><div class=\"v\" id=\"hNet\">—</div></div>\n  <div class=\"stat\"><div class=\"k\">Area days on market</div><div class=\"v\" id=\"hDom\">—</div></div>\n  <div class=\"stat\"><div class=\"k\">Sale-to-list</div><div class=\"v\" id=\"hStl\">—</div></div>\n  <div class=\"stat\"><div class=\"k\">Target move date</div><div class=\"v\" id=\"hMove\">—</div></div></div>`;\n const secs=[['goals','Your goals'],['market','Market'],['pricing','Pricing'],['marketing','Marketing plan'],['proof','Why us'],['net','Your net'],['next','Next steps'],['faq','Questions']];\n document.getElementById('chips').innerHTML=secs.map(([i,t])=>`<a href=\"#s-${i}\">${t}</a>`).join('');\n let h='';\n h+=`<section class=\"card sec\" id=\"s-goals\"><h2>What matters to you</h2><p class=\"sub\">From our conversation. Edit anything that isn't right.</p><ol class=\"steps\">${(S.seller.goals||[]).map((g,i)=>`<li>${ce('seller.goals.'+i,'','Goal')}</li>`).join('')}</ol>\n  <div class=\"rows\" style=\"margin-top:8px\"><div class=\"row\"><div class=\"lab\">Move by</div>${ce('seller.moveBy')}</div><div class=\"row\"><div class=\"lab\">Home highlights</div>${ce('property.highlights')}</div></div></section>`;\n h+=`<section class=\"card sec\" id=\"s-market\"><h2>Your market right now</h2><p class=\"sub\">Source: ${ce('market.source','','MLS export, date')}</p><div class=\"kpis\">\n  ${[['medianPrice','Median sold price'],['dom','Median days on market'],['monthsSupply','Months of supply'],['saleToList','Sale-to-list ratio']].map(([k,l])=>`<div class=\"kpi\"><div class=\"k\">${l}</div>${ce('market.'+k)}</div>`).join('')}</div>\n  <table class=\"cmp\" style=\"margin-top:14px\"><thead><tr><th>Comparable</th><th>Status</th><th>Price</th><th>Sq ft</th><th>DOM</th></tr></thead><tbody>\n  ${(PR.comps||[]).map((c,i)=>`<tr><td>${ce('pricing.comps.'+i+'.address','','Address')}</td><td data-l=\"Status\">${ce('pricing.comps.'+i+'.status')}</td><td data-l=\"Price\">${ce('pricing.comps.'+i+'.price')}</td><td data-l=\"Sq ft\">${ce('pricing.comps.'+i+'.sqft')}</td><td data-l=\"DOM\">${ce('pricing.comps.'+i+'.dom')}</td></tr>`).join('')}</tbody></table></section>`;\n const tiers=[['high','Aspirational','Tests the top of the market. Expect fewer showings and a likely price change.'],['mid','Market value','Where comparable homes actually sell. Most buyers, strongest offers.'],['low','Attract multiple offers','Priced to draw a crowd fast. Can create competition.']];\n h+=`<section class=\"card sec\" id=\"s-pricing\"><h2>Pricing strategy</h2><p class=\"sub\">Tap a card to set the recommendation. This is a broker opinion of price, not an appraisal.</p><div class=\"tiers\">\n  ${tiers.map(([k,n,d])=>`<div class=\"tier ${PR.recommended===k?'rec':''}\" data-tier=\"${k}\"><span class=\"badge\">Recommended</span><div class=\"nm\">${n}</div>${ce('pricing.'+k,'p','$')}<div class=\"d\">${d}</div></div>`).join('')}</div>\n  <div class=\"row long\"><div class=\"lab\">Why this price</div>${ce('pricing.rationale')}</div></section>`;\n h+=`<section class=\"card sec\" id=\"s-marketing\"><h2>How we'll sell it</h2><p class=\"sub\">Week-by-week launch plan.</p><ol class=\"tl\">${(S.marketing||[]).map((m,i)=>`<li><div class=\"wk\">${ce('marketing.'+i+'.week','','Week')}</div>${ce('marketing.'+i+'.title','t','Step')}${ce('marketing.'+i+'.items','i','Details')}</li>`).join('')}</ol></section>`;\n h+=`<section class=\"card sec\" id=\"s-proof\"><h2>Why ${esc(A.brokerage||'us')}</h2><p class=\"sub\">Only real, verifiable numbers. Replace any placeholders.</p><div class=\"kpis\">${(S.proof||[]).map((p,i)=>`<div class=\"kpi\"><div class=\"k\">${ce('proof.'+i+'.k','','Label')}</div>${ce('proof.'+i+'.v','','Value')}</div>`).join('')}</div>\n  <div class=\"quotes\" style=\"margin-top:12px\">${(S.testimonials||[]).map((t,i)=>`<div class=\"q\">${ce('testimonials.'+i+'.quote','','Client quote')}<div class=\"who\">${ce('testimonials.'+i+'.who','','Client, year')}</div></div>`).join('')}</div>\n  <div class=\"agent\" style=\"margin-top:16px\"><div class=\"avatar\" id=\"av\">A</div><div style=\"flex:1;min-width:200px\">${ce('agent.name','','Agent name')}${ce('agent.tagline','','Tagline')}</div><div style=\"min-width:200px\">${ce('agent.brokerage','','Brokerage')}${ce('agent.license','','License #')}${ce('agent.phone','','Phone')}${ce('agent.email','','Email')}</div></div></section>`;\n h+=`<section class=\"card sec\" id=\"s-net\"><h2>What you could walk away with</h2><p class=\"sub\">Estimate only. Your title or escrow company provides the official figures.</p><div class=\"netgrid\"><div class=\"rows\" style=\"grid-template-columns:1fr\">\n  ${[['price','Sale price $ (defaults to recommended)'],['payoff','Mortgage payoff $'],['listingFeePct','Listing brokerage fee %'],['buyerSidePct','Seller-paid buyer-agent comp / concessions %'],['closingPct','Other closing costs %'],['other','Repairs / credits $']].map(([k,l])=>`<div class=\"row\"><div class=\"lab\">${l}</div>${ce('net.'+k)}</div>`).join('')}</div>\n  <div class=\"calcbox\" style=\"background:#f8fafc\"><div id=\"netLines\"></div><p class=\"hint\">Commissions and fees are not set by law and are fully negotiable. Any payment to a buyer's agent is your decision.</p></div></div></section>`;\n h+=`<section class=\"card sec\" id=\"s-next\"><h2>Next steps</h2><ol class=\"steps\">${(S.nextSteps||[]).map((s,i)=>`<li>${ce('nextSteps.'+i,'','Step')}</li>`).join('')}</ol></section>`;\n h+=`<details class=\"card\" id=\"s-faq\" open><summary><span class=\"ttl\">Your questions, answered</span>${chev}</summary><div class=\"body\">${(S.objections||[]).map((o,i)=>`<div class=\"row long\"><div class=\"lab\">${ce('objections.'+i+'.q','','Question')}</div>${ce('objections.'+i+'.a','','Answer')}</div>`).join('')}</div></details>`;\n document.getElementById('main').innerHTML=h;\n document.getElementById('foot').innerHTML=`${esc(A.brokerage||'')} ${A.license?'· License '+esc(A.license):''} · Pricing is a broker price opinion, not an appraisal. Market data from ${esc(M.source||'the agent\\'s MLS export')}; deemed reliable but not guaranteed. Equal Housing Opportunity.${S.meta.generated?' Prepared '+esc(S.meta.generated)+'.':''} <span id=\"saved\"></span>`;\n calc();\n}\nfunction calc(){\n const PR=S.pricing||{},N=S.net||{},M=S.market||{};const rec=num(PR[PR.recommended]);\n const $=i=>document.getElementById(i);$('hVal').textContent=money(rec);\n const lo=num(PR.low),hi=num(PR.high);$('hRange').textContent=isFinite(lo)&&isFinite(hi)?'Strategy range '+money(lo)+' – '+money(hi):'';\n const price=isFinite(num(N.price))?num(N.price):rec;\n const L=[['Sale price',price],['Mortgage payoff',-(num(N.payoff)||0)],['Listing fee ('+(num(N.listingFeePct)||0)+'%)',-price*(num(N.listingFeePct)||0)/100],['Buyer-side comp / concessions ('+(num(N.buyerSidePct)||0)+'%)',-price*(num(N.buyerSidePct)||0)/100],['Other closing costs ('+(num(N.closingPct)||0)+'%)',-price*(num(N.closingPct)||0)/100],['Repairs / credits',-(num(N.other)||0)]];\n const net=L.reduce((a,b)=>a+(isFinite(b[1])?b[1]:0),0);\n $('netLines').innerHTML=L.map(([l,v])=>`<div class=\"nline\"><span>${esc(l)}</span><b>${money(v)}</b></div>`).join('')+`<div class=\"nline tot\"><span>Estimated net</span><b id=\"netTot\">${isFinite(price)?money(net):'—'}</b></div>`;\n $('hNet').textContent=isFinite(price)?money(net):'—';$('hDom').textContent=M.dom||'—';$('hStl').textContent=M.saleToList||'—';$('hMove').textContent=(S.seller||{}).moveBy||'—';\n $('av').textContent=((S.agent||{}).name||'A').trim().charAt(0).toUpperCase();\n}\nlet t;function save(){clearTimeout(t);t=setTimeout(()=>{const ok=ST.save(S);const el=document.getElementById('saved');if(el)el.textContent=ok?'Autosaved '+new Date().toLocaleTimeString():'Autosave unavailable'},300)}\ndocument.addEventListener('input',e=>{const el=e.target.closest('[data-path]');if(!el)return;setP(S,el.dataset.path,el.innerText.trim());calc();save()});\ndocument.addEventListener('click',e=>{const tr=e.target.closest('[data-tier]');if(tr&&!e.target.closest('[contenteditable]')){S.pricing.recommended=tr.dataset.tier;document.querySelectorAll('.tier').forEach(x=>x.classList.toggle('rec',x===tr));calc();save();return}\n const b=e.target.closest('[data-act]');if(!b)return;const a=b.dataset.act;\n if(a==='pdf')window.print();if(a==='top')scrollTo({top:0,behavior:'smooth'});\n if(a==='reset'&&confirm('Discard your edits and restore the original?')){ST.clear();S=JSON.parse(JSON.stringify(BASE));render()}});\nwindow.addEventListener('beforeprint',()=>document.querySelectorAll('details').forEach(d=>d.open=true));\nwindow.__doc={get state(){return S},calc};render();\n})();\n</script></body></html>\n"
    }
  ]
}