<div class="result-card search-result-card">
<div class="search-echo">{{ query }}</div>
<div style="display:flex; justify-content:space-between; align-items:center; margin:16px 0 12px;">
<div style="font-weight:600; font-size:1.1rem; color:var(--text);">
{% if role == "professional" %}
{{ brand.draft_header }}
{% elif role == "homeowner" %}
Here's what you need to know
{% else %}
{{ brand.answer_header }}
{% endif %}
</div>
<div style="display:flex; gap:8px; align-items:center;">
<button type="button" id="draft-edit-btn" onclick="_startEditing()"
style="background:none; border:1px solid var(--border); color:var(--text-muted); padding:6px 14px; border-radius:6px; font-size:0.8rem; cursor:pointer;">
Edit
</button>
<button type="button" onclick="_copyDraft(this)"
style="background:none; border:1px solid var(--border); color:var(--accent); padding:6px 14px; border-radius:6px; font-size:0.8rem; cursor:pointer; display:flex; align-items:center; gap:4px;">
<span class="copy-label">Copy</span>
</button>
</div>
</div>
{# Hidden field stores original AI text for diff comparison #}
<input type="hidden" id="ai-draft-original" value="">
<div id="draft-content" style="padding:16px; background:var(--surface-2, #252834); border-radius:10px; border:1px solid var(--border); transition: border-color 0.2s;">
{% if ai_response_html is defined and ai_response_html %}
{# AI-synthesized response — clean, conversational #}
<div class="ai-response" style="line-height:1.7; font-size:0.95rem;">
{{ ai_response_html | safe }}
</div>
{% elif results is defined and results %}
{# Fallback: raw RAG chunks (when AI synthesis unavailable) #}
<div style="font-size:0.85rem; color:var(--text-muted); margin-bottom:12px; font-style:italic;">
AI synthesis unavailable — showing raw knowledge base results:
</div>
{% for r in results %}
<div style="margin-bottom:12px; {% if not loop.last %}padding-bottom:12px; border-bottom:1px solid rgba(255,255,255,0.06);{% endif %}">
{{ r.content_html | safe }}
</div>
{% endfor %}
{% else %}
<div style="color:var(--text-muted);">No relevant information found.</div>
{% endif %}
{% if references %}
<div style="margin-top:16px; padding-top:12px; border-top:1px solid var(--border); font-size:0.82rem; color:var(--text-muted);">
<strong>Sources:</strong>
{% for ref in references %}
<span>{{ ref }}{% if not loop.last %} · {% endif %}</span>
{% endfor %}
</div>
{% endif %}
</div>
{# Editing toolbar — hidden until Edit is clicked #}
<div id="draft-edit-toolbar" style="display:none; margin-top:10px; padding:10px 16px; background:var(--surface-2, #252834); border-radius:8px; border:1px solid var(--accent);">
<div style="display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap; gap:8px;">
<div style="font-size:0.82rem; color:var(--text-muted);">
Editing — make your changes directly above, then:
</div>
<div style="display:flex; gap:8px; align-items:center;">
<button type="button" onclick="_saveDraftEdit()"
class="btn" style="padding:6px 16px; width:auto; font-size:0.82rem;">
Save Changes
</button>
<button type="button" onclick="_cancelEditing()"
style="background:none; border:1px solid var(--border); color:var(--text-muted); padding:6px 14px; border-radius:6px; font-size:0.82rem; cursor:pointer;">
Cancel
</button>
<button type="button" onclick="_markDraftGood()"
style="background:none; border:1px solid var(--border); color:var(--success, #34d399); padding:6px 14px; border-radius:6px; font-size:0.82rem; cursor:pointer;">
Used as-is ✓
</button>
</div>
</div>
<div id="edit-confirm" style="margin-top:6px;"></div>
</div>
{# Collapsible source details #}
{% set sources = source_details if source_details is defined else results %}
{% if sources %}
<details style="margin-top:12px;">
<summary style="cursor:pointer; font-size:0.82rem; color:var(--text-muted); font-weight:600;">
Knowledge sources ({{ sources | length }})
</summary>
<div style="margin-top:8px; padding:12px; background:var(--surface-2, #252834); border-radius:8px;">
{% for r in sources %}
<div style="display:flex; justify-content:space-between; align-items:center; padding:4px 0; font-size:0.8rem;">
<span style="color:var(--text-muted);">
{{ r.source_label }}
{% if r.source_tier == 'amy' %}
<span style="color:var(--success); font-weight:600;">(Expert note)</span>
{% endif %}
</span>
<span style="color:var(--accent); font-weight:600;">{{ "%.0f%%" | format(r.score * 100) }}</span>
</div>
{% endfor %}
</div>
</details>
{% endif %}
{# Admin: Add a note #}
{% if is_expert %}
<div style="margin-top:16px; padding-top:12px; border-top:1px solid var(--border);">
<button type="button" onclick="this.style.display='none'; document.getElementById('draft-note-form').style.display='block';"
style="background:none; border:1px solid var(--border); color:var(--text-muted); padding:6px 14px; border-radius:6px; font-size:0.8rem; cursor:pointer;">
+ Add a note
</button>
<div id="draft-note-form" style="display:none; margin-top:10px;">
<form hx-post="/admin/knowledge/add-note"
hx-target="#draft-note-confirm"
hx-swap="innerHTML">
<input type="hidden" name="query_context" value="{{ query }}">
<textarea name="note_text" rows="3"
placeholder="Add a correction, tip, or additional context..."
style="width:100%; background:var(--bg); border:1px solid var(--border); border-radius:8px; color:var(--text); padding:10px; font-family:inherit; font-size:0.9rem; resize:vertical;"></textarea>
<button type="submit" class="btn" style="margin-top:8px; padding:10px 24px; width:auto; font-size:0.85rem;">
Save Note
</button>
</form>
<div id="draft-note-confirm" style="margin-top:8px;"></div>
</div>
</div>
{% endif %}
{# Quick-action modifier buttons — re-generate with a specific overlay #}
{% if is_expert and ai_response_html is defined and ai_response_html %}
<div id="draft-regen-buttons" style="display:flex; gap:6px; margin-top:14px; flex-wrap:wrap; align-items:center;">
<span style="font-size:0.78rem; color:var(--text-muted); margin-right:2px;">Re-generate:</span>
<button type="button" class="btn-pill"
hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading"
hx-vals='js:{"query": {{ query | tojson }}, "modifier": "get_meeting"}'>
Get a meeting
</button>
<button type="button" class="btn-pill"
hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading"
hx-vals='js:{"query": {{ query | tojson }}, "modifier": "shorter"}'>
Shorter
</button>
<button type="button" class="btn-pill"
hx-post="/ask" hx-target="#search-results" hx-swap="innerHTML"
hx-indicator="#search-loading"
hx-vals='js:{"query": {{ query | tojson }}, "modifier": "more_detail"}'>
More detail + sources
</button>
</div>
{% endif %}
{% if not is_expert %}
<div style="margin-top:16px; font-size:0.85rem; color:var(--text-muted);">
Have a follow-up question? Type it in the search bar at the top of the page.
</div>
{% endif %}
</div>
<script nonce="{{ csp_nonce }}">
var _draftEditing = false;
function _copyDraft(btn) {
var content = document.getElementById('draft-content');
if (!content) return;
var text = content.innerText || content.textContent;
navigator.clipboard.writeText(text).then(function() {
var label = btn.querySelector('.copy-label');
label.textContent = 'Copied!';
setTimeout(function() { label.textContent = 'Copy'; }, 2000);
});
}
function _startEditing() {
var content = document.getElementById('draft-content');
var toolbar = document.getElementById('draft-edit-toolbar');
var editBtn = document.getElementById('draft-edit-btn');
var original = document.getElementById('ai-draft-original');
if (!content || !toolbar) return;
// Store original text for diff
original.value = content.innerText || content.textContent;
// Make content editable
content.contentEditable = 'true';
content.style.borderColor = 'var(--accent)';
content.style.outline = 'none';
content.focus();
// Show toolbar, hide edit button and re-generate buttons
toolbar.style.display = 'block';
if (editBtn) editBtn.style.display = 'none';
var regenBtns = document.getElementById('draft-regen-buttons');
if (regenBtns) regenBtns.style.display = 'none';
_draftEditing = true;
}
function _cancelEditing() {
var content = document.getElementById('draft-content');
var toolbar = document.getElementById('draft-edit-toolbar');
var editBtn = document.getElementById('draft-edit-btn');
if (!content || !toolbar) return;
content.contentEditable = 'false';
content.style.borderColor = 'var(--border)';
toolbar.style.display = 'none';
if (editBtn) editBtn.style.display = '';
var regenBtns = document.getElementById('draft-regen-buttons');
if (regenBtns) regenBtns.style.display = '';
_draftEditing = false;
}
function _saveDraftEdit() {
var content = document.getElementById('draft-content');
var original = document.getElementById('ai-draft-original');
var confirm = document.getElementById('edit-confirm');
if (!content || !original) return;
var editedText = content.innerText || content.textContent;
var originalText = original.value;
// Check if actually changed
if (editedText.trim() === originalText.trim()) {
_markDraftGood();
return;
}
// Submit edit via fetch
var formData = new FormData();
formData.append('original_query', '{{ query | e }}');
formData.append('ai_draft', originalText);
formData.append('edited_version', editedText);
fetch('/feedback/draft-edit', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]')?.content || ''
}
})
.then(function(r) { return r.text(); })
.then(function(html) {
if (confirm) confirm.innerHTML = html;
// Exit editing mode
content.contentEditable = 'false';
content.style.borderColor = 'var(--border)';
_draftEditing = false;
// Keep toolbar visible to show confirmation
})
.catch(function(err) {
if (confirm) confirm.innerHTML = '<span style="color:var(--error);">Failed to save — try again.</span>';
});
}
function _markDraftGood() {
var original = document.getElementById('ai-draft-original');
var confirm = document.getElementById('edit-confirm');
var content = document.getElementById('draft-content');
var originalText = original ? original.value : '';
// If editing hasn't started, grab current text
if (!originalText) {
originalText = content ? (content.innerText || content.textContent) : '';
}
var formData = new FormData();
formData.append('original_query', '{{ query | e }}');
formData.append('ai_draft', originalText);
fetch('/feedback/draft-good', {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]')?.content || ''
}
})
.then(function(r) { return r.text(); })
.then(function(html) {
// Show toolbar if hidden so confirmation is visible
var toolbar = document.getElementById('draft-edit-toolbar');
if (toolbar) toolbar.style.display = 'block';
if (confirm) confirm.innerHTML = html;
// Exit editing mode
if (content) {
content.contentEditable = 'false';
content.style.borderColor = 'var(--border)';
}
_draftEditing = false;
// Hide the edit button and other toolbar buttons
var editBtn = document.getElementById('draft-edit-btn');
if (editBtn) editBtn.style.display = 'none';
})
.catch(function() {
if (confirm) confirm.innerHTML = '<span style="color:var(--error);">Failed — try again.</span>';
});
}
// Store original text on page load for the "Used as-is" button
document.addEventListener('DOMContentLoaded', function() {
var content = document.getElementById('draft-content');
var original = document.getElementById('ai-draft-original');
if (content && original && !original.value) {
original.value = content.innerText || content.textContent;
}
});
</script>