Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>Grant Workbench Demo</title> | |
| <style> | |
| :root { | |
| --ink: #1b2426; | |
| --muted: #5a666a; | |
| --line: #d8dfdd; | |
| --paper: #fbfbf7; | |
| --panel: #ffffff; | |
| --green: #256f5d; | |
| --green-soft: #e8f4ef; | |
| --yellow: #a96f16; | |
| --yellow-soft: #fff4db; | |
| --red: #9a3535; | |
| --red-soft: #fdeceb; | |
| --black: #17191a; | |
| --blue: #2f5f89; | |
| --blue-soft: #e9f1f8; | |
| --steel: #425667; | |
| --steel-soft: #edf2f5; | |
| --violet: #66527a; | |
| --violet-soft: #f2eef7; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| background: var(--paper); | |
| color: var(--ink); | |
| font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; | |
| line-height: 1.45; | |
| } | |
| a { color: #174f47; font-weight: 800; } | |
| header { | |
| background: #edf3f0; | |
| border-bottom: 1px solid var(--line); | |
| } | |
| .wrap { | |
| width: min(1180px, calc(100vw - 32px)); | |
| margin: 0 auto; | |
| } | |
| .hero { | |
| min-height: 520px; | |
| display: grid; | |
| grid-template-columns: minmax(0, 1.08fr) minmax(360px, 0.92fr); | |
| gap: 30px; | |
| align-items: center; | |
| padding: 44px 0 38px; | |
| } | |
| .eyebrow { | |
| color: #174f47; | |
| font-size: 0.82rem; | |
| font-weight: 850; | |
| letter-spacing: 0; | |
| text-transform: uppercase; | |
| } | |
| h1 { | |
| margin: 10px 0 16px; | |
| font-size: clamp(2.4rem, 5vw, 4.9rem); | |
| line-height: 0.96; | |
| letter-spacing: 0; | |
| max-width: 860px; | |
| } | |
| h2 { margin: 0 0 14px; font-size: 1.48rem; letter-spacing: 0; } | |
| h3 { margin: 0 0 8px; font-size: 1rem; letter-spacing: 0; } | |
| p { margin: 0 0 14px; color: var(--muted); } | |
| .lead { font-size: 1.08rem; max-width: 760px; color: #344044; } | |
| .decision-strip { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 10px; | |
| margin: 24px 0 4px; | |
| } | |
| .decision-item { | |
| min-height: 96px; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: rgba(255, 255, 255, 0.76); | |
| padding: 12px; | |
| } | |
| .decision-item span { | |
| display: block; | |
| color: var(--muted); | |
| font-size: 0.76rem; | |
| font-weight: 850; | |
| text-transform: uppercase; | |
| } | |
| .decision-item strong { | |
| display: block; | |
| margin-top: 6px; | |
| font-size: 1.08rem; | |
| line-height: 1.12; | |
| } | |
| .notice { | |
| display: grid; | |
| gap: 8px; | |
| background: #fff8e8; | |
| border: 1px solid #ead5ad; | |
| border-left: 6px solid var(--yellow); | |
| padding: 16px 18px; | |
| border-radius: 8px; | |
| margin-top: 22px; | |
| color: #3b3428; | |
| } | |
| .demo-explainer { | |
| background: #ffffff; | |
| border: 1px solid var(--line); | |
| border-left: 6px solid var(--green); | |
| border-radius: 8px; | |
| padding: 20px; | |
| } | |
| .demo-explainer .demo-copy { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) minmax(280px, 0.68fr); | |
| gap: 18px; | |
| align-items: start; | |
| } | |
| .demo-explainer strong { color: var(--ink); } | |
| .demo-explainer ul { | |
| margin: 0; | |
| padding-left: 20px; | |
| color: var(--muted); | |
| } | |
| .demo-explainer li { margin: 0 0 8px; } | |
| .panel { | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| padding: 18px; | |
| } | |
| .context-panel { | |
| align-self: stretch; | |
| display: grid; | |
| align-content: center; | |
| gap: 16px; | |
| } | |
| .org-form { | |
| display: grid; | |
| gap: 12px; | |
| } | |
| label { | |
| display: grid; | |
| gap: 5px; | |
| color: #293437; | |
| font-size: 0.84rem; | |
| font-weight: 800; | |
| } | |
| input, select, textarea, button, .button { | |
| min-height: 42px; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| padding: 9px 12px; | |
| font: inherit; | |
| background: #fff; | |
| color: var(--ink); | |
| } | |
| textarea { min-height: 82px; resize: vertical; } | |
| button, .button { | |
| cursor: pointer; | |
| background: #277466; | |
| color: #fff; | |
| border-color: #277466; | |
| font-weight: 850; | |
| text-decoration: none; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| .secondary, .button.secondary { | |
| background: #fff; | |
| color: #174f47; | |
| border-color: #b8cbc6; | |
| } | |
| .dark { | |
| background: var(--black); | |
| border-color: var(--black); | |
| color: #fff; | |
| } | |
| nav { | |
| position: sticky; | |
| top: 0; | |
| z-index: 5; | |
| background: rgba(251, 251, 247, 0.96); | |
| border-bottom: 1px solid var(--line); | |
| backdrop-filter: blur(8px); | |
| } | |
| nav .wrap { | |
| display: flex; | |
| gap: 8px; | |
| align-items: center; | |
| padding: 10px 0; | |
| overflow-x: auto; | |
| } | |
| nav a { | |
| text-decoration: none; | |
| color: var(--ink); | |
| border: 1px solid var(--line); | |
| background: #fff; | |
| border-radius: 999px; | |
| padding: 8px 12px; | |
| white-space: nowrap; | |
| font-size: 0.88rem; | |
| } | |
| nav a:hover, nav a:focus-visible { border-color: #8eb3aa; outline: none; } | |
| main { padding: 28px 0 54px; } | |
| .section { | |
| padding: 26px 0; | |
| border-bottom: 1px solid var(--line); | |
| } | |
| .section-head { | |
| display: grid; | |
| grid-template-columns: minmax(0, 0.72fr) minmax(280px, 0.28fr); | |
| gap: 20px; | |
| align-items: end; | |
| margin-bottom: 14px; | |
| } | |
| .section-head p { margin-bottom: 0; } | |
| .section-kicker { | |
| color: #174f47; | |
| font-size: 0.76rem; | |
| font-weight: 850; | |
| text-transform: uppercase; | |
| } | |
| .grid-4 { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 12px; | |
| } | |
| .grid-3 { | |
| display: grid; | |
| grid-template-columns: repeat(3, minmax(0, 1fr)); | |
| gap: 16px; | |
| } | |
| .grid-2 { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 16px; | |
| } | |
| .card { | |
| background: var(--panel); | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| padding: 16px; | |
| } | |
| .step { | |
| border-left: 5px solid #b8cbc6; | |
| min-height: 128px; | |
| } | |
| .step.active { border-left-color: #277466; } | |
| .step.done { border-left-color: var(--green); background: #fbfffd; } | |
| .status-row { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| margin-top: 10px; | |
| } | |
| .pill { | |
| border: 1px solid var(--line); | |
| border-radius: 999px; | |
| background: #f8faf9; | |
| color: #344044; | |
| padding: 5px 9px; | |
| font-size: 0.78rem; | |
| font-weight: 800; | |
| white-space: nowrap; | |
| } | |
| .legend { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 10px; | |
| margin-top: 14px; | |
| } | |
| .legend .pill { border-radius: 8px; padding: 10px; white-space: normal; } | |
| .green { background: var(--green-soft); border-color: #a7d1c4; color: #174f47; } | |
| .yellow { background: var(--yellow-soft); border-color: #e6ca8c; color: #6b4611; } | |
| .red { background: var(--red-soft); border-color: #e5b9b7; color: #793131; } | |
| .lock { background: #eceeef; border-color: #b7bcbe; color: var(--black); } | |
| .blue { background: var(--blue-soft); border-color: #bfd3e4; color: #214966; } | |
| .steel { background: var(--steel-soft); border-color: #c8d2d9; color: #2f3f4c; } | |
| .violet { background: var(--violet-soft); border-color: #d8cce5; color: #51415f; } | |
| .source-grid, .question-grid, .packet-grid, .lock-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 12px; | |
| margin-top: 14px; | |
| } | |
| .source-card { | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: #fff; | |
| padding: 13px; | |
| } | |
| .source-card strong { display: block; margin-bottom: 4px; } | |
| .field-value { color: var(--ink); font-weight: 750; } | |
| .field-source { color: var(--muted); font-size: 0.84rem; } | |
| .toolbar { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| align-items: center; | |
| margin-top: 14px; | |
| } | |
| .quality-grid { | |
| display: grid; | |
| grid-template-columns: repeat(3, minmax(0, 1fr)); | |
| gap: 10px; | |
| margin-top: 14px; | |
| } | |
| .quality-item { | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: #fff; | |
| padding: 12px; | |
| min-height: 92px; | |
| } | |
| .quality-item span { | |
| display: block; | |
| color: var(--muted); | |
| font-size: 0.76rem; | |
| font-weight: 850; | |
| text-transform: uppercase; | |
| } | |
| .quality-item strong { | |
| display: block; | |
| margin-top: 6px; | |
| line-height: 1.2; | |
| } | |
| .metrics { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 10px; | |
| } | |
| .metric { | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: #f7faf8; | |
| padding: 12px; | |
| min-height: 86px; | |
| } | |
| .metric span { | |
| display: block; | |
| color: var(--muted); | |
| font-size: 0.78rem; | |
| font-weight: 800; | |
| } | |
| .metric strong { | |
| display: block; | |
| font-size: 1.55rem; | |
| margin-top: 4px; | |
| } | |
| .grant-board { | |
| display: grid; | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| gap: 12px; | |
| margin-top: 14px; | |
| } | |
| .grant-card { | |
| display: grid; | |
| gap: 10px; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: #fff; | |
| padding: 14px; | |
| min-height: 264px; | |
| } | |
| .grant-meta { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: 8px; | |
| } | |
| .grant-meta span { | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| background: #f8faf9; | |
| padding: 8px; | |
| color: var(--muted); | |
| font-size: 0.78rem; | |
| font-weight: 800; | |
| } | |
| .grant-meta strong { | |
| display: block; | |
| color: var(--ink); | |
| font-size: 0.92rem; | |
| margin-top: 2px; | |
| } | |
| .grant-next { | |
| border-top: 1px solid var(--line); | |
| padding-top: 10px; | |
| margin-top: auto; | |
| } | |
| .status-line { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| align-items: center; | |
| margin-top: 6px; | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| background: #fff; | |
| border: 1px solid var(--line); | |
| border-radius: 8px; | |
| overflow: hidden; | |
| } | |
| th, td { | |
| text-align: left; | |
| vertical-align: top; | |
| border-bottom: 1px solid var(--line); | |
| padding: 11px 12px; | |
| font-size: 0.91rem; | |
| } | |
| th { | |
| background: #eef5f1; | |
| color: #1f3935; | |
| font-size: 0.78rem; | |
| text-transform: uppercase; | |
| letter-spacing: 0; | |
| } | |
| tbody tr:last-child td { border-bottom: 0; } | |
| .caveat { | |
| background: #f4f0fb; | |
| border: 1px solid #d9cfee; | |
| border-left: 6px solid var(--blue); | |
| border-radius: 8px; | |
| padding: 16px; | |
| color: #313a46; | |
| } | |
| .data-note { | |
| border-left: 5px solid var(--steel); | |
| background: #fff; | |
| border-top: 1px solid var(--line); | |
| border-right: 1px solid var(--line); | |
| border-bottom: 1px solid var(--line); | |
| border-radius: 8px; | |
| padding: 14px 16px; | |
| } | |
| .hidden { display: none; } | |
| footer { | |
| padding: 26px 0 40px; | |
| color: var(--muted); | |
| font-size: 0.88rem; | |
| } | |
| @media (max-width: 920px) { | |
| .hero { grid-template-columns: 1fr; min-height: auto; } | |
| .grid-4, .grid-3, .grid-2, .source-grid, .question-grid, .packet-grid, .lock-grid, .decision-strip, .section-head, .quality-grid, .grant-board, .demo-explainer .demo-copy { grid-template-columns: 1fr; } | |
| .legend { grid-template-columns: 1fr 1fr; } | |
| } | |
| @media (max-width: 540px) { | |
| .wrap { width: min(calc(100vw - 22px), 1180px); } | |
| h1 { font-size: 2.35rem; } | |
| .metrics, .legend { grid-template-columns: 1fr; } | |
| .card, .source-card, .grant-card, .quality-item, .decision-item { min-width: 0; overflow-wrap: anywhere; } | |
| .card .pill, .source-card .pill, .grant-card .pill, .legend .pill { white-space: normal; } | |
| .toolbar button, .toolbar .button { width: 100%; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="wrap hero"> | |
| <div> | |
| <div class="eyebrow">Grant workbench demo</div> | |
| <h1>Grant Workbench Demo</h1> | |
| <p class="lead">A compact path from organization facts to grant-fit review, missing human answers, draft packet fields, and locked final approvals.</p> | |
| <p class="lead"><strong>Output:</strong> a grant shortlist, fit notes, missing-question checklist, draft-safe answer bank, and source links.</p> | |
| <div class="decision-strip" aria-label="Demo state summary"> | |
| <div class="decision-item"><span>Demo profile</span><strong>Cedar Ridge Heritage Museum is made up for this demo</strong></div> | |
| <div class="decision-item"><span>Grant universe</span><strong>1,912 rows, official-source links preserved</strong></div> | |
| <div class="decision-item"><span>Human input</span><strong>4 missing/private facts stay explicit</strong></div> | |
| <div class="decision-item"><span>Final authority</span><strong>Certification and submission remain locked</strong></div> | |
| </div> | |
| <div class="notice" role="note"> | |
| <strong>Demo profile. Not submitted. Not legal/financial advice.</strong> | |
| <span>Verify all funder details before acting. Built as a showcase for how I help small museums/nonprofits. This static Space does not run real public lookup, IRS lookup, SAM lookup, scraping, API calls, or user-entered organization processing.</span> | |
| </div> | |
| <div class="legend" aria-label="Field status legend"> | |
| <span class="pill green">Green = found from reliable source</span> | |
| <span class="pill yellow">Yellow = inferred draft, confirm it</span> | |
| <span class="pill red">Red = missing/private fact</span> | |
| <span class="pill lock">Black lock = human-only certification/signature/submission</span> | |
| </div> | |
| </div> | |
| <aside class="panel context-panel" aria-label="Start organization form"> | |
| <h2>Start with an organization</h2> | |
| <p id="nextActionText">Next recommended action: build the made-up Cedar Ridge demo profile, then review grant fit before preparing a packet.</p> | |
| <div class="org-form"> | |
| <label>Made-up demo organization | |
| <input id="orgName" value="Cedar Ridge Heritage Museum"> | |
| </label> | |
| <label>Website | |
| <input id="orgWebsite" value="https://cedar-ridge-heritage.example"> | |
| </label> | |
| <label>State | |
| <select id="orgState"> | |
| <option value="OR" selected>OR</option> | |
| <option value="CA">CA</option> | |
| <option value="MA">MA</option> | |
| <option value="NY">NY</option> | |
| <option value="VT">VT</option> | |
| </select> | |
| </label> | |
| <button id="buildProfileBtn" type="button">Build demo profile</button> | |
| </div> | |
| </aside> | |
| </div> | |
| </header> | |
| <nav aria-label="Page sections"> | |
| <div class="wrap"> | |
| <a href="#what-this-demo-is">Demo vs Full Stack</a> | |
| <a href="#flow">Flow</a> | |
| <a href="#profile">Profile</a> | |
| <a href="#missing">Missing Questions</a> | |
| <a href="#fit-review">Fit Review</a> | |
| <a href="#packet">Packet Preview</a> | |
| <a href="#all-grants">Search All Grants</a> | |
| </div> | |
| </nav> | |
| <main class="wrap"> | |
| <section id="what-this-demo-is" class="section"> | |
| <article class="demo-explainer"> | |
| <h2>This Is A Demo, Not The Full Workbench</h2> | |
| <div class="demo-copy"> | |
| <div> | |
| <p><strong>This posted page is only a demo of the grant workbench.</strong> The grant listings and source links attached here are real, but this public page mostly shows the discovery and workflow preview layer.</p> | |
| <p>The full grant workbench is meant to take an organization's basic information, project details, budget notes, documents, past application language, and grant instructions, then turn that material into a guided application plan.</p> | |
| <p>In the full stack, the workbench can find likely-fit grants, break down what each application asks for, show what is missing, draft reusable answer blocks, prepare safe form fields where possible, and keep a checklist of what still needs human review.</p> | |
| </div> | |
| <div> | |
| <ul> | |
| <li><strong>Why it saves time:</strong> nonprofits do not have to start from a blank page, hunt through PDFs, or retype the same organization details over and over.</li> | |
| <li><strong>What this demo cannot do:</strong> it does not submit grants, certify anything, guarantee eligibility, or replace official grant instructions.</li> | |
| <li><strong>Important limitation:</strong> the public version is incomplete without the rest of the private stack behind it, so treat it as a preview, not the finished application system.</li> | |
| <li><strong>Need this for your nonprofit?</strong> I can build a grant-fit packet using your real organization details and public grant sources.</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </article> | |
| </section> | |
| <section id="flow" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Progressive disclosure</div> | |
| <h2>Guided Review Flow</h2> | |
| </div> | |
| <p>Each step separates sourced facts, draft assumptions, missing facts, and approvals so the dense grant workflow stays legible.</p> | |
| </div> | |
| <div class="grid-3"> | |
| <article id="stepProfile" class="card step active"> | |
| <h3>1. Build org profile</h3> | |
| <p>Simulate public-source facts and mark confidence by field.</p> | |
| <span class="pill blue">Waiting for demo profile</span> | |
| </article> | |
| <article id="stepQuestions" class="card step"> | |
| <h3>2. Ask only missing facts</h3> | |
| <p>Collect private or certifiable facts the machine should not invent.</p> | |
| <span id="questionReadiness" class="pill red">4 missing questions</span> | |
| </article> | |
| <article id="stepPacket" class="card step"> | |
| <h3>3. Draft packet, lock signoff</h3> | |
| <p>Prepare draft answers, attachments, and human-only approvals.</p> | |
| <span id="packetReadiness" class="pill lock">Human certification locked</span> | |
| </article> | |
| </div> | |
| </section> | |
| <section id="profile" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Evidence layer</div> | |
| <h2>Simulated Public Profile</h2> | |
| </div> | |
| <p>Cedar Ridge Heritage Museum is a made-up organization used only to demonstrate how the Grant Workbench handles an organization profile. A future private/local version can use a real nonprofit's details and real public sources.</p> | |
| </div> | |
| <div id="sourceCards" class="source-grid hidden"></div> | |
| </section> | |
| <section id="missing" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Human-only facts</div> | |
| <h2>Missing Questions</h2> | |
| </div> | |
| <p id="missingIntro">Once the demo profile is built, the system asks only for missing/private facts it cannot certify.</p> | |
| </div> | |
| <div id="questionCards" class="question-grid hidden"></div> | |
| <div class="toolbar"> | |
| <button id="answerQuestionsBtn" type="button" class="secondary">Answer missing questions</button> | |
| <button id="preparePacketBtn" type="button">Prepare packet</button> | |
| </div> | |
| </section> | |
| <section id="fit-review" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Rank before drafting</div> | |
| <h2>Grant Fit Review</h2> | |
| </div> | |
| <p>The sample matches keep money, deadline, readiness, intended use, and next action together so review can happen without flattening the underlying grant data.</p> | |
| </div> | |
| <div class="quality-grid" aria-label="Grant fit signals"> | |
| <div class="quality-item"><span>Best immediate fit</span><strong>Community history microgrant</strong></div> | |
| <div class="quality-item"><span>Main constraint</span><strong>Budget and match facts need human confirmation</strong></div> | |
| <div class="quality-item"><span>Data boundary</span><strong>Fit examples use sample profile data; full database remains separate</strong></div> | |
| </div> | |
| <div id="grantBoard" class="grant-board" aria-live="polite"></div> | |
| </section> | |
| <section id="packet" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Draft surface</div> | |
| <h2>Application Packet Preview</h2> | |
| </div> | |
| <p>Draft-safe fields can be gathered, mapped, and filled. Certification, signatures, and submission stay with a human.</p> | |
| </div> | |
| <div id="packetPanel" class="hidden"> | |
| <div id="packetRows" class="packet-grid"></div> | |
| <h3>Human signoff checklist</h3> | |
| <div id="lockRows" class="lock-grid"></div> | |
| <div class="toolbar"> | |
| <button id="exportPacketBtn" type="button" class="secondary">Export demo packet JSON</button> | |
| <button id="printPacketBtn" type="button" class="dark">Print / Save PDF</button> | |
| </div> | |
| </div> | |
| </section> | |
| <section id="all-grants" class="section"> | |
| <div class="section-head"> | |
| <div> | |
| <div class="section-kicker">Underlying database</div> | |
| <h2>Search All Grants</h2> | |
| </div> | |
| <p>Use the attached database when you need breadth. Use the fit review above when you need a decision-ready shortlist.</p> | |
| </div> | |
| <div class="grid-2"> | |
| <article class="panel"> | |
| <h3>Attached Grant DB</h3> | |
| <div class="metrics"> | |
| <div class="metric"><span>Total rows</span><strong>1,912</strong></div> | |
| <div class="metric"><span>Federal rows</span><strong>1,234</strong></div> | |
| <div class="metric"><span>State sources</span><strong>627</strong></div> | |
| <div class="metric"><span>Due dates</span><strong>769</strong></div> | |
| </div> | |
| <div class="toolbar"> | |
| <a id="grantDatabaseHtmlLink" class="button" href="all_grants_database.html">Open all_grants_database.html</a> | |
| <a id="grantDatabaseCsvLink" class="button secondary" href="all_grants_database.csv" download>Download all_grants_database.csv</a> | |
| </div> | |
| </article> | |
| <article class="data-note"> | |
| <h3>Database caveat</h3> | |
| <p>Federal rows are Grants.gov opportunities. State rows include official grant/funding source pages and portals, not a perfect parse of every individual opportunity for every state.</p> | |
| <div class="status-line"> | |
| <span class="pill blue">Official links retained</span> | |
| <span class="pill yellow">State rows vary by source</span> | |
| <span class="pill red">Verify before acting</span> | |
| </div> | |
| </article> | |
| </div> | |
| <article class="card" style="margin-top:16px"> | |
| <h3>Included real grant data</h3> | |
| <p>The Space includes the real source snapshot behind the demo: the full grant universe, Grants.gov federal rows, state grant source rows, state directory rows, source gaps, summary, and public source receipts with local cache paths removed.</p> | |
| <div class="toolbar"> | |
| <a class="button secondary" href="data/grant_universe.csv" download>Full CSV</a> | |
| <a class="button secondary" href="data/grant_universe.jsonl" download>Full JSONL</a> | |
| <a class="button secondary" href="data/federal_grants_gov_opportunities.csv" download>Federal rows</a> | |
| <a class="button secondary" href="data/state_grant_sources.csv" download>State sources</a> | |
| <a class="button secondary" href="data/source_receipts_public.csv" download>Public receipts</a> | |
| </div> | |
| </article> | |
| </section> | |
| <section id="caveats" class="section"> | |
| <h2>Public Demo Boundaries</h2> | |
| <div class="grid-2"> | |
| <article class="card"> | |
| <h3>What the demo does</h3> | |
| <p>Shows the target interface: org profile, missing questions, grant ranking, draft field map, attachments, export, and human signoff.</p> | |
| </article> | |
| <article class="card"> | |
| <h3>What the demo does not do</h3> | |
| <p>No real organization lookup, no IRS/SAM verification, no real form submission, and no auto-certification.</p> | |
| </article> | |
| </div> | |
| </section> | |
| </main> | |
| <footer class="wrap"> | |
| Generated UTC: 2026-05-14T16:15:14+00:00. Grant DB source snapshot UTC: 2026-05-14T14:03:13+00:00. | |
| </footer> | |
| <script> | |
| const profileFields = [{"label": "Organization name", "value": "Cedar Ridge Heritage Museum", "status": "green", "meaning": "Found from reliable demo source", "source": "Demo profile website profile"}, {"label": "Mission", "value": "Preserve and share Cedar Ridge mill-town history through collections, oral histories, and school programs.", "status": "green", "meaning": "Found from reliable demo source", "source": "Demo profile about page"}, {"label": "Project fit", "value": "Mill Town Memory Lab: oral histories, collections care, free tours, and light gallery stabilization.", "status": "yellow", "meaning": "Inferred draft, confirm before use", "source": "Synthesized from demo project notes"}, {"label": "EIN", "value": "Not shown in public demo", "status": "red", "meaning": "Missing/private fact required from human", "source": "Human must provide or verify privately"}, {"label": "UEI/SAM status", "value": "Not shown in public demo", "status": "red", "meaning": "Missing/private fact required from human", "source": "Human must provide or verify privately"}, {"label": "Certification and signature", "value": "Human-only", "status": "lock", "meaning": "Black lock: certification/signature/submission", "source": "Authorized representative only"}]; | |
| const missingQuestions = [{"id": "project_scope", "question": "Which one project should this packet prepare first?", "hint": "Use one bounded project, not the whole wish list."}, {"id": "budget_confirmed", "question": "What budget total and match amount can leadership certify?", "hint": "Budget documents stay human-confirmed in the public demo."}, {"id": "sam_status", "question": "Is the organization registered in SAM.gov or only planning state/private grants?", "hint": "No SAM lookup runs in this static Space."}, {"id": "board_approval", "question": "Who is authorized to approve and submit the final application?", "hint": "Submission authority is always locked for human signoff."}]; | |
| const packetRows = [{"field": "Applicant name", "draft": "Cedar Ridge Heritage Museum", "status": "green", "note": "Safe to draft from the demo public profile."}, {"field": "Project title", "draft": "Mill Town Memory Lab", "status": "yellow", "note": "Drafted from demo notes; human should confirm final title."}, {"field": "Project summary", "draft": "A draft-safe summary for oral histories, collections care, free school access, and light stabilization.", "status": "yellow", "note": "Useful starting language, not a certified final narrative."}, {"field": "Budget total", "draft": "Needs human-confirmed budget document", "status": "red", "note": "The machine can map numbers, but a person must certify them."}, {"field": "Signature and certifications", "draft": "Locked for authorized representative", "status": "lock", "note": "Never auto-filled or submitted by the public demo."}]; | |
| const certificationLocks = [{"item": "Legal applicant certification", "owner": "Authorized representative", "status": "Black lock"}, {"item": "Budget approval", "owner": "Treasurer or board reviewer", "status": "Black lock"}, {"item": "SAM/UEI attestation if federal", "owner": "Authorized representative", "status": "Black lock"}, {"item": "Final submission", "owner": "Human submitter", "status": "Black lock"}]; | |
| const demoGrants = [{"name": "Cedar Ridge Community History Microgrant", "funder": "Cedar Ridge Community Foundation", "due": "2026-06-12", "status": "Drafting", "amount": "$7,500", "use": "Weekend oral-history recording booth and volunteer transcription stipends.", "next": "Tighten the one-page project summary and attach a board support note."}, {"name": "North Valley Collections Care Fund", "funder": "North Valley Heritage Trust", "due": "2026-07-01", "status": "Ready to verify", "amount": "$18,000", "use": "Archival shelving, rehousing supplies, and a part-time collections technician.", "next": "Confirm current eligibility language and quote expiration dates."}, {"name": "Riverbend Arts Access Program", "funder": "Riverbend Cultural Council", "due": "2026-08-15", "status": "Watchlist", "amount": "$12,000", "use": "Free family history days, bilingual exhibit labels, and school tour materials.", "next": "Decide whether the access budget belongs in this cycle or next cycle."}, {"name": "Old Mill Heritage Capital Match", "funder": "Old Mill Preservation League", "due": "2026-10-30", "status": "Needs match", "amount": "$35,000", "use": "Exterior drainage fixes and visitor entry stabilization for a sample mill gallery.", "next": "Build a match plan and choose which capital items are phase-one only."}]; | |
| const answered = new Set(); | |
| const sourceCards = document.querySelector("#sourceCards"); | |
| const questionCards = document.querySelector("#questionCards"); | |
| const packetPanel = document.querySelector("#packetPanel"); | |
| const packetMount = document.querySelector("#packetRows"); | |
| const lockMount = document.querySelector("#lockRows"); | |
| const grantBoard = document.querySelector("#grantBoard"); | |
| const questionReadiness = document.querySelector("#questionReadiness"); | |
| const packetReadiness = document.querySelector("#packetReadiness"); | |
| const nextActionText = document.querySelector("#nextActionText"); | |
| function statusClass(status) { | |
| if (status === "green") return "green"; | |
| if (status === "yellow") return "yellow"; | |
| if (status === "red") return "red"; | |
| if (status === "lock") return "lock"; | |
| return "blue"; | |
| } | |
| function statusText(status) { | |
| if (status === "green") return "Green: found from reliable source"; | |
| if (status === "yellow") return "Yellow: inferred draft, needs confirmation"; | |
| if (status === "red") return "Red: missing/private fact required"; | |
| if (status === "lock") return "Black lock: human-only certification/signature/submission"; | |
| return status; | |
| } | |
| function makeCard(className, title, body, pill, footer) { | |
| const card = document.createElement("article"); | |
| card.className = className; | |
| const h = document.createElement("h3"); | |
| h.textContent = title; | |
| const p = document.createElement("p"); | |
| p.textContent = body; | |
| const tag = document.createElement("span"); | |
| tag.className = "pill " + pill.className; | |
| tag.textContent = pill.text; | |
| card.appendChild(h); | |
| card.appendChild(p); | |
| card.appendChild(tag); | |
| if (footer) { | |
| const small = document.createElement("p"); | |
| small.className = "field-source"; | |
| small.textContent = footer; | |
| card.appendChild(small); | |
| } | |
| return card; | |
| } | |
| function fitStatusClass(status) { | |
| if (status === "Drafting") return "green"; | |
| if (status === "Ready to verify") return "blue"; | |
| if (status === "Watchlist") return "steel"; | |
| if (status === "Needs match") return "yellow"; | |
| return "violet"; | |
| } | |
| function renderGrantBoard() { | |
| grantBoard.innerHTML = ""; | |
| demoGrants.forEach((grant) => { | |
| const card = document.createElement("article"); | |
| card.className = "grant-card"; | |
| const h = document.createElement("h3"); | |
| h.textContent = grant.name; | |
| const funder = document.createElement("p"); | |
| funder.textContent = grant.funder; | |
| const tag = document.createElement("span"); | |
| tag.className = "pill " + fitStatusClass(grant.status); | |
| tag.textContent = grant.status; | |
| const meta = document.createElement("div"); | |
| meta.className = "grant-meta"; | |
| meta.innerHTML = "<span>Amount<strong>" + grant.amount + "</strong></span>" + | |
| "<span>Due<strong>" + grant.due + "</strong></span>"; | |
| const use = document.createElement("p"); | |
| use.textContent = grant.use; | |
| const next = document.createElement("p"); | |
| next.className = "grant-next"; | |
| next.textContent = "Next action: " + grant.next; | |
| card.appendChild(h); | |
| card.appendChild(funder); | |
| card.appendChild(tag); | |
| card.appendChild(meta); | |
| card.appendChild(use); | |
| card.appendChild(next); | |
| grantBoard.appendChild(card); | |
| }); | |
| } | |
| function buildProfile() { | |
| sourceCards.innerHTML = ""; | |
| profileFields.forEach((field) => { | |
| sourceCards.appendChild(makeCard( | |
| "source-card", | |
| field.label, | |
| field.value, | |
| {className: statusClass(field.status), text: statusText(field.status)}, | |
| field.source | |
| )); | |
| }); | |
| sourceCards.classList.remove("hidden"); | |
| document.querySelector("#stepProfile").classList.add("done"); | |
| document.querySelector("#stepQuestions").classList.add("active"); | |
| nextActionText.textContent = "Next recommended action: answer the missing facts, then check whether the grant shortlist is ready for packet drafting."; | |
| renderQuestions(); | |
| document.querySelector("#profile").scrollIntoView({behavior: "smooth", block: "start"}); | |
| } | |
| function renderQuestions() { | |
| questionCards.innerHTML = ""; | |
| missingQuestions.forEach((item) => { | |
| const card = document.createElement("article"); | |
| card.className = "card"; | |
| const h = document.createElement("h3"); | |
| h.textContent = item.question; | |
| const hint = document.createElement("p"); | |
| hint.textContent = item.hint; | |
| const textarea = document.createElement("textarea"); | |
| textarea.id = "answer_" + item.id; | |
| textarea.placeholder = "Demo answer"; | |
| textarea.addEventListener("input", () => { | |
| if (textarea.value.trim()) answered.add(item.id); | |
| else answered.delete(item.id); | |
| updateReadiness(); | |
| }); | |
| card.appendChild(h); | |
| card.appendChild(hint); | |
| card.appendChild(textarea); | |
| questionCards.appendChild(card); | |
| }); | |
| questionCards.classList.remove("hidden"); | |
| updateReadiness(); | |
| } | |
| function updateReadiness() { | |
| const missing = missingQuestions.length - answered.size; | |
| questionReadiness.textContent = missing === 0 ? "Ready for draft packet" : `${missing} missing/private questions`; | |
| questionReadiness.className = "pill " + (missing === 0 ? "green" : answered.size ? "yellow" : "red"); | |
| } | |
| function answerQuestions() { | |
| missingQuestions.forEach((item, index) => { | |
| const box = document.querySelector("#answer_" + item.id); | |
| if (box && !box.value.trim()) { | |
| box.value = index === 0 ? "Prepare the Mill Town Memory Lab first." : "Demo response for human review."; | |
| answered.add(item.id); | |
| } | |
| }); | |
| document.querySelector("#stepQuestions").classList.add("done"); | |
| updateReadiness(); | |
| nextActionText.textContent = "Next recommended action: prepare the packet and keep final certification locked for a human."; | |
| } | |
| function preparePacket() { | |
| if (sourceCards.classList.contains("hidden")) buildProfile(); | |
| packetMount.innerHTML = ""; | |
| packetRows.forEach((row) => { | |
| packetMount.appendChild(makeCard( | |
| "source-card", | |
| row.field, | |
| row.draft, | |
| {className: statusClass(row.status), text: statusText(row.status)}, | |
| row.note | |
| )); | |
| }); | |
| lockMount.innerHTML = ""; | |
| certificationLocks.forEach((row) => { | |
| lockMount.appendChild(makeCard( | |
| "source-card", | |
| row.item, | |
| row.owner, | |
| {className: "lock", text: row.status}, | |
| "Human approval required" | |
| )); | |
| }); | |
| packetPanel.classList.remove("hidden"); | |
| document.querySelector("#stepPacket").classList.add("active", "done"); | |
| packetReadiness.textContent = "Draft packet prepared, certification locked"; | |
| packetReadiness.className = "pill lock"; | |
| nextActionText.textContent = "Next recommended action: review exported draft fields against funder instructions before any real-world use."; | |
| document.querySelector("#packet").scrollIntoView({behavior: "smooth", block: "start"}); | |
| } | |
| function exportPacket() { | |
| const answers = {}; | |
| missingQuestions.forEach((item) => { | |
| const box = document.querySelector("#answer_" + item.id); | |
| answers[item.id] = box ? box.value.trim() : ""; | |
| }); | |
| const packet = { | |
| exported_utc: new Date().toISOString(), | |
| demo_profile: true, | |
| org_first_flow: true, | |
| no_real_lookup_in_space: true, | |
| organization: document.querySelector("#orgName").value, | |
| website: document.querySelector("#orgWebsite").value, | |
| state: document.querySelector("#orgState").value, | |
| simulated_profile: profileFields, | |
| missing_question_answers: answers, | |
| ranked_demo_grants: demoGrants, | |
| draft_packet_fields: packetRows, | |
| human_only_certification: certificationLocks | |
| }; | |
| const blob = new Blob([JSON.stringify(packet, null, 2)], {type: "application/json"}); | |
| const url = URL.createObjectURL(blob); | |
| const link = document.createElement("a"); | |
| link.href = url; | |
| link.download = "cedar_ridge_org_first_demo_packet.json"; | |
| link.click(); | |
| URL.revokeObjectURL(url); | |
| } | |
| document.querySelector("#buildProfileBtn").addEventListener("click", buildProfile); | |
| document.querySelector("#answerQuestionsBtn").addEventListener("click", answerQuestions); | |
| document.querySelector("#preparePacketBtn").addEventListener("click", preparePacket); | |
| document.querySelector("#exportPacketBtn").addEventListener("click", exportPacket); | |
| document.querySelector("#printPacketBtn").addEventListener("click", () => window.print()); | |
| renderGrantBoard(); | |
| </script> | |
| </body> | |
| </html> | |