`;
body.appendChild(skel);
}
function _renderNotes() {
_updateRailBadge();
const body = document.querySelector('#notes-pane .notes-pane-body');
if (!body) return;
const prevPositions = _captureCardPositions();
const activeReminderHighlights = _loadActiveHighlights();
const sorted = _sortedVisibleNotes();
let html = '';
// Today view: render a compact card listing the next-unchecked step from
// each active goal. Tapping a step toggles it done (same idx-based wiring
// as regular checkboxes). Tapping the title opens the goal note for full
// editing.
if (state.activeFilter === 'today') {
body.innerHTML = '';
_renderLabelsInto(body);
_renderQuickAdd(body);
if (sorted.length === 0) {
body.insertAdjacentHTML('beforeend', `
All caught up — no pending goal steps right now.
`);
} else {
let todayHtml = `
Today · one step per goal
`;
for (const note of sorted) {
const next = _nextGoalStep(note);
if (!next) continue;
const progress = _goalProgress(note).trim();
todayHtml += `
${_esc(note.title || '(untitled goal)')}
${_linkify(next.item.text || '')}
${_esc(progress)}
`;
}
todayHtml += `
`;
body.insertAdjacentHTML('beforeend', todayHtml);
}
_wireTodayView(body);
return;
}
for (const note of sorted) {
if (state.editingId === note.id) continue; // skip : form is shown instead
const borderColor = COLOR_HEX[note.color || ''] || 'var(--border)';
const dueFmt = _formatDueDate(note.due_date);
const overdue = _isDueOverdue(note.due_date);
let contentHtml = '';
if (_hasItems(note) && Array.isArray(note.items)) {
// Goal notes can carry a free-form description above the step list :
// todos rarely do, but the same render works for both.
if (note.note_type === 'goal' && (note.content || '').trim()) {
const fullText = note.content || '';
const preview = fullText.length > 300 ? fullText.slice(0, 300) + '…' : fullText;
contentHtml += `
${_esc(preview)}
`;
}
contentHtml += '
';
// Show ALL items : the preview container is scrollable (CSS caps
// its max-height + overflow-y:auto), so there's no need to truncate.
for (let i = 0; i < note.items.length; i++) {
const item = note.items[i];
const doneClass = item.done ? ' done' : '';
const indent = Math.min(item.indent || 0, 3);
contentHtml += `
${_linkify(item.text)}
`;
}
contentHtml += '
';
} else {
const fullText = note.content || '';
const preview = fullText.length > 600 ? fullText.slice(0, 600) + '…' : fullText;
// _linkify already calls _esc internally, so URLs become clickable
// anchors (used by e.g. the "remind me to reply" email deep-link).
contentHtml = preview ? `
`;
}
// Always render quick-add at top (collapsed unless user is typing)
const existingForm = body.querySelector('.note-form');
if (existingForm && state.editingId === '__new__') {
// Keep the expanded form, replace cards after it
const next = [...body.children].filter(c => c !== existingForm);
next.forEach(c => c.remove());
if (sorted.length === 0) {
body.insertAdjacentHTML('beforeend', '
No notes ' + uiModule.emptyStateIcon('smiley') + '