${data.encounters.map((encounter, index) => {
// Truncate details to 4 sentences max to prevent overflow
let details = encounter.details || '';
// Remove encounter name if it appears at start
if (details.toLowerCase().startsWith(encounter.name.toLowerCase())) {
details = details.substring(encounter.name.length).replace(/^:\s*/, '').trim();
}
// Remove location prefix if present (format: "Location Name: description")
// Handle multiple colons - strip the first one that looks like a location
const locationMatch = details.match(/^([^:]+):\s*(.+)$/);
if (locationMatch) {
const potentialLocation = locationMatch[1].trim();
// If it looks like a location name (capitalized, not too long), remove it
if (potentialLocation.length > 3 && potentialLocation.length < 50 && /^[A-Z]/.test(potentialLocation)) {
details = locationMatch[2].trim();
}
}
// Split into sentences and keep only first 4
const sentences = details.match(/[^.!?]+[.!?]+/g) || [details];
if (sentences.length > 4) {
details = sentences.slice(0, 4).join(' ').trim();
}
// Also limit by character count as fallback (max ~350 chars)
if (details.length > 350) {
details = details.substring(0, 347).trim();
// Try to end at a sentence boundary
const lastPeriod = details.lastIndexOf('.');
if (lastPeriod > 280) {
details = details.substring(0, lastPeriod + 1);
} else {
details += '...';
}
}
return `
${data.plotResolutions.map(resolution => {
// Truncate to 1 sentence max to prevent overflow (more aggressive)
let text = resolution || '';
// Split into sentences and keep only first 1
const sentences = text.match(/[^.!?]+[.!?]+/g) || [text];
if (sentences.length > 1) {
text = sentences.slice(0, 1).join(' ').trim();
}
// Also limit by character count as fallback (max ~120 chars for tighter fit)
if (text.length > 120) {
text = text.substring(0, 117).trim();
// Try to end at a sentence boundary
const lastPeriod = text.lastIndexOf('.');
if (lastPeriod > 90) {
text = text.substring(0, lastPeriod + 1);
} else {
text += '...';
}
}
return `