<style nonce="{{ csp_nonce }}">
.search-result-card table td a {
color: var(--accent);
text-decoration: underline;
}
.search-result-card table td a:hover {
color: var(--accent);
opacity: 0.8;
}
.search-result-card table td a.dbi-link,
.search-result-card a.dbi-link {
color: var(--text-tertiary);
font-size: 0.75rem;
text-decoration: none;
margin-left: 0.25rem;
}
.search-result-card table td a.dbi-link:hover,
.search-result-card a.dbi-link:hover {
color: var(--text-secondary);
text-decoration: none;
opacity: 1;
}
/* Property Intelligence Panel */
.intel-panel {
display: grid;
grid-template-columns: 1fr;
gap: 12px;
margin-bottom: 16px;
}
@media (min-width: 640px) {
.intel-panel {
grid-template-columns: 1fr 1fr 1fr;
gap: 16px;
}
}
.intel-col {
padding: 12px 14px;
background: var(--obsidian-mid);
border: 1px solid var(--glass-border);
border-radius: var(--radius-md);
}
.intel-col-label {
font-family: var(--mono);
font-size: var(--text-xs);
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.06em;
margin-bottom: 6px;
}
.intel-col-value {
font-family: var(--mono);
font-size: var(--text-lg);
font-weight: 400;
color: var(--text-primary);
}
.intel-col-detail {
font-family: var(--sans);
font-size: var(--text-xs);
color: var(--text-secondary);
margin-top: 2px;
}
/* Enforcement alert state โ used when violations exist */
.intel-col--alert {
background: rgba(248, 113, 113, 0.07);
border-color: rgba(248, 113, 113, 0.25);
}
/* Triage intelligence signals (search_results authenticated view) */
.triage-section {
margin: var(--space-4) 0;
padding-top: var(--space-4);
border-top: 1px solid var(--glass-border);
}
.triage-section-label {
font-family: var(--mono);
font-size: var(--text-xs);
font-weight: 400;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: var(--space-3);
display: flex;
align-items: center;
gap: 6px;
}
.triage-row {
display: flex;
align-items: center;
gap: var(--space-3);
flex-wrap: wrap;
padding: var(--space-2) 0;
border-bottom: 1px solid rgba(255,255,255,0.02);
}
.triage-row:last-child { border-bottom: none; }
.triage-row__permit {
font-family: var(--mono);
font-size: var(--text-xs);
color: var(--text-secondary);
min-width: 110px;
}
.triage-station-badge {
display: inline-flex;
align-items: center;
gap: 5px;
font-family: var(--mono);
font-size: var(--text-xs);
padding: 2px 7px;
border-radius: 9999px;
border: 1px solid;
}
.triage-station-badge--green {
color: #22c55e; background: rgba(34,197,94,0.08); border-color: rgba(34,197,94,0.20);
}
.triage-station-badge--amber {
color: #f59e0b; background: rgba(245,158,11,0.08); border-color: rgba(245,158,11,0.20);
}
.triage-station-badge--red {
color: #ef4444; background: rgba(239,68,68,0.08); border-color: rgba(239,68,68,0.20);
}
.triage-station-badge__dot {
width: 6px; height: 6px; border-radius: 9999px; flex-shrink: 0;
}
.triage-station-badge--green .triage-station-badge__dot { background: #22c55e; }
.triage-station-badge--amber .triage-station-badge__dot { background: #f59e0b; }
.triage-station-badge--red .triage-station-badge__dot { background: #ef4444; }
.triage-stuck {
font-family: var(--mono); font-size: var(--text-xs);
color: #ef4444; display: inline-flex; align-items: center; gap: 4px;
}
.triage-reviewer {
font-family: var(--mono); font-size: var(--text-xs);
color: var(--text-secondary);
}
</style>
{# Default context vars โ callers that don't pass these get safe no-op values #}
{% set project_context = project_context if project_context is defined else none %}
{% set violation_counts = violation_counts if violation_counts is defined else none %}
{% set active_businesses = active_businesses if active_businesses is defined else [] %}
{% set show_quick_actions = show_quick_actions if show_quick_actions is defined else false %}
{% set address_intel = address_intel if address_intel is defined else none %}
{% set triage_signals = triage_signals if triage_signals is defined else [] %}
<div class="result-card search-result-card glass-card">
<div class="search-echo" style="display: flex; justify-content: space-between; align-items: center;">
<span>{{ query_echo }}</span>
{% if watch_data %}
<span class="watch-container">
{% if existing_watch_id %}
{% include 'fragments/watch_confirmation.html' %}
{% elif g.user %}
{% include 'fragments/watch_button.html' %}
{% else %}
{% include 'fragments/login_prompt.html' %}
{% endif %}
</span>
{% endif %}
</div>
{# Quick Actions - only on address/parcel searches, not on complaint/violation results #}
{% if show_quick_actions and not no_results and (report_url or street_address) %}
<div class="glass-card" style="margin-top:var(--space-4);margin-bottom:var(--space-4);">
<div style="font-weight: 600; margin-bottom: var(--space-3); color: var(--text-primary);">Quick Actions</div>
<div style="display: flex; flex-wrap: wrap; gap: 10px;">
<!-- Primary: View Property Report -->
{% if report_url %}
<a href="{{ report_url }}" class="obsidian-btn obsidian-btn-primary"
style="display:inline-flex;align-items:center;gap:6px;text-decoration:none;">
๐ View Property Report
</a>
{% endif %}
<!-- Analyze Project (prefill with real permit data if available) -->
{% if street_address %}
<form hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading" style="display:inline;margin:0;">
<input type="hidden" name="analyze" value="1">
<input type="hidden" name="address" value="{{ street_address or '' }}">
{% if project_context %}
<input type="hidden" name="q" value="{{ project_context.description }}">
<input type="hidden" name="estimated_cost" value="{{ project_context.estimated_cost or '' }}">
<input type="hidden" name="neighborhood" value="{{ project_context.neighborhood or '' }}">
{% else %}
<input type="hidden" name="q" value="I want to analyze a project at {{ street_address }}">
{% endif %}
<button type="submit" class="obsidian-btn obsidian-btn-outline"
style="display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-family:var(--sans);">
๐ {% if project_context %}Analyze: {{ project_context.label }}{% else %}Analyze Project{% endif %}
</button>
</form>
{% endif %}
<!-- Check Violations โ 3 visual states based on data availability -->
{% if street_address %}
<form hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading" style="display:inline;margin:0;">
<input type="hidden" name="q" value="Are there any violations at {{ street_address }}?">
<button type="submit" class="obsidian-btn obsidian-btn-outline"
style="display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-family:var(--sans);
{% if violation_counts and violation_counts.total > 0 %}
background:rgba(248,113,113,0.1);color:var(--signal-red);border-color:rgba(248,113,113,0.35);
{% elif violation_counts %}
background:rgba(52,211,153,0.08);color:var(--signal-green);border-color:rgba(52,211,153,0.25);
{% endif %}
">
{% if violation_counts and violation_counts.total > 0 %}
โ ๏ธ Check Violations ยท {{ violation_counts.total }} open
{% elif violation_counts %}
โ No open violations
{% else %}
โ ๏ธ Check Violations
{% endif %}
</button>
</form>
{% endif %}
<!-- Who's Here โ only shown when businesses data is available -->
{% if active_businesses and street_address %}
<form hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading" style="display:inline;margin:0;">
<input type="hidden" name="q" value="Who is operating at {{ street_address }}?">
<button type="submit" class="obsidian-btn obsidian-btn-outline"
style="display:inline-flex;align-items:center;gap:6px;cursor:pointer;font-family:var(--sans);">
๐ข Who's Here
{% if active_businesses|length == 1 %}ยท {{ active_businesses[0].name[:22] }}
{% else %}ยท {{ active_businesses|length }} businesses{% endif %}
</button>
</form>
{% endif %}
</div>
</div>
{% endif %}
{# ===== Property Intelligence Panel ===== #}
{% if address_intel and show_quick_actions and not no_results %}
<div class="intel-panel">
{# Column 1: Enforcement #}
<div class="intel-col{% if address_intel.enforcement_total and address_intel.enforcement_total > 0 %} intel-col--alert{% endif %}">
<div class="intel-col-label">Enforcement</div>
{% if address_intel.enforcement_total is not none %}
{% if address_intel.enforcement_total > 0 %}
<div class="intel-col-value" style="color:var(--signal-red);">{{ address_intel.enforcement_total }} open</div>
<div class="intel-col-detail" style="color:var(--signal-red);">
{% if address_intel.open_violations %}{{ address_intel.open_violations }} violation{{ 's' if address_intel.open_violations != 1 else '' }}{% endif %}{% if address_intel.open_violations and address_intel.open_complaints %}, {% endif %}{% if address_intel.open_complaints %}{{ address_intel.open_complaints }} complaint{{ 's' if address_intel.open_complaints != 1 else '' }}{% endif %}
</div>
{% else %}
<div class="intel-col-value" style="color:var(--signal-green);">โ Clear</div>
<div class="intel-col-detail">No open violations</div>
{% endif %}
{% else %}
<div class="intel-col-value" style="color:var(--text-secondary);">—</div>
<div class="intel-col-detail">No parcel data</div>
{% endif %}
</div>
{# Column 2: Businesses #}
<div class="intel-col">
<div class="intel-col-label">Businesses</div>
{% if address_intel.business_count > 0 %}
<div class="intel-col-value" style="color:var(--text-primary);">{{ address_intel.business_count }} active</div>
<div class="intel-col-detail">
{{ address_intel.active_businesses[0].name[:28] }}{% if address_intel.business_count > 1 %} +{{ address_intel.business_count - 1 }}{% endif %}
</div>
{% elif address_intel.business_count == 0 and address_intel.active_businesses is defined %}
<div class="intel-col-value" style="color:var(--text-secondary);">None</div>
<div class="intel-col-detail">No registered businesses</div>
{% else %}
<div class="intel-col-value" style="color:var(--text-secondary);">—</div>
<div class="intel-col-detail">Parcel search only</div>
{% endif %}
</div>
{# Column 3: Permits #}
<div class="intel-col">
<div class="intel-col-label">Permits</div>
{% if address_intel.total_permits is not none %}
<div class="intel-col-value" style="color:var(--text-primary);">
{{ address_intel.total_permits }}
<span style="font-size:var(--text-xs);font-weight:400;color:var(--text-secondary);">total</span>
</div>
<div class="intel-col-detail">
{% if address_intel.active_permits %}{{ address_intel.active_permits }} active{% else %}None active{% endif %}{% if address_intel.latest_permit_type %} ยท {{ address_intel.latest_permit_type | title_permit }}{% endif %}
</div>
{% if address_intel.routing_total and address_intel.routing_total > 0 %}
<div style="margin-top:8px;padding-top:8px;border-top:1px solid var(--glass-border);">
<div class="intel-col-label">Plan Review</div>
{% set pct = ((address_intel.routing_complete or 0) * 100 / address_intel.routing_total) | int %}
<div style="display:flex;align-items:center;gap:8px;">
<div style="flex:1;height:6px;background:var(--glass);border-radius:3px;overflow:hidden;">
<div style="width:{{ pct }}%;height:100%;background:{% if pct == 100 %}var(--signal-green){% elif pct >= 50 %}var(--accent){% else %}var(--signal-amber){% endif %};border-radius:3px;"></div>
</div>
<span style="font-size:var(--text-xs);font-weight:400;color:var(--text-primary);white-space:nowrap;">{{ address_intel.routing_complete }}/{{ address_intel.routing_total }}</span>
</div>
{% if address_intel.routing_latest_station %}
<div class="intel-col-detail" style="margin-top:4px;">
{% if address_intel.routing_latest_result and 'approv' in address_intel.routing_latest_result|lower %}
<span style="color:var(--signal-green);">โ</span>
{% elif address_intel.routing_latest_result and 'comment' in address_intel.routing_latest_result|lower %}
<span style="color:var(--signal-amber);">๐ฌ</span>
{% endif %}
{{ address_intel.routing_latest_station }}{% if address_intel.routing_latest_date %} ยท {{ address_intel.routing_latest_date | format_date }}{% endif %}
</div>
{% endif %}
</div>
{% endif %}
{% else %}
<div class="intel-col-value" style="color:var(--text-secondary);">—</div>
<div class="intel-col-detail">No permit data</div>
{% endif %}
</div>
</div>
{% endif %}
{# ===== Triage Intelligence Signals ===== #}
{% if triage_signals %}
<div class="triage-section">
<div class="triage-section-label">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
Triage signals
</div>
{% for sig in triage_signals %}
<div class="triage-row">
<span class="triage-row__permit">{{ sig.permit_number }}</span>
{% if sig.current_station and sig.days_at_station is not none %}
<span class="triage-station-badge triage-station-badge--{{ sig.threshold_class or 'green' }}" title="{{ sig.days_at_station }} days at {{ sig.current_station }}">
<span class="triage-station-badge__dot"></span>
{{ sig.days_at_station }}d at {{ sig.current_station }}
</span>
{% elif sig.current_station %}
<span class="triage-reviewer">At {{ sig.current_station }}</span>
{% endif %}
{% if sig.is_stuck %}
<span class="triage-stuck">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
Stuck
</span>
{% endif %}
{% if sig.reviewer %}
<span class="triage-reviewer">Reviewer: {{ sig.reviewer }}</span>
{% endif %}
</div>
{% endfor %}
</div>
{% endif %}
{{ result_html | safe }}
{% if no_results and no_results_address %}
<div class="glass-card" style="margin-top: var(--space-5)">
{# ===== Fuzzy suggestions: "Did you mean...?" ===== #}
{% if fuzzy_suggestions %}
<div style="font-weight: 600; margin-bottom: 10px;">Did you mean?</div>
<div style="display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px;">
{% for s in fuzzy_suggestions %}
<form method="POST" action="/ask" style="display:inline;margin:0;padding:0;">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="q" value="{{ s.street_number }} {{ s.full_name }}">
<button type="submit"
style="display:inline-flex;align-items:center;gap:8px;color:var(--accent);background:none;border:none;cursor:pointer;padding:4px 0;font-family:var(--sans);font-size:var(--text-base);text-align:left;">
<span>➤</span>
{{ s.street_number }} {{ s.full_name }}
<span style="color:var(--text-secondary);font-size:var(--text-sm);">({{ s.count }} permits)</span>
</button>
</form>
{% endfor %}
</div>
<div style="border-top:1px solid var(--glass-border);padding-top:12px;margin-top:4px;">
{% endif %}
<div style="font-weight: 600; margin-bottom: 8px;">What you can do next</div>
<div style="display: flex; flex-direction: column; gap: 10px;">
{% if report_url %}
<a href="{{ report_url }}"
style="display: inline-flex; align-items: center; gap: 8px; color: var(--accent); text-decoration: none; font-weight: 400; font-size: var(--text-base);">
<span>📊</span> Run Property Report
</a>
{% endif %}
<a href="/?q={{ no_results_address }}"
style="display: inline-flex; align-items: center; gap: 8px; color: var(--text-secondary); text-decoration: none; font-size: var(--text-sm);">
<span>🔍</span> Try a different search
</a>
<span style="color: var(--text-secondary); font-size: var(--text-sm); margin-top: 4px;">
No permit history doesn't mean no permits are required — it may just mean no permits have been filed yet at this address.
</span>
</div>
{% if fuzzy_suggestions %}
</div>
{% endif %}
</div>
{% elif not no_results %}
{# ===== Neighborhood stats card ===== #}
{% if hood_stats %}
<div class="glass-card" style="margin-top:var(--space-3);">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
<span style="font-family:var(--sans);font-weight:400;font-size:var(--text-base);color:var(--text-primary);">{{ hood_stats.name }}</span>
<span style="font-family:var(--mono);font-size:var(--text-xs);color:var(--text-secondary);">neighborhood</span>
</div>
<div style="display:flex;gap:20px;flex-wrap:wrap;">
<div>
<div style="font-family:var(--mono);font-size:var(--text-lg);font-weight:300;color:var(--accent);">{{ "{:,}".format(hood_stats.total_permits) }}</div>
<div style="font-family:var(--mono);font-size:var(--text-xs);color:var(--text-secondary);text-transform:uppercase;">total permits</div>
</div>
<div>
<div style="font-family:var(--mono);font-size:var(--text-lg);font-weight:300;color:var(--signal-green);">{{ "{:,}".format(hood_stats.active_permits) }}</div>
<div style="font-family:var(--mono);font-size:var(--text-xs);color:var(--text-secondary);text-transform:uppercase;">active</div>
</div>
{% if hood_stats.top_types %}
<div style="flex:1;min-width:160px;">
<div style="font-family:var(--mono);font-size:var(--text-xs);color:var(--text-secondary);text-transform:uppercase;margin-bottom:4px;">top permit types</div>
{% for t in hood_stats.top_types %}
<div style="font-family:var(--sans);font-size:var(--text-sm);color:var(--text-secondary);display:flex;justify-content:space-between;gap:8px;">
<span style="overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ t.type }}</span>
<span style="color:var(--text-secondary);flex-shrink:0;">{{ "{:,}".format(t.count) }}</span>
</div>
{% endfor %}
</div>
{% endif %}
</div>
</div>
{% endif %}
{% endif %}
{% if show_primary_prompt and prompt_street_number %}
{% include 'fragments/primary_address_prompt.html' %}
{% endif %}
</div>