diff --git a/COPYING.md b/COPYING.md
--- a/COPYING.md
+++ b/COPYING.md
@@ -3,8 +3,8 @@
 Version 2, June 1991
 
     Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
-    51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-
+    <https://fsf.org/>
+    
     Everyone is permitted to copy and distribute verbatim copies
     of this license document, but changing it is not allowed.
 
@@ -317,10 +317,9 @@
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+    
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, see <https://www.gnu.org/licenses/>.
 
 Also add information on how to contact you by electronic and paper
 mail.
diff --git a/COPYRIGHT b/COPYRIGHT
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -14,9 +14,8 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+   You should have received a copy of the GNU General Public License along
+   with this program; if not, see <https://www.gnu.org/licenses/>.
 
 The GNU General Public License is available in the file COPYING.md in
 the source distribution.  On Debian systems, the complete text of the
diff --git a/MANUAL.txt b/MANUAL.txt
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -1,7 +1,7 @@
 ---
 title: Pandoc User's Guide
 author: John MacFarlane
-date: 2025-09-29
+date: 2025-10-05
 ---
 
 # Synopsis
@@ -151,8 +151,7 @@
 uses [`selnolig`] and [`lua-ul`]. `xelatex` uses [`bidi`] (with
 the `dir` variable set).
 If the `mathspec` variable is set, `xelatex` will use [`mathspec`]
-instead of [`unicode-math`].  The [`upquote`] and [`microtype`]
-packages are used if available, and [`csquotes`] will be used
+instead of [`unicode-math`].  The [`csquotes`] package will be used
 for [typography] if the `csquotes` variable or metadata field is
 set to a true value.  The [`natbib`], [`biblatex`], [`bibtex`],
 and [`biber`] packages can optionally be used for [citation
@@ -194,6 +193,7 @@
 [`longtable`]: https://ctan.org/pkg/longtable
 [`mathspec`]: https://ctan.org/pkg/mathspec
 [`microtype`]: https://ctan.org/pkg/microtype
+[`multirow`]: https://ctan.org/pkg/multirow
 [`natbib`]: https://ctan.org/pkg/natbib
 [`parskip`]: https://ctan.org/pkg/parskip
 [`polyglossia`]: https://ctan.org/pkg/polyglossia
@@ -3419,7 +3419,7 @@
 ### Variables for Typst
 
 `template`
-:   Typst template to use.
+:   Typst template to use (relative path only).
 
 `margin`
 :   A dictionary with the fields defined in the Typst documentation:
@@ -4926,6 +4926,14 @@
 you'll need to add colons as above.
 
 [PHP Markdown Extra tables]: https://michelf.ca/projects/php-markdown/extra/#table
+
+### Extension: `table_attributes` ###
+
+Attributes may be attached to tables by including them at the end
+of the caption. (For the syntax, see
+[`header_attributes`][Extension: `header_attributes`].)
+
+      : Here's the caption. {#ident .class key="value"}
 
 ## Metadata blocks
 
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,5 +1,43 @@
 # Revision history for pandoc
 
+## pandoc 3.8.2 (2025-10-05)
+
+  * Markdown reader/writer: implement new `table_attributes` extension
+    (#10884). When `table_attributes` is enabled (as it is by default for
+    pandoc's Markdown), attributes can be attached to a table by
+    including them at the end of the caption. Previously the writer
+    would emit an identifier in this position, but the reader didn't
+    handle it. Now arbitrary attributes are allowed, and they work in
+    both the reader and writer.
+
+   * Typst writer: don't add superfluous semicolons (#11196).
+    Previously we added semicolons after inline commands not
+    followed by spaces, but mainly this was to deal with one issue:
+    the presence of a semicolon after an inline command, which
+    would be swallowed as a command separator (#9252).
+    This commits adopts an approach that should avoid so many
+    superfluous semicolons: it escapes semicolons that might come
+    right after a command.
+
+  * Typst template: fix 3.8 regression in which links disappear
+    (#11194). A template change in 3.8 added a show rule for links which
+    causes them to disappear except in special cases.
+
+  * Text.Pandoc.Parsing: rewrite `oneOfStrings` more efficiently.
+
+  * LaTeX writer: Fix strikeout in links (#11192, Tuong Nguyen Manh).
+    As in #1294 `\url` and `\href` need to be protected
+    inside an mbox for `soul` commands.
+
+  * Text.Pandoc.Extensions: Add `Ext_table_attributes` constructor for
+    `Extension` [API change].
+
+  * Use released texmath 0.13.0.1.
+
+  * Update FSF contact information in COPYING (#11183, Bensun Muite).
+
+  * MANUAL.txt: remove some redundancy (#11178, Reuben Thomas).
+
 ## pandoc 3.8.1 (2025-09-29)
 
   * New output format `vimdoc` (Vim documentation format) (#11132, reptee).
@@ -4283,7 +4321,7 @@
       image. The first `!` of image markup must now be followed by a
       non-space character; otherwise, the enclosed text is parsed as
       normal content.
-    
+
   * Ms writer:
 
     + Fix handling of Figure (#8660).
@@ -4391,7 +4429,7 @@
     Krewinkel). The table foot is made part of the table body, as
     otherwise it won't show up in the output. The root cause for
     this is that longtable cannot detect page breaks in Beamer.
-    
+
   * LaTeX template: Add CJKsansfont and CJKmonofont for XeLaTeX
     (#8656, Yudong Jin). `CJKsansfont` and `CJKmonofont` will be
     set for xelatex only if `CJKmainfont` is also provided.
diff --git a/data/templates/template.typst b/data/templates/template.typst
--- a/data/templates/template.typst
+++ b/data/templates/template.typst
@@ -67,6 +67,8 @@
   show link: this => {
     if filecolor != none and type(this.dest) == label {
       text(this, fill: rgb(content-to-string(filecolor)))
+    } else {
+      text(this)
     }
   }
 
diff --git a/pandoc.cabal b/pandoc.cabal
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,6 +1,6 @@
 cabal-version:   2.4
 name:            pandoc
-version:         3.8.1
+version:         3.8.2
 build-type:      Simple
 license:         GPL-2.0-or-later
 license-file:    COPYING.md
@@ -544,7 +544,7 @@
                  syb                   >= 0.1      && < 0.8,
                  tagsoup               >= 0.14.6   && < 0.15,
                  temporary             >= 1.1      && < 1.4,
-                 texmath               >= 0.13     && < 0.14,
+                 texmath               >= 0.13.0.1 && < 0.14,
                  text                  >= 1.1.1.0  && < 2.2,
                  text-conversions      >= 0.3      && < 0.4,
                  time                  >= 1.5      && < 1.16,
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -84,6 +84,7 @@
     | Ext_gutenberg           -- ^ Use Project Gutenberg conventions for plain
     | Ext_hard_line_breaks    -- ^ All newlines become hard line breaks
     | Ext_header_attributes   -- ^ Explicit header attributes {#id .class k=v}
+    | Ext_table_attributes    -- ^ Explicit table attributes after caption
     | Ext_ignore_line_breaks  -- ^ Newlines in paragraphs are ignored
     | Ext_implicit_figures    -- ^ A paragraph with just an image is a figure
     | Ext_implicit_header_references -- ^ Implicit reference links for headers
@@ -253,6 +254,7 @@
   , Ext_task_lists
   , Ext_auto_identifiers
   , Ext_header_attributes
+  , Ext_table_attributes
   , Ext_link_attributes
   , Ext_implicit_header_references
   , Ext_line_blocks
diff --git a/src/Text/Pandoc/Parsing/General.hs b/src/Text/Pandoc/Parsing/General.hs
--- a/src/Text/Pandoc/Parsing/General.hs
+++ b/src/Text/Pandoc/Parsing/General.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE BangPatterns               #-}
 {-# LANGUAGE FlexibleContexts           #-}
 {-# LANGUAGE OverloadedStrings          #-}
 {- |
@@ -86,6 +87,8 @@
 import Data.Ord (Down(..))
 import Data.Maybe (fromMaybe)
 import Data.Text (Text)
+import qualified Data.Text.Lazy.Builder as TB
+import qualified Data.Text.Lazy as TL
 import Text.Pandoc.Asciify (toAsciiText)
 import Text.Pandoc.Builder (Attr, Inline(Str), Inlines, trimInlines)
 import Text.Pandoc.Class.PandocMonad (PandocMonad, readFileFromDirs, report)
@@ -278,22 +281,20 @@
 -- (This version due to Andrew Pimlott on the Haskell mailing list.)
 
 oneOfStrings' :: (Stream s m Char, UpdateSourcePos s Char)
-              => (Char -> Char -> Bool) -> [Text] -> ParsecT s st m Text
-oneOfStrings' f = fmap T.pack . oneOfStrings'' f . fmap T.unpack
-
--- TODO: This should be re-implemented in a Text-aware way
-oneOfStrings'' :: (Stream s m Char, UpdateSourcePos s Char)
-               => (Char -> Char -> Bool) -> [String] -> ParsecT s st m String
-oneOfStrings'' _ []   = Prelude.fail "no strings"
-oneOfStrings'' matches strs = try $ do
-  c <- anyChar
-  let strs' = [xs | (x:xs) <- strs, x `matches` c]
-  case strs' of
+               => (Char -> Char -> Bool) -> [Text] -> ParsecT s st m Text
+oneOfStrings' _ [] = Prelude.fail "no strings to match"
+oneOfStrings' matches strs =
+  TL.toStrict . TB.toLazyText <$> try (go (TB.fromText mempty) strs)
+ where
+   go acc strs' = do
+     c <- anyChar
+     let strs'' = [t | Just (d, t) <- map T.uncons strs', matches c d]
+     let !acc' = acc <> TB.singleton c
+     case strs'' of
        []  -> Prelude.fail "not found"
-       _   -> (c:) <$> oneOfStrings'' matches strs'
-               <|> if "" `elem` strs'
-                      then return [c]
-                      else Prelude.fail "not found"
+       _   -> if any T.null strs''
+                 then option acc' (try (go acc' strs''))
+                 else go acc' strs''
 
 -- | Parses one of a list of strings.  If the list contains
 -- two strings one of which is a prefix of the other, the longer
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -22,7 +22,7 @@
 
 import Control.Monad
 import Control.Monad.Except (throwError)
-import Data.Bifunctor (second)
+import qualified Data.Bifunctor as Bifunctor
 import Data.Char (isAlphaNum, isPunctuation, isSpace)
 import Data.List (transpose, elemIndex, sortOn, foldl')
 import qualified Data.Map as M
@@ -1305,14 +1305,19 @@
 
 -- Parses a table caption:  inlines beginning with 'Table:'
 -- and followed by blank lines.
-tableCaption :: PandocMonad m => MarkdownParser m (F Inlines)
+tableCaption :: PandocMonad m => MarkdownParser m (F Inlines, Attr)
 tableCaption = do
   guardEnabled Ext_table_captions
   try $ do
     skipNonindentSpaces
     (string ":" <* notFollowedBy (satisfy isPunctuation)) <|>
       (oneOf ['T','t'] >> string "able:")
-    trimInlinesF <$> inlines1 <* blanklines
+    let attributes' = guardEnabled Ext_table_attributes *> attributes
+    ils <- trimInlinesF . mconcat <$>
+               many (notFollowedBy (attributes' *> blanklines) *> inline)
+    attr <- option nullAttr attributes'
+    blanklines
+    pure (ils, attr)
 
 -- Parse a simple table with '---' header and one line per row.
 simpleTable :: PandocMonad m
@@ -1326,7 +1331,8 @@
               (if headless then tableFooter else tableFooter <|> blanklines')
   -- All columns in simple tables have default widths.
   let useDefaultColumnWidths tc =
-        let cs' = map (second (const ColWidthDefault)) $ tableColSpecs tc
+        let cs' = map (Bifunctor.second (const ColWidthDefault)) $
+                   tableColSpecs tc
         in tc {tableColSpecs = cs'}
   return $ useDefaultColumnWidths <$> tableComponents
 
@@ -1476,7 +1482,8 @@
 
 table :: PandocMonad m => MarkdownParser m (F Blocks)
 table = try $ do
-  frontCaption <- option Nothing (Just <$> tableCaption)
+  (frontCaption, frontAttr) <- option (Nothing, nullAttr)
+                               (Bifunctor.first Just <$> tableCaption)
   tableComponents <-
          (guardEnabled Ext_pipe_tables >> try (scanForPipe >> pipeTable)) <|>
          (guardEnabled Ext_multiline_tables >> try (multilineTable False)) <|>
@@ -1487,13 +1494,14 @@
          (guardEnabled Ext_grid_tables >>
                 try gridTable) <?> "table"
   optional blanklines
-  caption <- case frontCaption of
-                  Nothing -> option (return mempty) tableCaption
-                  Just c  -> return c
+  (caption, attr) <- case frontCaption of
+                        Nothing -> option (return mempty, nullAttr) tableCaption
+                        Just c  -> return (c, frontAttr)
   return $ do
     caption' <- caption
     (TableComponents _attr _capt colspecs th tb tf) <- tableComponents
-    return $ B.table (B.simpleCaption $ B.plain caption') colspecs th tb tf
+    return $ B.tableWith attr
+                (B.simpleCaption $ B.plain caption') colspecs th tb tf
 
 --
 -- inline
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -1120,23 +1120,25 @@
                      then "\\hyperlink" <> braces (literal lab) <> braces contents
                      else "\\hyperref" <> brackets (literal lab) <> braces contents
      _ -> case txt of
+          -- For soul sommands we need to protect \url and \href in an mbox or
+          -- we get an error (see #9366)
           [Str x] | T.all isAscii x  -- see #8802
                   , unEscapeString (T.unpack x) ==
                     unEscapeString (T.unpack src) ->  -- autolink
                do modify $ \s -> s{ stUrl = True }
                   src' <- stringToLaTeX URLString (escapeURI src)
-                  return $ literal $ "\\url{" <> src' <> "}"
+                  protectInMboxIfInSoul $ literal $ "\\url{" <> src' <> "}"
           [Str x] | Just rest <- T.stripPrefix "mailto:" src,
                     unEscapeString (T.unpack x) == unEscapeString (T.unpack rest) -> -- email autolink
                do modify $ \s -> s{ stUrl = True }
                   src' <- stringToLaTeX URLString (escapeURI src)
                   contents <- inlineListToLaTeX txt
-                  return $ "\\href" <> braces (literal src') <>
+                  protectInMboxIfInSoul $ "\\href" <> braces (literal src') <>
                      braces ("\\nolinkurl" <> braces contents)
           _ -> do contents <- inlineListToLaTeX txt
                   src' <- stringToLaTeX URLString (escapeURI src)
-                  return $ literal ("\\href{" <> src' <> "}{") <>
-                           contents <> char '}')
+                  protectInMboxIfInSoul $ literal ("\\href{" <> src' <> "}{") <>
+                    contents <> char '}')
      >>= (if T.null id'
              then return
              else \x -> do
@@ -1268,6 +1270,15 @@
   result <- pa
   modify $ \st -> st{ stInSoulCommand = oldInSoulCommand }
   pure result
+
+-- Inside soul commands some commands need to be protected in an mbox
+-- or we get an error (e.g. see #1294)
+protectInMboxIfInSoul :: (PandocMonad m, HasChars a) => Doc a -> LW m (Doc a)
+protectInMboxIfInSoul command = do
+  inSoul <- gets stInSoulCommand
+  return $ if inSoul
+    then "\\mbox" <> braces command
+    else command
 
 -- Babel languages with a .ldf that works well with all engines (see #8283).
 -- We follow the guidance from the Babel documentation:
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -607,7 +607,7 @@
         | otherwise            = "> "
   contents <- blockListToMarkdown opts blocks
   return $ text leader <> prefixed leader contents <> blankline
-blockToMarkdown' opts t@(Table (ident,_,_) blkCapt specs thead tbody tfoot) = do
+blockToMarkdown' opts t@(Table attr blkCapt specs thead tbody tfoot) = do
   let (caption, aligns, widths, headers, rows) = toLegacyTable blkCapt specs thead tbody tfoot
   let isColRowSpans (Cell _ _ rs cs _) = rs > 1 || cs > 1
   let rowHasColRowSpans (Row _ cs) = any isColRowSpans cs
@@ -621,9 +621,9 @@
   let numcols = maximum (length aligns :| length widths :
                            map length (headers:rows))
   caption' <- inlineListToMarkdown opts caption
-  let caption'' = if T.null ident
+  let caption'' = if attr == nullAttr
                      then caption'
-                     else caption' <+> attrsToMarkdown opts (ident,[],[])
+                     else caption' <+> attrsToMarkdown opts attr
   let caption'''
         | null caption = blankline
         | isEnabled Ext_table_captions opts
diff --git a/src/Text/Pandoc/Writers/Typst.hs b/src/Text/Pandoc/Writers/Typst.hs
--- a/src/Text/Pandoc/Writers/Typst.hs
+++ b/src/Text/Pandoc/Writers/Typst.hs
@@ -443,9 +443,8 @@
             case cls of
               (lang:_) | writerHighlightMethod opts /= NoHighlighting
                        -> "#raw(lang:" <> doubleQuoted lang <>
-                              ", " <> doubleQuoted code <> ")" <> endCode
+                              ", " <> doubleQuoted code <> ")"
               _ | T.any (=='`') code -> "#raw(" <> doubleQuoted code <> ")"
-                                           <> endCode
                 | otherwise -> "`" <> literal code <> "`"
       case writerHighlightMethod opts of
         Skylighting _ ->
@@ -503,7 +502,6 @@
           -> if T.all isIdentChar ident
                 then pure $ literal $ "@" <> ident
                 else pure $ "#ref" <> parens (toLabel ArgumentLabel ident)
-                            <> endCode
         _ -> do
           contents <- inlinesToTypst inlines
           let dest = case T.uncons src of
@@ -512,13 +510,13 @@
           pure $ "#link" <> parens dest <>
                     (if inlines == [Str src]
                           then mempty
-                          else nowrap $ brackets contents) <> endCode
+                          else nowrap $ brackets contents)
     Image attr _inlines (src,_tit) -> do
       opts <-  gets stOptions
       pure $ mkImage opts True src attr
     Note blocks -> do
       contents <- blocksToTypst blocks
-      return $ "#footnote" <> brackets (chomp contents) <> endCode
+      return $ "#footnote" <> brackets (chomp contents)
 
 -- see #9104; need box or image is treated as block-level
 mkImage :: WriterOptions -> Bool -> Text -> Attr -> Doc Text
@@ -544,7 +542,7 @@
 
 textstyle :: PandocMonad m => Doc Text -> [Inline] -> TW m (Doc Text)
 textstyle s inlines = do
-  (<> endCode) . (s <>) . brackets . fixInitialAfterBreakEscape
+  (s <>) . brackets . fixInitialAfterBreakEscape
     <$> inlinesToTypst inlines
 
 fixInitialAfterBreakEscape :: Doc Text -> Doc Text
@@ -564,6 +562,7 @@
 escapeTypst smart context t =
   (case T.uncons t of
     Just (c, _)
+      | c == ';' -> char '\\' -- see #9252
       | needsEscapeAtLineStart c || isOrderedListMarker t
         -> afterBreak "\\"
     _ -> mempty) <>
@@ -654,7 +653,7 @@
        pure $ (if citationMode cite == SuppressAuthor  -- see #11044
                   then parens
                   else id)
-            $ "#cite" <> parens (label <> form <> suppl) <> endCode
+            $ "#cite" <> parens (label <> form <> suppl)
 
 doubleQuoted :: Text -> Doc Text
 doubleQuoted = doubleQuotes . literal . escape
@@ -663,9 +662,6 @@
   escapeChar '\\' = "\\\\"
   escapeChar '"' = "\\\""
   escapeChar c = T.singleton c
-
-endCode :: Doc Text
-endCode = beforeNonBlank ";"
 
 extractLabel :: Text -> Maybe Text
 extractLabel = go . T.unpack
diff --git a/test/command/10884.md b/test/command/10884.md
new file mode 100644
--- /dev/null
+++ b/test/command/10884.md
@@ -0,0 +1,17 @@
+```
+% pandoc -f markdown -t markdown
+  header1   header2
+  --------- ---------
+  r1c1      r1c2
+  r2c1      r2c2
+
+  : mycaption {#myid .myclass key="value"}
+^D
+  header1   header2
+  --------- ---------
+  r1c1      r1c2
+  r2c1      r2c2
+
+  : mycaption {#myid .myclass key="value"}
+
+```
diff --git a/test/command/9366.md b/test/command/9366.md
new file mode 100644
--- /dev/null
+++ b/test/command/9366.md
@@ -0,0 +1,34 @@
+```
+% pandoc -f native -t latex
+[ Para
+    [ Strikeout
+        [ Link
+            ( "" , [] , [] )
+            [ Str "Example" ]
+            ( "https://example.com" , "" )
+        ]
+    ]
+, Para
+    [ Strikeout
+        [ Link
+            ( "" , [] , [] )
+            [ Str "https://example.com" ]
+            ( "https://example.com" , "" )
+        ]
+    ]
+, Para
+    [ Strikeout
+        [ Link
+            ( "" , [] , [] )
+            [ Str "info@example.com" ]
+            ( "mailto:info@example.com" , "" )
+        ]
+    ]
+]
+^D
+\st{\mbox{\href{https://example.com}{Example}}}
+
+\st{\mbox{\url{https://example.com}}}
+
+\st{\mbox{\href{mailto:info@example.com}{\nolinkurl{info@example.com}}}}
+```
diff --git a/test/command/9387.md b/test/command/9387.md
--- a/test/command/9387.md
+++ b/test/command/9387.md
@@ -9,7 +9,7 @@
 test
 
 ] #label("my label")
-See #link(label("my label"))[my label];.
+See #link(label("my label"))[my label].
 
 ```
 
diff --git a/test/command/9452.md b/test/command/9452.md
--- a/test/command/9452.md
+++ b/test/command/9452.md
@@ -14,6 +14,6 @@
 
 With supplement @something2024[p.~3].
 
-And just the year (#cite(<something2024>, form: "year");).
+And just the year (#cite(<something2024>, form: "year")).
 
 ```
diff --git a/test/tables/nordics.markdown b/test/tables/nordics.markdown
--- a/test/tables/nordics.markdown
+++ b/test/tables/nordics.markdown
@@ -15,4 +15,4 @@
            Total                                  27,376,022      1,258,336
   -------------------------------------------------------------------------------
 
-  : States belonging to the *Nordics.* {#nordics}
+  : States belonging to the *Nordics.* {#nordics source="wikipedia"}
diff --git a/test/tables/nordics.typst b/test/tables/nordics.typst
--- a/test/tables/nordics.typst
+++ b/test/tables/nordics.typst
@@ -5,7 +5,7 @@
     table.header(table.cell(align: center)[Name], table.cell(align: center)[Capital], table.cell(align: center)[Population
       \
       (in 2018)], table.cell(align: center)[Area \
-      (in km#super[2];)],),
+      (in km#super[2])],),
     table.hline(),
     [Denmark], [Copenhagen], [5,809,502], [43,094],
     [Finland], [Helsinki], [5,537,364], [338,145],
diff --git a/test/tables/students.markdown b/test/tables/students.markdown
--- a/test/tables/students.markdown
+++ b/test/tables/students.markdown
@@ -20,4 +20,4 @@
 | 4100332                                 | Toyota, Hiroko                          |
 +-----------------------------------------+-----------------------------------------+
 
-: List of Students {#students}
+: List of Students {#students source="mdn"}
diff --git a/test/writer.typst b/test/writer.typst
--- a/test/writer.typst
+++ b/test/writer.typst
@@ -91,6 +91,8 @@
   show link: this => {
     if filecolor != none and type(this.dest) == label {
       text(this, fill: rgb(content-to-string(filecolor)))
+    } else {
+      text(this)
     }
   }
 
@@ -488,13 +490,13 @@
 
 Multiple blocks with italics:
 
-/ #emph[apple];: #block[
+/ #emph[apple]: #block[
 red fruit
 
 contains seeds, crisp, pleasant to taste
 ]
 
-/ #emph[orange];: #block[
+/ #emph[orange]: #block[
 orange fruit
 
 ```
@@ -626,27 +628,27 @@
 
 = Inline Markup
 <inline-markup>
-This is #emph[emphasized];, and so #emph[is this];.
+This is #emph[emphasized], and so #emph[is this].
 
-This is #strong[strong];, and so #strong[is this];.
+This is #strong[strong], and so #strong[is this].
 
-An #emph[#link("/url")[emphasized link];];.
+An #emph[#link("/url")[emphasized link]].
 
-#strong[#emph[This is strong and em.];]
+#strong[#emph[This is strong and em.]]
 
-So is #strong[#emph[this];] word.
+So is #strong[#emph[this]] word.
 
-#strong[#emph[This is strong and em.];]
+#strong[#emph[This is strong and em.]]
 
-So is #strong[#emph[this];] word.
+So is #strong[#emph[this]] word.
 
 This is code: `>`, `$`, `\`, `\$`, `<html>`.
 
-#strike[This is #emph[strikeout];.]
+#strike[This is #emph[strikeout].]
 
-Superscripts: a#super[bc];d a#super[#emph[hello];] a#super[hello~there];.
+Superscripts: a#super[bc]d a#super[#emph[hello]] a#super[hello~there].
 
-Subscripts: H#sub[2];O, H#sub[23];O, H#sub[many~of~them];O.
+Subscripts: H#sub[2]O, H#sub[23]O, H#sub[many~of~them]O.
 
 These should not be superscripts or subscripts, because of the unescaped spaces:
 a^b c^d, a\~b c\~d.
@@ -664,7 +666,7 @@
 'He said, "I want to go."' Were you alive in the 70's?
 
 Here is some quoted '`code`' and a
-"#link("http://example.com/?foo=1&bar=2")[quoted link];".
+"#link("http://example.com/?foo=1&bar=2")[quoted link]".
 
 Some dashes: one---two --- three---four --- five.
 
@@ -756,13 +758,13 @@
 <links>
 == Explicit
 <explicit>
-Just a #link("/url/")[URL];.
+Just a #link("/url/")[URL].
 
-#link("/url/")[URL and title];.
+#link("/url/")[URL and title].
 
-#link("/url/")[URL and title];.
+#link("/url/")[URL and title].
 
-#link("/url/")[URL and title];.
+#link("/url/")[URL and title].
 
 #link("/url/")[URL and title]
 
@@ -772,21 +774,21 @@
 
 #link("mailto:nobody@nowhere.net")[Email link]
 
-#link("")[Empty];.
+#link("")[Empty].
 
 == Reference
 <reference>
-Foo #link("/url/")[bar];.
+Foo #link("/url/")[bar].
 
-With #link("/url/")[embedded \[brackets\]];.
+With #link("/url/")[embedded \[brackets\]].
 
 #link("/url/")[b] by itself should be a link.
 
-Indented #link("/url")[once];.
+Indented #link("/url")[once].
 
-Indented #link("/url")[twice];.
+Indented #link("/url")[twice].
 
-Indented #link("/url")[thrice];.
+Indented #link("/url")[thrice].
 
 This should \[not\]\[\] be a link.
 
@@ -794,20 +796,20 @@
 [not]: /url
 ```
 
-Foo #link("/url/")[bar];.
+Foo #link("/url/")[bar].
 
-Foo #link("/url/")[biz];.
+Foo #link("/url/")[biz].
 
 == With ampersands
 <with-ampersands>
 Here's a
-#link("http://example.com/?foo=1&bar=2")[link with an ampersand in the URL];.
+#link("http://example.com/?foo=1&bar=2")[link with an ampersand in the URL].
 
-Here's a link with an amersand in the link text: #link("http://att.com/")[AT&T];.
+Here's a link with an amersand in the link text: #link("http://att.com/")[AT&T].
 
-Here's an #link("/script?foo=1&bar=2")[inline link];.
+Here's an #link("/script?foo=1&bar=2")[inline link].
 
-Here's an #link("/script?foo=1&bar=2")[inline link in pointy braces];.
+Here's an #link("/script?foo=1&bar=2")[inline link in pointy braces].
 
 == Autolinks
 <autolinks>
