Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"/> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/> | |
| <title>PawMap</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css"/> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"/> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,400;0,14..32,500;0,14..32,600;0,14..32,700;1,14..32,400&display=swap" rel="stylesheet"/> | |
| <link rel="stylesheet" href="/static/style.css"/> | |
| <script src="https://cdn.jsdelivr.net/npm/lucide@0.454.0/dist/umd/lucide.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/lottie-web@5.12.2/build/player/lottie.min.js"></script> | |
| </head> | |
| <body> | |
| <div id="desktop-layout"> | |
| <!-- ══ LEFT SIDEBAR (desktop only) ══ --> | |
| <aside id="sidebar-left"> | |
| <div class="sidebar-logo"> | |
| <span class="sidebar-paw">🐾</span> | |
| <span class="sidebar-brand">PawMap</span> | |
| </div> | |
| <p class="sidebar-tagline">Collaborative stray animal mapping, powered by AI.</p> | |
| <div class="sidebar-divider"></div> | |
| <div class="sidebar-section"> | |
| <h3>The problem</h3> | |
| <p>Independent rescuers in Brasília, DF keep track of entire stray animal colonies in their heads — which ones were neutered, which one got hurt last winter, which one hasn't shown up this week. That knowledge lives in WhatsApp groups and fades when people move on.</p> | |
| <p>PawMap turns those scattered sightings into a shared, persistent map — one photo at a time.</p> | |
| </div> | |
| <div class="sidebar-divider"></div> | |
| <div class="sidebar-section"> | |
| <h3>How it works</h3> | |
| <div class="how-steps"> | |
| <div class="how-step"> | |
| <div class="how-num"><i data-lucide="camera"></i></div> | |
| <div class="how-content"> | |
| <strong>Snap a photo</strong> | |
| <span>Point your camera at any stray dog or cat.</span> | |
| </div> | |
| </div> | |
| <div class="how-connector"></div> | |
| <div class="how-step"> | |
| <div class="how-num"><i data-lucide="scan-line"></i></div> | |
| <div class="how-content"> | |
| <strong>AI identifies</strong> | |
| <span>Species, breed, color and condition — automatically.</span> | |
| </div> | |
| </div> | |
| <div class="how-connector"></div> | |
| <div class="how-step"> | |
| <div class="how-num"><i data-lucide="git-merge"></i></div> | |
| <div class="how-content"> | |
| <strong>Smart matching</strong> | |
| <span>Checks if this animal has been seen before.</span> | |
| </div> | |
| </div> | |
| <div class="how-connector"></div> | |
| <div class="how-step"> | |
| <div class="how-num"><i data-lucide="map-pin"></i></div> | |
| <div class="how-content"> | |
| <strong>Map updates</strong> | |
| <span>Sighting linked to the animal's profile — or a new one is created.</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </aside> | |
| <div class="phone-wrap"> | |
| <div class="better-on-mobile"><i data-lucide="smartphone"></i> Better on mobile</div> | |
| <div class="phone-frame"> | |
| <div class="phone-btn phone-btn-vol-up"></div> | |
| <div class="phone-btn phone-btn-vol-down"></div> | |
| <div class="phone-btn phone-btn-power"></div> | |
| <div id="app"> | |
| <!-- ══ ONBOARDING ══ --> | |
| <div id="screen-splash"> | |
| <button id="ob-skip">Skip</button> | |
| <!-- Steps --> | |
| <div id="ob-track"> | |
| <!-- Step 1 --> | |
| <div class="ob-step"> | |
| <div class="ob-lottie-wrap"> | |
| <div id="lottie-1" class="ob-lottie"></div> | |
| <div class="ob-lottie-fallback"><i data-lucide="camera"></i></div> | |
| </div> | |
| <div class="ob-text"> | |
| <div class="ob-step-label">Step 1 of 4</div> | |
| <h2>Help a stray find its way</h2> | |
| <p>Every street dog and cat deserves to be seen. PawMap lets your community map them together — one photo at a time.</p> | |
| </div> | |
| </div> | |
| <!-- Step 2 --> | |
| <div class="ob-step"> | |
| <div class="ob-lottie-wrap"> | |
| <div id="lottie-2" class="ob-lottie"></div> | |
| <div class="ob-lottie-fallback"><i data-lucide="scan-line"></i></div> | |
| </div> | |
| <div class="ob-text"> | |
| <div class="ob-step-label">Step 2 of 4</div> | |
| <h2>Snap a photo — AI does the rest</h2> | |
| <p>Point your camera and tap. Our AI instantly identifies species, breed, color, and condition. No forms to fill.</p> | |
| </div> | |
| </div> | |
| <!-- Step 3 --> | |
| <div class="ob-step"> | |
| <div class="ob-lottie-wrap"> | |
| <div id="lottie-3" class="ob-lottie"></div> | |
| <div class="ob-lottie-fallback"><i data-lucide="refresh-cw"></i></div> | |
| </div> | |
| <div class="ob-text"> | |
| <div class="ob-step-label">Step 3 of 4</div> | |
| <h2>AI matches the same animal</h2> | |
| <p>Seen this dog before? The AI compares your photo with previous sightings and links them automatically — building each animal's story.</p> | |
| </div> | |
| </div> | |
| <!-- Step 4 --> | |
| <div class="ob-step"> | |
| <div class="ob-lottie-wrap"> | |
| <div id="lottie-4" class="ob-lottie"></div> | |
| <div class="ob-lottie-fallback"><i data-lucide="home"></i></div> | |
| </div> | |
| <div class="ob-text"> | |
| <div class="ob-step-label">Step 4 of 4</div> | |
| <h2>Every map pin is a chance</h2> | |
| <p>Mapping a dog brings more chances to find a forever family — or get help from the community when it's needed most.</p> | |
| </div> | |
| </div> | |
| </div><!-- /ob-track --> | |
| <!-- Dots --> | |
| <div id="ob-dots"> | |
| <span class="ob-dot active"></span> | |
| <span class="ob-dot"></span> | |
| <span class="ob-dot"></span> | |
| <span class="ob-dot"></span> | |
| </div> | |
| <!-- Actions --> | |
| <div id="ob-actions"> | |
| <button id="ob-next">Next →</button> | |
| </div> | |
| </div><!-- /screen-splash --> | |
| <!-- ══ HEADER ══ --> | |
| <header id="header"> | |
| <button class="icon-btn" id="menu-btn" aria-label="Menu"> | |
| <svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg> | |
| </button> | |
| <span class="logo">PawMap</span> | |
| <button class="icon-btn" aria-label="Options"> | |
| <svg viewBox="0 0 24 24"><circle cx="12" cy="5" r="1.5" fill="#fff" stroke="none"/><circle cx="12" cy="12" r="1.5" fill="#fff" stroke="none"/><circle cx="12" cy="19" r="1.5" fill="#fff" stroke="none"/></svg> | |
| </button> | |
| </header> | |
| <!-- ══ FILTER ROW ══ --> | |
| <div id="filter-row"> | |
| <button class="chip active" data-species="all">All</button> | |
| <button class="chip" data-species="dog"><i data-lucide="dog"></i> Dogs</button> | |
| <button class="chip" data-species="cat"><i data-lucide="cat"></i> Cats</button> | |
| <button class="chip" data-timeframe="today">Today</button> | |
| <button class="chip" data-timeframe="week">This Week</button> | |
| </div> | |
| <!-- ══ SCREEN: MAP ══ --> | |
| <div id="screen-map" class="screen active"> | |
| <div id="map"></div> | |
| <div id="map-empty">No sightings yet</div> | |
| <div id="sighting-card" class="hidden"> | |
| <div class="card-photo" id="card-photo"><i data-lucide="paw-print"></i></div> | |
| <div class="card-info"> | |
| <div class="card-top"><span class="badge" id="card-badge">Dog</span><span class="card-time" id="card-time"></span></div> | |
| <div class="card-location" id="card-location"></div> | |
| <div class="card-sub" id="card-sub"></div> | |
| </div> | |
| <button class="btn-ficha" id="card-btn">View profile</button> | |
| </div> | |
| </div> | |
| <!-- ══ SCREEN: REGISTER ══ --> | |
| <div id="screen-register" class="screen"> | |
| <input type="file" id="photo-input" accept="image/*"/> | |
| <div id="viewfinder"> | |
| <div id="gps-pill"> | |
| <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> | |
| <span id="gps-text">Tap to detect location</span> | |
| </div> | |
| <img id="photo-preview" src="" alt="photo"/> | |
| <div id="camera-placeholder"> | |
| <svg viewBox="0 0 24 24"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg> | |
| <p>Tap the button to take a photo</p> | |
| </div> | |
| <button id="shutter-btn" aria-label="Take photo"> | |
| <svg viewBox="0 0 24 24"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg> | |
| </button> | |
| </div> | |
| <div id="reg-sheet"> | |
| <div class="drag-handle"></div> | |
| <div id="notes-row"> | |
| <svg viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg> | |
| <textarea id="notes-input" rows="1" placeholder="Add a note (optional)"></textarea> | |
| </div> | |
| <button class="btn-secondary" id="gps-btn"> | |
| <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> | |
| Add Location | |
| </button> | |
| <button class="btn-primary" id="submit-reg-btn" disabled> | |
| <svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg> | |
| Report Sighting | |
| </button> | |
| </div> | |
| </div> | |
| <!-- ══ SCREEN: ANALYSIS ══ --> | |
| <div id="screen-analysis" class="screen"> | |
| <div class="flow-header"> | |
| <button class="back-btn" id="analysis-back"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></button> | |
| <h2>Analyzing Sighting</h2> | |
| </div> | |
| <div id="analysis-photo-wrap"> | |
| <img id="analysis-photo" src="" alt="photo"/> | |
| <div id="ai-badge"><span class="dot"></span><span id="ai-badge-text">AI Analyzing...</span></div> | |
| <div id="animal-result-badge"><svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg><span id="result-badge-text">Caramel Dog</span></div> | |
| </div> | |
| <div class="analysis-card"> | |
| <h3>Identified Details <button id="edit-btn"><i data-lucide="pencil"></i></button></h3> | |
| <p class="subtitle">AI filled in these details. Correct if needed.</p> | |
| <div class="dropdowns-grid"> | |
| <div class="dropdown-field"><label>Species</label><select id="sel-species"><option value="dog">Dog</option><option value="cat">Cat</option></select></div> | |
| <div class="dropdown-field"><label>Breed (Estimated)</label><select id="sel-breed"></select></div> | |
| <div class="dropdown-field"><label>Primary Color</label><select id="sel-color"><option value="Caramelo">Caramel</option><option value="Preto">Black</option><option value="Branco">White</option><option value="Cinza">Gray</option><option value="Marrom">Brown</option><option value="Mesclado">Mixed</option></select></div> | |
| <div class="dropdown-field"><label>Size</label><select id="sel-size"><option value="Pequeno">Small</option><option value="Médio">Medium</option><option value="Grande">Large</option></select></div> | |
| </div> | |
| <div class="condition-label">Condition (Optional)</div> | |
| <div class="condition-chips"> | |
| <button class="cond-chip" data-val="Injured"><span class="check"><i data-lucide="check"></i></span> Injured</button> | |
| <button class="cond-chip" data-val="Looks Healthy"><span class="check"><i data-lucide="check"></i></span> Looks Healthy</button> | |
| <button class="cond-chip" data-val="Has Collar"><span class="check"><i data-lucide="check"></i></span> Has Collar</button> | |
| </div> | |
| </div> | |
| <div class="analysis-card" id="similar-section"> | |
| <h3>Similar animals nearby</h3> | |
| <p class="subtitle">Found by AI for context — recognition is automatic.</p> | |
| <div class="similar-scroll" id="similar-scroll"></div> | |
| </div> | |
| <div class="analysis-card"> | |
| <div class="dropdown-field"> | |
| <label>Name <span class="optional-tag">optional</span></label> | |
| <input type="text" id="animal-name-input" placeholder="e.g. Caputino, Bolinha, Luna…" maxlength="40" autocomplete="off"/> | |
| </div> | |
| </div> | |
| <div id="analysis-actions"> | |
| <button class="btn-primary" id="confirm-btn">Confirm & Report →</button> | |
| <button class="btn-outline" id="discard-btn">Discard Photo</button> | |
| </div> | |
| </div> | |
| <!-- ══ SCREEN: CONFIRM ══ --> | |
| <div id="screen-confirm" class="screen"> | |
| <div id="confirm-inner"> | |
| <div id="confirm-photo-wrap"> | |
| <div id="confirm-photo"><i data-lucide="paw-print"></i></div> | |
| <div id="confirm-check"><svg viewBox="0 0 24 24"><polyline points="20 6 9 20 4 14"/></svg></div> | |
| </div> | |
| <div id="confirm-title">Sighting<br>Reported!</div> | |
| <div id="confirm-card"> | |
| <div class="confirm-row"> | |
| <span class="confirm-row-label"><svg viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>Animal:</span> | |
| <span class="confirm-row-value" id="confirm-animal">—</span> | |
| </div> | |
| <div class="confirm-row"> | |
| <span class="confirm-row-label"><svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg>Location:</span> | |
| <span class="confirm-row-value" id="confirm-local">—</span> | |
| </div> | |
| <div class="confirm-row"> | |
| <span class="confirm-row-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>Time:</span> | |
| <span class="confirm-row-value" id="confirm-hora">—</span> | |
| </div> | |
| </div> | |
| <div id="confirm-id-grid" class="confirm-id-grid"></div> | |
| <div class="confirm-btns"> | |
| <button class="btn-primary" id="register-another-btn"><svg viewBox="0 0 24 24"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg>Report Another</button> | |
| <button class="btn-secondary" id="go-map-btn"><svg viewBox="0 0 24 24"><polygon points="3 6 9 3 15 6 21 3 21 18 15 21 9 18 3 21"/></svg>View on Map</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- ══ SCREEN: SIGHTINGS LIST ══ --> | |
| <div id="screen-sightings" class="screen"> | |
| <div id="sightings-header"> | |
| <span id="sightings-count">Loading...</span> | |
| <button id="refresh-btn" title="Refresh"><i data-lucide="refresh-cw"></i></button> | |
| </div> | |
| <div id="animals-list"></div> | |
| </div> | |
| <!-- ══ SCREEN: PROFILE / FICHA ══ --> | |
| <div id="screen-profile" class="screen"> | |
| <div class="profile-scroll"> | |
| <!-- Hero --> | |
| <div class="profile-hero"> | |
| <img class="profile-hero-img" id="profile-hero-img" src="" alt=""/> | |
| <div class="hero-gradient"></div> | |
| <div class="hero-top-btns"> | |
| <button class="hero-btn" id="profile-back-btn"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></button> | |
| <button class="hero-btn" id="profile-share-btn"><svg viewBox="0 0 24 24"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><line x1="8.59" y1="13.51" x2="15.42" y2="17.49"/><line x1="15.41" y1="6.51" x2="8.59" y2="10.49"/></svg></button> | |
| </div> | |
| <div id="profile-sightings-badge"> | |
| <svg viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg> | |
| <span id="profile-badge-text">0 sightings</span> | |
| </div> | |
| </div> | |
| <!-- Content --> | |
| <div class="profile-content"> | |
| <h1 id="profile-title">...</h1> | |
| <div id="profile-status"><span class="status-dot"></span><span id="profile-status-text">...</span></div> | |
| <div id="profile-helped-banner" style="display:none"> | |
| <i data-lucide="heart"></i> | |
| <span>This animal has been helped by the community</span> | |
| </div> | |
| <div id="profile-ai-desc" class="ai-desc-callout" style="display:none"> | |
| <span class="ai-label">AI</span> | |
| <p id="profile-ai-text"></p> | |
| </div> | |
| <!-- Identification --> | |
| <div class="profile-section"> | |
| <div class="section-title">Identification</div> | |
| <div class="id-grid"> | |
| <div class="id-cell"><div class="id-cell-label">Species</div><div class="id-cell-value" id="prof-species">—</div></div> | |
| <div class="id-cell"><div class="id-cell-label">Breed</div><div class="id-cell-value" id="prof-breed">—</div></div> | |
| <div class="id-cell"><div class="id-cell-label">Size</div><div class="id-cell-value" id="prof-size">—</div></div> | |
| <div class="id-cell"><div class="id-cell-label">Color</div><div class="id-cell-value" id="prof-color">—</div></div> | |
| </div> | |
| </div> | |
| <!-- Gallery --> | |
| <div class="profile-section"> | |
| <div class="gallery-header"> | |
| <div class="section-title" style="margin-bottom:0">Sightings Gallery</div> | |
| <button class="gallery-see-all">See all</button> | |
| </div> | |
| <div class="gallery-scroll" id="profile-gallery"></div> | |
| </div> | |
| <!-- Community Help --> | |
| <div class="profile-section" id="profile-help-section" style="display:none"> | |
| <div class="section-title help-section-title"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="var(--green)" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg> | |
| Community Help | |
| </div> | |
| <div id="profile-help-list"></div> | |
| </div> | |
| <!-- Trajectory --> | |
| <div class="profile-section"> | |
| <div class="section-title">Recent Path</div> | |
| <div id="trajectory-map"></div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Footer --> | |
| <div class="profile-footer"> | |
| <button class="btn-adopt" id="btn-adopt"><i data-lucide="heart"></i> I Want to Adopt / Help</button> | |
| </div> | |
| </div> | |
| <!-- ══ HELP BOTTOM SHEET ══ --> | |
| <div id="help-overlay" class="hidden"></div> | |
| <div id="help-sheet" class="help-sheet hidden"> | |
| <div class="drag-handle"></div> | |
| <div id="help-animal-row"> | |
| <div id="help-animal-photo"></div> | |
| <div id="help-animal-info"> | |
| <div id="help-animal-name">—</div> | |
| <div id="help-animal-sub">—</div> | |
| </div> | |
| </div> | |
| <div class="help-actions"> | |
| <button class="help-action-btn" id="help-share"> | |
| <span class="help-action-icon"><i data-lucide="share-2"></i></span> | |
| <span class="help-action-text"> | |
| <strong>Share this animal</strong> | |
| <small>Send via WhatsApp or copy link</small> | |
| </span> | |
| <svg class="help-chevron" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg> | |
| </button> | |
| <button class="help-action-btn" id="help-directions"> | |
| <span class="help-action-icon"><i data-lucide="map-pin"></i></span> | |
| <span class="help-action-text"> | |
| <strong>Get directions</strong> | |
| <small>Navigate to last known location</small> | |
| </span> | |
| <svg class="help-chevron" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg> | |
| </button> | |
| <button class="help-action-btn" id="help-helped"> | |
| <span class="help-action-icon"><i data-lucide="check-circle"></i></span> | |
| <span class="help-action-text"> | |
| <strong>I helped this animal</strong> | |
| <small>Log that you fed, treated, or fostered them</small> | |
| </span> | |
| <svg class="help-chevron" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg> | |
| </button> | |
| </div> | |
| <button class="help-cancel" id="help-cancel">Cancel</button> | |
| </div> | |
| <!-- ══ HELPED CONFIRM ══ --> | |
| <div id="helped-confirm" class="helped-confirm hidden"> | |
| <div class="helped-inner"> | |
| <div class="helped-icon-wrap"><i data-lucide="heart"></i></div> | |
| <h3>Thank you</h3> | |
| <p>Your help has been recorded.<br>Every act of care makes a difference.</p> | |
| <button id="helped-ok">Done</button> | |
| </div> | |
| </div> | |
| <!-- ══ SCREEN: HELP PROOF ══ --> | |
| <div id="screen-help-proof" class="screen"> | |
| <div class="flow-header"> | |
| <button class="back-btn" id="help-proof-back"><svg viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg></button> | |
| <h2>I Helped This Animal</h2> | |
| </div> | |
| <div id="help-proof-animal-row"> | |
| <div id="help-proof-animal-photo" class="help-proof-thumb"></div> | |
| <div> | |
| <div id="help-proof-animal-name" class="help-proof-animal-name">—</div> | |
| <div id="help-proof-animal-sub" class="help-proof-animal-sub">—</div> | |
| </div> | |
| </div> | |
| <div class="help-proof-section"> | |
| <div class="help-proof-label">What did you do?</div> | |
| <div class="help-type-chips" id="help-type-chips"> | |
| <button class="help-type-chip active" data-type="fed"><i data-lucide="utensils"></i> Fed</button> | |
| <button class="help-type-chip" data-type="vet"><i data-lucide="stethoscope"></i> Took to vet</button> | |
| <button class="help-type-chip" data-type="adopted"><i data-lucide="home"></i> Adopted</button> | |
| <button class="help-type-chip" data-type="rescued"><i data-lucide="shield-check"></i> Rescued</button> | |
| <button class="help-type-chip" data-type="other"><i data-lucide="heart"></i> Other</button> | |
| </div> | |
| </div> | |
| <div class="help-proof-section"> | |
| <div class="help-proof-label">Add a photo <span class="optional-tag">optional</span></div> | |
| <div id="help-proof-viewfinder" class="help-proof-viewfinder"> | |
| <input type="file" id="help-proof-input" accept="image/*"/> | |
| <img id="help-proof-preview" src="" alt="" class="hidden"/> | |
| <div id="help-proof-placeholder"> | |
| <svg viewBox="0 0 24 24"><path d="M23 19a2 2 0 01-2 2H3a2 2 0 01-2-2V8a2 2 0 012-2h4l2-3h6l2 3h4a2 2 0 012 2z"/><circle cx="12" cy="13" r="4"/></svg> | |
| <span>Tap to add photo proof</span> | |
| </div> | |
| <div id="help-proof-ai-badge" class="help-proof-ai-badge hidden"> | |
| <span class="dot"></span><span id="help-proof-ai-text">Verifying with AI…</span> | |
| </div> | |
| <div id="help-proof-verified-badge" class="help-proof-verified-badge hidden"> | |
| <svg viewBox="0 0 24 24"><path d="M20 6L9 17l-5-5"/></svg> | |
| <span id="help-proof-verified-text">Same animal confirmed</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="help-proof-section"> | |
| <div class="help-proof-label">Tell the story <span class="optional-tag">optional</span></div> | |
| <textarea id="help-proof-notes" rows="3" placeholder="What happened? Where did you take them?"></textarea> | |
| </div> | |
| <button class="btn-primary help-proof-submit" id="help-proof-submit"> | |
| <svg viewBox="0 0 24 24"><path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"/></svg> | |
| Register Help | |
| </button> | |
| </div> | |
| <!-- ══ PHOTO LIGHTBOX ══ --> | |
| <div id="photo-lightbox" class="photo-lightbox hidden" role="dialog"> | |
| <div class="lightbox-backdrop"></div> | |
| <div class="lightbox-inner"> | |
| <img id="lightbox-img" src="" alt="photo" /> | |
| <button id="lightbox-close" aria-label="Close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button> | |
| </div> | |
| </div> | |
| <!-- ══ PHOTO CONTEXT MENU ══ --> | |
| <div id="photo-menu" class="photo-menu hidden"> | |
| <button id="photo-menu-download"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> | |
| Download photo | |
| </button> | |
| </div> | |
| <!-- ══ BOTTOM NAV ══ --> | |
| <nav id="bottom-nav"> | |
| <button class="nav-btn active" data-screen="map"><span class="nav-icon"><i data-lucide="map"></i></span><span>Map</span></button> | |
| <button class="nav-btn" data-screen="register"><span class="nav-icon"><i data-lucide="camera"></i></span><span>Report</span></button> | |
| <button class="nav-btn" data-screen="sightings"><span class="nav-icon"><i data-lucide="eye"></i></span><span>Sightings</span></button> | |
| </nav> | |
| </div><!-- /#app --> | |
| </div><!-- /.phone-frame --> | |
| </div><!-- /.phone-wrap --> | |
| <!-- ══ RIGHT SIDEBAR (desktop only) ══ --> | |
| <aside id="sidebar-right"> | |
| <div class="sidebar-section"> | |
| <div class="sidebar-badge-title">Built for</div> | |
| <a class="hackathon-badge" href="https://huggingface.co/build-small-hackathon" target="_blank" rel="noopener"> | |
| <span class="hb-icon">🏡</span> | |
| <span class="hb-text"> | |
| <strong>Build Small Hackathon 2026</strong> | |
| <small>Backyard AI track · Hugging Face</small> | |
| </span> | |
| </a> | |
| </div> | |
| <div class="sidebar-divider"></div> | |
| <div class="sidebar-section"> | |
| <h3>Tech stack</h3> | |
| <div class="stack-list"> | |
| <div class="stack-row"> | |
| <span class="stack-label">Vision AI</span> | |
| <span class="stack-value">Nemotron Omni 30B</span> | |
| </div> | |
| <div class="stack-row"> | |
| <span class="stack-label">Embeddings</span> | |
| <span class="stack-value">all-MiniLM-L6-v2</span> | |
| </div> | |
| <div class="stack-row"> | |
| <span class="stack-label">Matching</span> | |
| <span class="stack-value">Cosine similarity</span> | |
| </div> | |
| <div class="stack-row"> | |
| <span class="stack-label">Map</span> | |
| <span class="stack-value">Leaflet.js + OSM</span> | |
| </div> | |
| <div class="stack-row"> | |
| <span class="stack-label">Frontend</span> | |
| <span class="stack-value">gr.Server SPA</span> | |
| </div> | |
| <div class="stack-row"> | |
| <span class="stack-label">Storage</span> | |
| <span class="stack-value">SQLite</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="sidebar-divider"></div> | |
| <div class="sidebar-section"> | |
| <h3>Help an animal today</h3> | |
| <p>Open a profile from the map, tap <strong>I Want to Help</strong>, and log what you did — fed, treated, fostered. A photo proves it; the AI verifies it's the same animal.</p> | |
| </div> | |
| <div class="sidebar-divider"></div> | |
| <div class="sidebar-section sidebar-links"> | |
| <a href="https://huggingface.co/spaces/build-small-hackathon/viralata-mapper" target="_blank" rel="noopener"> | |
| <svg viewBox="0 0 24 24"><path d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"/></svg> | |
| View on Hugging Face | |
| </a> | |
| <a href="https://huggingface.co/blog/build-small-hackathon/pawmap" target="_blank" rel="noopener"> | |
| <svg viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg> | |
| Field Notes | |
| </a> | |
| </div> | |
| <div class="sidebar-footer"> | |
| Made in Brasília, DF 🇧🇷<br> | |
| <span>for every stray that deserves to be seen</span> | |
| </div> | |
| </aside> | |
| </div><!-- /desktop-layout --> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script> | |
| <script src="/static/app.js"></script> | |
| <script src="/static/help-proof.js"></script> | |
| <script> | |
| [1,2,3,4].forEach(function(i) { | |
| lottie.loadAnimation({ | |
| container: document.getElementById('lottie-' + i), | |
| renderer: 'svg', | |
| loop: true, | |
| autoplay: true, | |
| path: '/static/lottie/step' + i + '.json' | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |