docs: def serialize_paragraph(ctx, document, par, root, embed=True):
      """Serializes paragraph element.
  
      This is the most important serializer of them all.    
      """
  
      style = get_style(document, par)
  
      elem = etree.Element('p')
  
      if ctx.options['embed_styles']:
          _style = get_style_css(ctx, par)
  
          if _style != '':
              elem.set('style', _style)
  
      else:
          _style = ''
  
      if style:
          elem.set('class', get_css_classes(document, style))
  
      max_font_size = get_style_fontsize(par)
  
      if style:
          max_font_size = _get_font_size(document, style)
  
      for el in par.elements:
          _serializer =  ctx.get_serializer(el)
  
          if _serializer:
              _serializer(ctx, document, el, elem)
  
          if isinstance(el, doc.Text):
              children = list(elem)
              _text_style = get_style_css(ctx, el)
              _text_class = el.rpr.get('style', '').lower()
  
              if _text_class == '':
                  __s = get_style(document, par)
                  if __s is not None:
                      _text_class = get_style_name(__s).lower()
  
              if get_style_fontsize(el) > max_font_size:
                  max_font_size = get_style_fontsize(el)
  
              if 'superscript' in el.rpr:
                  new_element = etree.Element('sup')
                  new_element.text = el.value()
              elif 'subscript' in el.rpr:
                  new_element = etree.Element('sub')
                  new_element.text = el.value()               
              elif 'b' in el.rpr or 'i' in el.rpr or 'u' in el.rpr:                
                  new_element = None
                  _element = None
  
                  def _add_formatting(f, new_element, _element):
                      if f in el.rpr:
                          _t = etree.Element(f)
  
                          if new_element is not None:
                              _element.append(_t)
                              _element = _t
                          else:
                              new_element = _t
                              _element = new_element
  
                      return new_element, _element
  
                  new_element, _element = _add_formatting('b', new_element, _element)
                  new_element, _element = _add_formatting('i', new_element, _element)
                  new_element, _element = _add_formatting('u', new_element, _element)
                  
                  _element.text = el.value()
  
                  for comment_id in ctx.opened_comments:
                      document.comments[comment_id].text += ' ' + el.value()
              else:
                  new_element = etree.Element('span')
                  new_element.text = el.value()
                  if ctx.options['embed_styles']:
                      try:
                          new_element.set('class', _text_class)
                      except:
                          pass
  
                  for comment_id in ctx.opened_comments:
                      if comment_id in document.comments:
                          document.comments[comment_id].text += ' ' + el.value()
  
              if ctx.options['embed_styles']:
                  if _text_style != '' and _style != _text_style:
                      new_element.set('style', _text_style)
  
              # This is for situations when style has options and
              # text is trying to unset them
              # else:            
              #     new_element.set('class', 'noformat')
  
              was_inserted = False
  
              if len(children) > 0:
                  _child_style = children[-1].get('style') or ''
                  _child_class = children[-1].get('class', '')
  
                  if new_element.tag == children[-1].tag and ((_text_class == _child_class or _child_class == '') and (_text_style == _child_style or _child_style == '')) and children[-1].tail is None:
                      txt = children[-1].text or ''
                      txt2 = new_element.text or ''
                      children[-1].text = u'{}{}'.format(txt, txt2)  
                      was_inserted = True
  
                  if not was_inserted:
                      if _style == _text_style  and new_element.tag == 'span' and (_text_class == _child_class or _child_class == ''):
                          _e = children[-1]
  
                          txt = _e.tail or ''
                          _e.tail = u'{}{}'.format(txt, new_element.text)
                          was_inserted = True
    
                      if not was_inserted and new_element.tag == 'span' and (_text_class != _child_class):
                          _e = children[-1]
                          txt = _e.tail or ''
                          _e.tail = u'{}{}'.format(txt, new_element.text)
                          was_inserted = True       
  
              if not was_inserted:
                  _child_class = new_element.get('class', '')
                  try:
                      _child_class = children[-1].get('class', '')
                  except:
                      _child_class = ''
  
                  if _style ==  _text_style  and new_element.tag == 'span' and (_text_class == _child_class):
                      txt = elem.text or ''
                      elem.text = u'{}{}'.format(txt, new_element.text)
                  else:
                      if new_element.text != u'':
                          elem.append(new_element)
      
      if not par.is_dropcap() and par.ilvl == None:
          if style:
              if ctx.header.is_header(par, max_font_size, elem, style=style):
                  elem.tag = ctx.header.get_header(par, style, elem)
                  if par.ilvl == None:        
                      root = close_list(ctx, root)
                      ctx.ilvl, ctx.numid = None, None
  
                  if root is not None:
                      root.append(elem)
  
                  fire_hooks(ctx, document, par, elem, ctx.get_hook('h'))
                  return root
          else:
  #            Commented part where we only checked for heading if font size
  #            was bigger than default font size. In many cases this did not
  #            work out well.
  #            if max_font_size > ctx.header.default_font_size:
              if True:
                  if ctx.header.is_header(par, max_font_size, elem, style=style):
                      if elem.text != '' and len(list(elem)) != 0:
                          elem.tag = ctx.header.get_header(par, max_font_size, elem)
  
                          if par.ilvl == None:        
                              root = close_list(ctx, root)
                              ctx.ilvl, ctx.numid = None, None
  
  
                          if root is not None:
                              root.append(elem)
  
                          fire_hooks(ctx, document, par, elem, ctx.get_hook('h'))
                          return root
  
      if len(list(elem)) == 0 and elem.text is None:
          if ctx.options['empty_paragraph_as_nbsp']:
              elem.append(etree.Entity('nbsp'))
  
      # Indentation is different. We are starting or closing list.
      if par.ilvl != None:        
          root = open_list(ctx, document, par, root, elem)
          return root
      else:
          root = close_list(ctx, root)
          ctx.ilvl, ctx.numid = None, None
  
      # Add new elements to our root element.
      if root is not None:
          root.append(elem)
  
      fire_hooks(ctx, document, par, elem, ctx.get_hook('p'))
  
      return root