(function (root, factory) {
  const renderMarkdown = factory();
  if (typeof module === 'object' && module.exports) module.exports = renderMarkdown;
  root.renderMarkdown = renderMarkdown;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
  function escapeHtml(value) {
    return String(value || '').replace(/[&<>"']/g, (character) => ({
      '&': '&amp;',
      '<': '&lt;',
      '>': '&gt;',
      '"': '&quot;',
      "'": '&#39;',
    })[character]);
  }

  function renderInline(value) {
    const code = [];
    let rendered = escapeHtml(value).replace(/`([^`\n]+)`/g, (_match, body) => {
      const marker = '\u0000CODE' + code.length + '\u0000';
      code.push('<code>' + body + '</code>');
      return marker;
    });
    rendered = rendered
      .replace(/\[([^\]\n]+)\]\(([^\s)]+)(?:\s+&quot;[^&]*?&quot;)?\)/g, (_match, label, escapedUrl) => {
        const url = escapedUrl.replace(/&amp;/g, '&');
        const safe = /^(https?:|mailto:)/i.test(url) || /^(\/|#|\.\/|\.\.\/)/.test(url);
        if (!safe) return label;
        return '<a href="' + escapedUrl + '" target="_blank" rel="noopener noreferrer">' + label + '</a>';
      })
      .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
      .replace(/(^|[^*])\*([^*\n]+)\*/g, '$1<em>$2</em>');
    return rendered.replace(/\u0000CODE(\d+)\u0000/g, (_match, index) => code[Number(index)]);
  }

  function renderList(lines, options, firstTaskIndex) {
    const taskList = lines.every(line => /^[-*+]\s+\[[ xX]\]\s+/.test(line));
    const items = lines.map((line, offset) => {
      let body = line.replace(/^[-*+]\s+/, '');
      if (!taskList) return '<li>' + renderInline(body) + '</li>';
      const checked = /^\[[xX]\]\s+/.test(body);
      body = body.replace(/^\[[ xX]\]\s+/, '');
      const control = options.interactiveTasks ?
        ' class="task-list-toggle" data-task-index="' + (firstTaskIndex + offset) +
          '" aria-label="Mark ' + escapeHtml(body) + (checked ? ' incomplete"' : ' complete"') :
        ' disabled';
      const manage = options.interactiveTasks && options.manageTasks ?
        '<button type="button" class="task-list-manage" data-task-index="' + (firstTaskIndex + offset) +
          '" data-task-label="' + escapeHtml(body) + '" aria-label="Manage step: ' + escapeHtml(body) + '"' +
          (offset === 0 ? ' data-task-first="true"' : '') +
          (offset === lines.length - 1 ? ' data-task-last="true"' : '') + '>Manage</button>' : '';
      return '<li class="task-list-item"><input type="checkbox"' + control +
        (checked ? ' checked' : '') + '> ' + renderInline(body) + manage + '</li>';
    }).join('');
    return '<ul' + (taskList ? ' class="task-list"' : '') + '>' + items + '</ul>';
  }

  function renderMarkdown(raw, options = {}) {
    const lines = String(raw || '').replace(/\r\n?/g, '\n').split('\n');
    const output = [];
    let index = 0;
    let taskIndex = 0;
    while (index < lines.length) {
      const line = lines[index];
      if (!line.trim()) {
        index += 1;
        continue;
      }
      const fence = line.match(/^```([A-Za-z0-9_-]*)\s*$/);
      if (fence) {
        const body = [];
        index += 1;
        while (index < lines.length && !/^```\s*$/.test(lines[index])) {
          body.push(lines[index]);
          index += 1;
        }
        if (index < lines.length) index += 1;
        const language = fence[1] ? ' class="language-' + fence[1] + '"' : '';
        output.push('<pre><code' + language + '>' + escapeHtml(body.join('\n')) + '</code></pre>');
        continue;
      }
      const heading = line.match(/^(#{1,6})\s+(.+)$/);
      if (heading) {
        const level = heading[1].length;
        output.push('<h' + level + '>' + renderInline(heading[2]) + '</h' + level + '>');
        index += 1;
        continue;
      }
      if (/^>\s?/.test(line)) {
        const quote = [];
        while (index < lines.length && /^>\s?/.test(lines[index])) {
          quote.push(lines[index].replace(/^>\s?/, ''));
          index += 1;
        }
        output.push('<blockquote><p>' + renderInline(quote.join('\n')).replace(/\n/g, '<br>') + '</p></blockquote>');
        continue;
      }
      if (/^[-*+]\s+/.test(line)) {
        const list = [];
        while (index < lines.length && /^[-*+]\s+/.test(lines[index])) {
          list.push(lines[index]);
          index += 1;
        }
        output.push(renderList(list, options, taskIndex));
        if (list.every(candidate => /^[-*+]\s+\[[ xX]\]\s+/.test(candidate))) {
          taskIndex += list.length;
        }
        continue;
      }
      const paragraph = [];
      while (index < lines.length && lines[index].trim() &&
             !/^```/.test(lines[index]) && !/^(#{1,6})\s+/.test(lines[index]) &&
             !/^>\s?/.test(lines[index]) && !/^[-*+]\s+/.test(lines[index])) {
        paragraph.push(lines[index]);
        index += 1;
      }
      output.push('<p>' + renderInline(paragraph.join('\n')).replace(/\n/g, '<br>') + '</p>');
    }
    return output.join('');
  }

  renderMarkdown.toggleTask = function toggleTask(raw, targetIndex, checked) {
    const parts = String(raw || '').split(/(\r\n|\n|\r)/);
    let fenced = false;
    let taskIndex = 0;
    for (let index = 0; index < parts.length; index += 2) {
      const line = parts[index];
      if (/^\s*```/.test(line)) {
        fenced = !fenced;
        continue;
      }
      if (fenced) continue;
      const task = line.match(/^([-*+]\s+\[)([ xX])(\])/);
      if (!task) continue;
      if (taskIndex === Number(targetIndex)) {
        parts[index] = task[1] + (checked ? 'x' : ' ') + task[3] + line.slice(task[0].length);
        return parts.join('');
      }
      taskIndex += 1;
    }
    return parts.join('');
  };

  return renderMarkdown;
});
