From b41d5b090be6081f8e2b5729ba879be29db806c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 May 2025 17:15:37 +0200 Subject: [PATCH 01/17] Preserve HTML entities in headers Closes #2114. Closes #2120. --- lib/ex_doc/doc_ast.ex | 12 +++++ lib/ex_doc/formatter/html.ex | 8 +++- lib/ex_doc/formatter/html/templates.ex | 22 ++++------ test/ex_doc/doc_ast_test.exs | 25 +++++++++++ test/ex_doc/formatter/html/templates_test.exs | 44 ------------------- test/ex_doc/formatter/html_test.exs | 4 +- 6 files changed, 54 insertions(+), 61 deletions(-) diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex index fdd5087a1..f8ee57539 100644 --- a/lib/ex_doc/doc_ast.ex +++ b/lib/ex_doc/doc_ast.ex @@ -110,6 +110,18 @@ defmodule ExDoc.DocAST do def extract_title([{:h1, _attrs, inner, _meta} | ast]), do: {:ok, inner, ast} def extract_title(_ast), do: :error + @doc """ + Extracts headers (h2) from the given AST. + + Returns the header text. + """ + def extract_headers(doc_ast) do + for {:h2, _, _, _} = node <- doc_ast, + text = ExDoc.DocAST.text(node), + text != "", + do: text + end + @doc """ Compute a synopsis from a document by looking at its first paragraph. """ diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 9620d312c..9d76acaa3 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -320,7 +320,10 @@ defmodule ExDoc.Formatter.HTML do source_path: nil, source_url: config.source_url, title: "API Reference", - title_content: title_content + title_content: title_content, + headers: + if(nodes_map.modules != [], do: ["Modules"], else: []) ++ + if(nodes_map.tasks != [], do: ["Mix Tasks"], else: []) } end @@ -456,7 +459,8 @@ defmodule ExDoc.Formatter.HTML do source_url: source_url, search_data: search_data, title: title, - title_content: title_html || title + title_content: title_html || title, + headers: ExDoc.DocAST.extract_headers(ast) } end diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index f6805f203..837cb0d0f 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -59,7 +59,6 @@ defmodule ExDoc.Formatter.HTML.Templates do defp sidebar_extras(extras) do for extra <- extras do %{id: id, title: title, group: group} = extra - item = %{id: to_string(id), title: to_string(title), group: to_string(group)} case extra do @@ -74,14 +73,14 @@ defmodule ExDoc.Formatter.HTML.Templates do end) item - |> Map.put(:headers, extract_headers(extra.content)) + |> Map.put(:headers, headers_to_id_and_anchors(extra.headers)) |> Map.put(:searchData, search_data) %{url: url} when is_binary(url) -> Map.put(item, :url, url) _ -> - Map.put(item, :headers, extract_headers(extra.content)) + Map.put(item, :headers, headers_to_id_and_anchors(extra.headers)) end end end @@ -140,8 +139,9 @@ defmodule ExDoc.Formatter.HTML.Templates do defp module_sections(module) do {sections, _} = - module.rendered_doc - |> extract_headers() + module.doc + |> ExDoc.DocAST.extract_headers() + |> headers_to_id_and_anchors() |> Enum.map_reduce(%{}, fn header, acc -> # TODO Duplicates some of the logic of link_headings/3 case Map.fetch(acc, header.id) do @@ -156,14 +156,10 @@ defmodule ExDoc.Formatter.HTML.Templates do [sections: sections] end - # TODO: split into sections in Formatter.HTML instead (possibly via DocAST) - defp extract_headers(content) do - ~r/(.*?)<\/h2>/m - |> Regex.scan(content, capture: :all_but_first) - |> List.flatten() - |> Enum.filter(&(&1 != "")) - |> Enum.map(&ExDoc.Utils.strip_tags/1) - |> Enum.map(&%{id: &1, anchor: URI.encode(text_to_id(&1))}) + defp headers_to_id_and_anchors(headers) do + Enum.map(headers, fn text -> + %{id: text, anchor: URI.encode(text_to_id(text))} + end) end def module_summary(module_node) do diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index fe8186088..113329745 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -150,6 +150,31 @@ defmodule ExDoc.DocASTTest do end end + describe "extract_headers" do + test "extracts h2 headers" do + assert extract_headers(""" + # h1 + ## h2-a + ### h3 + ## h2-b + ## + """) == ["h2-a", "h2-b"] + end + + test "trims whitespace and preserve HTML entities" do + assert extract_headers(""" + # h1 + ##\s\s\sh2\s<&>\sh2\s\s\s + """) == ["h2 <&> h2"] + end + + defp extract_headers(markdown) do + markdown + |> ExDoc.DocAST.parse!("text/markdown") + |> ExDoc.DocAST.extract_headers() + end + end + describe "highlight" do test "with default class" do # Empty class diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index f13e21260..1d1bd6872 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -324,50 +324,6 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do ] = create_sidebar_items(%{modules: nodes}, [])["modules"] end - test "outputs extras with headers" do - item = %{content: nil, group: nil, id: nil, title: nil} - - assert create_sidebar_items(%{}, [%{item | content: "

Foo

Bar

"}])["extras"] == - [ - %{ - "group" => "", - "headers" => [ - %{"anchor" => "foo", "id" => "Foo"}, - %{"anchor" => "bar", "id" => "Bar"} - ], - "id" => "", - "title" => "" - } - ] - - assert create_sidebar_items(%{}, [%{item | content: "

Foo

\n

Bar

"}])[ - "extras" - ] == - [ - %{ - "group" => "", - "headers" => [ - %{"anchor" => "foo", "id" => "Foo"}, - %{"anchor" => "bar", "id" => "Bar"} - ], - "id" => "", - "title" => "" - } - ] - - assert create_sidebar_items(%{}, [%{item | content: "

Foo

"}])["extras"] == - [ - %{ - "group" => "", - "headers" => [ - %{"anchor" => "foo", "id" => "Foo"} - ], - "id" => "", - "title" => "" - } - ] - end - test "builds sections out of moduledocs", context do names = [CompiledWithDocs, CompiledWithoutDocs, DuplicateHeadings] config = doc_config(context) diff --git a/test/ex_doc/formatter/html_test.exs b/test/ex_doc/formatter/html_test.exs index af21cb9aa..15e928ab9 100644 --- a/test/ex_doc/formatter/html_test.exs +++ b/test/ex_doc/formatter/html_test.exs @@ -617,7 +617,7 @@ defmodule ExDoc.Formatter.HTMLTest do "headers" => [ %{"anchor" => "heading-without-content", "id" => "Heading without content"}, %{"anchor" => "header-sample", "id" => "Header sample"}, - %{"anchor" => "more-than", "id" => "more > than"} + %{"anchor" => "more-than", "id" => "more > than"} ] }, %{"id" => "livebookfile"}, @@ -768,7 +768,7 @@ defmodule ExDoc.Formatter.HTMLTest do "headers" => [ %{"anchor" => "heading-without-content", "id" => "Heading without content"}, %{"anchor" => "header-sample", "id" => "Header sample"}, - %{"anchor" => "more-than", "id" => "more > than"} + %{"anchor" => "more-than", "id" => "more > than"} ] } ] = Jason.decode!(content)["extras"] From 0be766e5359b6bad7fbb716385e73f18e858eabc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 May 2025 17:18:29 +0200 Subject: [PATCH 02/17] Add more tests --- test/ex_doc/doc_ast_test.exs | 2 +- test/ex_doc/formatter/html/templates_test.exs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index 113329745..26113110a 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -164,7 +164,7 @@ defmodule ExDoc.DocASTTest do test "trims whitespace and preserve HTML entities" do assert extract_headers(""" # h1 - ##\s\s\sh2\s<&>\sh2\s\s\s + ##\s\s\s**h2**\s<&>\s`h2`\s\s\s """) == ["h2 <&> h2"] end diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index 1d1bd6872..dabfed5f7 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -336,7 +336,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do assert compiled_with_docs["sections"] == [ %{ "anchor" => "module-example-unicode-escaping", - "id" => "Example ☃ Unicode > escaping" + "id" => "Example ☃ Unicode > escaping" } ] From 91c3304f54ee05281935606f1b481d71e6158113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 7 May 2025 17:33:45 +0200 Subject: [PATCH 03/17] Avoid unnecessary work --- lib/ex_doc/formatter/html/search_data.ex | 2 ++ lib/ex_doc/formatter/html/templates.ex | 6 ++---- lib/ex_doc/utils.ex | 1 - test/ex_doc/utils_test.exs | 1 - 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/ex_doc/formatter/html/search_data.ex b/lib/ex_doc/formatter/html/search_data.ex index 2bc2e0273..b721dd818 100644 --- a/lib/ex_doc/formatter/html/search_data.ex +++ b/lib/ex_doc/formatter/html/search_data.ex @@ -58,6 +58,7 @@ defmodule ExDoc.Formatter.HTML.SearchData do end defp module(%ExDoc.ModuleNode{} = node) do + # TODO: This should work on DocAST {intro, sections} = extract_sections(node.doc_format, node) module = @@ -132,6 +133,7 @@ defmodule ExDoc.Formatter.HTML.SearchData do {"", []} end + # TODO: This should work on DocAST when we prebuild extra. defp extract_sections_from_markdown(string) do [intro | sections] = Regex.split(~r/(?\b.+)/, string, include_captures: true) diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index 837cb0d0f..63515071d 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -184,9 +184,7 @@ defmodule ExDoc.Formatter.HTML.Templates do defp sidebar_type(:livemd), do: "extras" defp sidebar_type(:extra), do: "extras" - # TODO: Move link_headings and friends to html.ex (possibly via DocAST) - # or even to autolinking code, so content is built with it upfront instead - # of added at the template level. + # TODO: Adding the link headings must be done via DocAST instead of using regexes. @doc """ Add link headings for the given `content`. @@ -203,7 +201,7 @@ defmodule ExDoc.Formatter.HTML.Templates do ~r/<(h[23]).*?>(.*?)<\/\1>/m |> Regex.scan(content) |> Enum.reduce({content, %{}}, fn [match, tag, title], {content, occurrences} -> - possible_id = text_to_id(title) + possible_id = title |> ExDoc.Utils.strip_tags() |> text_to_id() id_occurred = Map.get(occurrences, possible_id, 0) anchor_id = if id_occurred >= 1, do: "#{possible_id}-#{id_occurred}", else: possible_id diff --git a/lib/ex_doc/utils.ex b/lib/ex_doc/utils.ex index 518d3c276..7ee73188b 100644 --- a/lib/ex_doc/utils.ex +++ b/lib/ex_doc/utils.ex @@ -102,7 +102,6 @@ defmodule ExDoc.Utils do def text_to_id(text) when is_binary(text) do text - |> strip_tags() |> String.replace(~r/&#\d+;/, "") |> String.replace(~r/&[A-Za-z0-9]+;/, "") |> String.replace(~r/\W+/u, "-") diff --git a/test/ex_doc/utils_test.exs b/test/ex_doc/utils_test.exs index caf7cb7eb..a65f74649 100644 --- a/test/ex_doc/utils_test.exs +++ b/test/ex_doc/utils_test.exs @@ -100,6 +100,5 @@ defmodule ExDoc.UtilsTest do assert Utils.text_to_id(" ☃ ") == "" assert Utils.text_to_id(" ² ") == "" assert Utils.text_to_id(" ⏜ ") == "" - assert Utils.text_to_id("Git opts (:git)") == "git-opts-git" end end From d9d8fffe4987705f304a8de127b34691a2c35359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 11:21:57 +0200 Subject: [PATCH 04/17] Explicitly pass headers as arguments --- lib/ex_doc/doc_ast.ex | 29 ++++++++++++++------------ lib/ex_doc/formatter/html.ex | 8 ++----- lib/ex_doc/formatter/html/templates.ex | 2 +- test/ex_doc/doc_ast_test.exs | 8 ++----- 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex index f8ee57539..f85560196 100644 --- a/lib/ex_doc/doc_ast.ex +++ b/lib/ex_doc/doc_ast.ex @@ -115,8 +115,9 @@ defmodule ExDoc.DocAST do Returns the header text. """ - def extract_headers(doc_ast) do - for {:h2, _, _, _} = node <- doc_ast, + def extract_headers(doc_ast, headers) do + for {tag, _, _, _} = node <- doc_ast, + tag in headers, text = ExDoc.DocAST.text(node), text != "", do: text @@ -168,17 +169,17 @@ defmodule ExDoc.DocAST do defp do_text({_tag, _attr, ast, _meta}), do: text(ast) @doc """ - Wraps a list of HTML nodes into `
` tags whenever `matcher` returns true. + Wraps a list of HTML nodes into `
` tags whenever `headers` returns true. """ - def sectionize(list, matcher), do: sectionize(list, matcher, []) + def sectionize(list, headers), do: sectionize(list, headers, []) - defp sectionize(list, matcher, acc) do - case pivot(list, acc, matcher) do + defp sectionize(list, headers, acc) do + case pivot(list, acc, headers) do {acc, {header_tag, header_attrs, _, _} = header, rest} -> {inner, rest} = Enum.split_while(rest, ¬_tag?(&1, header_tag)) class = String.trim_trailing("#{header_tag} #{header_attrs[:class]}") - section = {:section, [class: class], [header | sectionize(inner, matcher, [])], %{}} - sectionize(rest, matcher, [section | acc]) + section = {:section, [class: class], [header | sectionize(inner, headers, [])], %{}} + sectionize(rest, headers, [section | acc]) acc -> acc @@ -188,14 +189,16 @@ defmodule ExDoc.DocAST do defp not_tag?({tag, _, _, _}, tag), do: false defp not_tag?(_, _tag), do: true - defp pivot([head | tail], acc, fun) do - case fun.(head) do - true -> {acc, head, tail} - false -> pivot(tail, [head | acc], fun) + defp pivot([{tag, _, _, _} = head | tail], acc, headers) do + if tag in headers do + {acc, head, tail} + else + pivot(tail, [head | acc], headers) end end - defp pivot([], acc, _fun), do: Enum.reverse(acc) + defp pivot([head | tail], acc, headers), do: pivot(tail, [head | acc], headers) + defp pivot([], acc, _headers), do: Enum.reverse(acc) @doc """ Highlights a DocAST converted to string. diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 9d76acaa3..75931449f 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -460,7 +460,7 @@ defmodule ExDoc.Formatter.HTML do search_data: search_data, title: title, title_content: title_html || title, - headers: ExDoc.DocAST.extract_headers(ast) + headers: ExDoc.DocAST.extract_headers(ast, [:h2]) } end @@ -491,11 +491,7 @@ defmodule ExDoc.Formatter.HTML do end defp sectionize(ast, ".cheatmd") do - ExDoc.DocAST.sectionize(ast, fn - {:h2, _, _, _} -> true - {:h3, _, _, _} -> true - _ -> false - end) + ExDoc.DocAST.sectionize(ast, [:h2, :h3]) end defp sectionize(ast, _), do: ast diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index 63515071d..8ab6960e9 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -140,7 +140,7 @@ defmodule ExDoc.Formatter.HTML.Templates do defp module_sections(module) do {sections, _} = module.doc - |> ExDoc.DocAST.extract_headers() + |> ExDoc.DocAST.extract_headers([:h2]) |> headers_to_id_and_anchors() |> Enum.map_reduce(%{}, fn header, acc -> # TODO Duplicates some of the logic of link_headings/3 diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index 26113110a..ac1f7d318 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -171,7 +171,7 @@ defmodule ExDoc.DocASTTest do defp extract_headers(markdown) do markdown |> ExDoc.DocAST.parse!("text/markdown") - |> ExDoc.DocAST.extract_headers() + |> ExDoc.DocAST.extract_headers([:h2]) end end @@ -246,7 +246,7 @@ defmodule ExDoc.DocASTTest do {:p, [], ["p6"], %{}} ] - assert DocAST.sectionize(list, &h2_or_h3?/1) == + assert DocAST.sectionize(list, [:h2, :h3]) == [ {:h1, [], ["H1"], %{}}, {:section, [class: "h2 example"], @@ -281,9 +281,5 @@ defmodule ExDoc.DocASTTest do ], %{}} ] end - - defp h2_or_h3?({:h2, _, _, _}), do: true - defp h2_or_h3?({:h3, _, _, _}), do: true - defp h2_or_h3?(_), do: false end end From cbe35b129aa67a730a9d9948dd75db273e4df1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 11:34:22 +0200 Subject: [PATCH 05/17] Simplify and optimize to_string --- lib/ex_doc/doc_ast.ex | 35 ++++++++++++++--------------------- test/ex_doc/doc_ast_test.exs | 19 ------------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex index f85560196..7caa41f8d 100644 --- a/lib/ex_doc/doc_ast.ex +++ b/lib/ex_doc/doc_ast.ex @@ -31,35 +31,32 @@ defmodule ExDoc.DocAST do @doc """ Transform AST into string. """ - def to_string(ast, fun \\ fn _ast, string -> string end) + def to_string(binary) do + IO.iodata_to_binary(to_iodata(binary)) + end - def to_string(binary, _fun) when is_binary(binary) do + defp to_iodata(binary) when is_binary(binary) do ExDoc.Utils.h(binary) end - def to_string(list, fun) when is_list(list) do - result = Enum.map_join(list, "", &to_string(&1, fun)) - fun.(list, result) + defp to_iodata(list) when is_list(list) do + Enum.map(list, &to_iodata/1) end - def to_string({:comment, _attrs, inner, _meta} = ast, fun) do - fun.(ast, "") + defp to_iodata({:comment, _attrs, inner, _meta}) do + [""] end - def to_string({tag, attrs, _inner, _meta} = ast, fun) when tag in @void_elements do - result = "<#{tag}#{ast_attributes_to_string(attrs)}/>" - fun.(ast, result) + defp to_iodata({tag, attrs, _inner, _meta}) when tag in @void_elements do + "<#{tag}#{ast_attributes_to_string(attrs)}/>" end - def to_string({tag, attrs, inner, %{verbatim: true}} = ast, fun) do - inner = Enum.join(inner, "") - result = "<#{tag}#{ast_attributes_to_string(attrs)}>" <> inner <> "" - fun.(ast, result) + defp to_iodata({tag, attrs, inner, %{verbatim: true}}) do + ["<#{tag}#{ast_attributes_to_string(attrs)}>", inner, ""] end - def to_string({tag, attrs, inner, _meta} = ast, fun) do - result = "<#{tag}#{ast_attributes_to_string(attrs)}>" <> to_string(inner, fun) <> "" - fun.(ast, result) + defp to_iodata({tag, attrs, inner, _meta}) do + ["<#{tag}#{ast_attributes_to_string(attrs)}>", to_iodata(inner), ""] end defp ast_attributes_to_string(attrs) do @@ -200,10 +197,6 @@ defmodule ExDoc.DocAST do defp pivot([head | tail], acc, headers), do: pivot(tail, [head | acc], headers) defp pivot([], acc, _headers), do: Enum.reverse(acc) - @doc """ - Highlights a DocAST converted to string. - """ - # TODO: Could this be done over the AST instead? def highlight(html, language, opts \\ []) do highlight_info = language.highlight_info() diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index ac1f7d318..33e098622 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -83,25 +83,6 @@ defmodule ExDoc.DocASTTest do assert DocAST.to_string(ast) == ~s{\n} end - test "with fun" do - markdown = """ - foo **bar** baz - """ - - ast = DocAST.parse!(markdown, "text/markdown") - - f = fn - {:strong, _, _, _}, string -> - String.upcase(string) - - _ast, string -> - string - end - - assert DocAST.to_string(ast, f) == - "

foo BAR baz

" - end - test "void elements" do markdown = """ foo\s\s From 6961df5008db3900d0a4b4a5a203319e4a0fbf60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 11:56:36 +0200 Subject: [PATCH 06/17] Convert highlight into DocAST --- lib/ex_doc/doc_ast.ex | 81 +++++++++++++++--------------------- lib/ex_doc/formatter/html.ex | 2 +- test/ex_doc/doc_ast_test.exs | 79 +++++++++++++++++------------------ 3 files changed, 73 insertions(+), 89 deletions(-) diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex index 7caa41f8d..36e30886f 100644 --- a/lib/ex_doc/doc_ast.ex +++ b/lib/ex_doc/doc_ast.ex @@ -1,3 +1,5 @@ +import Kernel, except: [to_string: 1] + defmodule ExDoc.DocAST do # General helpers for dealing with the documentation AST # (which is the Markdown -> HTML AST). @@ -198,41 +200,58 @@ defmodule ExDoc.DocAST do defp pivot([], acc, _headers), do: Enum.reverse(acc) def highlight(html, language, opts \\ []) do - highlight_info = language.highlight_info() - - ## Html cannot be parsed with regex, but we try our best... - Regex.replace( - ~r/]*)?>([^<]*)<\/code><\/pre>/, - html, - &highlight_code_block(&1, &2, &3, &4, highlight_info, opts) - ) + do_highlight(html, language.highlight_info(), opts) end - defp highlight_code_block(full_block, pre_attr, lang, code, highlight_info, outer_opts) do + defp do_highlight( + {:pre, pre_attrs, [{:code, code_attrs, [code], code_meta}], pre_meta} = ast, + highlight_info, + opts + ) + when is_binary(code) do + {lang, code_attrs} = Keyword.pop(code_attrs, :class, "") + case pick_language_and_lexer(lang, highlight_info, code) do - {_language, nil, _opts} -> - full_block + {_lang, nil, _lexer_opts} -> + ast - {lang, lexer, opts} -> + {lang, lexer, lexer_opts} -> try do - render_code(pre_attr, lang, lexer, opts, code, outer_opts) + Makeup.highlight_inner_html(code, + lexer: lexer, + lexer_options: lexer_opts, + formatter_options: opts + ) rescue exception -> ExDoc.Utils.warn( [ "crashed while highlighting #{lang} snippet:\n\n", - full_block, + ExDoc.DocAST.to_string(ast), "\n\n", Exception.format_banner(:error, exception, __STACKTRACE__) ], __STACKTRACE__ ) - full_block + ast + else + highlighted -> + code_attrs = [class: "makeup #{lang}", translate: "no"] ++ code_attrs + code_meta = Map.put(code_meta, :verbatim, true) + {:pre, pre_attrs, [{:code, code_attrs, [highlighted], code_meta}], pre_meta} end end end + defp do_highlight(list, highlight_info, opts) when is_list(list) do + Enum.map(list, &do_highlight(&1, highlight_info, opts)) + end + + defp do_highlight(other, _highlight_info, _opts) do + other + end + defp pick_language_and_lexer("", _highlight_info, "$ " <> _) do {"shell", ExDoc.ShellLexer, []} end @@ -251,36 +270,4 @@ defmodule ExDoc.DocAST do :error -> {lang, nil, []} end end - - defp render_code(pre_attr, lang, lexer, lexer_opts, code, opts) do - highlight_tag = Keyword.get(opts, :highlight_tag, "span") - - highlighted = - code - |> unescape_html() - |> IO.iodata_to_binary() - |> Makeup.highlight_inner_html( - lexer: lexer, - lexer_options: lexer_opts, - formatter_options: [highlight_tag: highlight_tag] - ) - - ~s(#{highlighted}) - end - - entities = [{"&", ?&}, {"<", ?<}, {">", ?>}, {""", ?"}, {"'", ?'}] - - for {encoded, decoded} <- entities do - defp unescape_html(unquote(encoded) <> rest) do - [unquote(decoded) | unescape_html(rest)] - end - end - - defp unescape_html(<>) do - [c | unescape_html(rest)] - end - - defp unescape_html(<<>>) do - [] - end end diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 75931449f..51328d565 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -144,8 +144,8 @@ defmodule ExDoc.Formatter.HTML do defp autolink_and_render(doc, language, autolink_opts, opts) do doc |> language.autolink_doc(autolink_opts) - |> ExDoc.DocAST.to_string() |> ExDoc.DocAST.highlight(language, opts) + |> ExDoc.DocAST.to_string() end defp output_setup(build, config) do diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index 33e098622..73e5b6258 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -158,54 +158,51 @@ defmodule ExDoc.DocASTTest do describe "highlight" do test "with default class" do - # Empty class - assert DocAST.highlight( - ~S[
mix run --no-halt path/to/file.exs
], - ExDoc.Language.Elixir - ) =~ + # Four spaces + assert highlight(""" + mix run --no-halt path/to/file.exs + """) =~ ~r{
.*}
 
-      # Without class
-      assert DocAST.highlight(
-               "
mix run --no-halt path/to/file.exs
", - ExDoc.Language.Elixir - ) =~ + # Code block without language + assert highlight(""" + ``` + mix run --no-halt path/to/file.exs
+ ``` + """) =~ ~r{
.*}
 
-      # Pre class
-      assert DocAST.highlight(
-               ~S[
mix run --no-halt path/to/file.exs
], - ExDoc.Language.Elixir - ) =~ + # Pre IAL + assert highlight(""" + ``` + mix run --no-halt path/to/file.exs
+ ``` + {:class="wrap"} + """) =~ ~r{
.*}
 
-      # Pre id
-      assert DocAST.highlight(
-               ~S[
mix run --no-halt path/to/file.exs
], - ExDoc.Language.Elixir - ) =~ - ~r{
.*}
-
-      # Pre id and class
-      assert DocAST.highlight(
-               ~S[
mix run --no-halt path/to/file.exs
], - ExDoc.Language.Elixir - ) =~ - ~r{
.*}
-
-      # IEx highlight with empty class
-      assert DocAST.highlight(
-               ~S[
iex> max(4, 5)
], - ExDoc.Language.Elixir - ) =~ - ~r{
.*}
+      # Code with language
+      assert highlight("""
+             ```html
+             
+             ```
+             """) =~
+               ~r{
.*}
+
+      # Code with shell detection
+      assert highlight("""
+             ```
+             $ hello
+             ```
+             """) =~
+               ~r{
\$.*}
+    end
 
-      # IEx highlight without class
-      assert DocAST.highlight(
-               ~S[
iex> max(4, 5)
], - ExDoc.Language.Elixir - ) =~ - ~r{
.*}
+    defp highlight(markdown) do
+      markdown
+      |> ExDoc.DocAST.parse!("text/markdown")
+      |> ExDoc.DocAST.highlight(ExDoc.Language.Elixir)
+      |> ExDoc.DocAST.to_string()
     end
   end
 

From 8bbc037e083d397b056b02ca753c35e78d2a9360 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= 
Date: Thu, 8 May 2025 12:29:59 +0200
Subject: [PATCH 07/17] Add more DocAST helpers

---
 lib/ex_doc/doc_ast.ex        | 177 ++++++++++++++++++++++++-----------
 lib/ex_doc/formatter/html.ex |   2 +-
 test/ex_doc/doc_ast_test.exs |  96 ++++++++++++++-----
 3 files changed, 196 insertions(+), 79 deletions(-)

diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex
index 36e30886f..5648706bb 100644
--- a/lib/ex_doc/doc_ast.ex
+++ b/lib/ex_doc/doc_ast.ex
@@ -122,6 +122,43 @@ defmodule ExDoc.DocAST do
         do: text
   end
 
+  @doc """
+  Extracts the headers which have anchors (aka ids) in them.
+  """
+  def extract_headers_with_ids(ast, headers) do
+    ast
+    |> reduce_tags([], fn {tag, attrs, inner, _}, acc ->
+      with true <- tag in headers,
+           id = Keyword.get(attrs, :id, ""),
+           text = ExDoc.DocAST.text(inner),
+           true <- id != "" and text != "" do
+        [{tag, text, id} | acc]
+      else
+        _ -> acc
+      end
+    end)
+    |> Enum.reverse()
+  end
+
+  @doc """
+  Adds an id attribute to the given headers.
+  """
+  def add_ids_to_headers(doc_ast, headers) do
+    doc_ast
+    |> map_reduce_tags(%{}, fn {tag, attrs, inner, meta} = ast, seen ->
+      if tag in headers and not Keyword.has_key?(attrs, :id) do
+        possible_id = inner |> text() |> ExDoc.Utils.text_to_id()
+        id_count = Map.get(seen, possible_id, 0)
+        actual_id = if id_count >= 1, do: "#{possible_id}-#{id_count}", else: possible_id
+        seen = Map.put(seen, possible_id, id_count + 1)
+        {{tag, [id: actual_id] ++ attrs, inner, meta}, seen}
+      else
+        {ast, seen}
+      end
+    end)
+    |> elem(0)
+  end
+
   @doc """
   Compute a synopsis from a document by looking at its first paragraph.
   """
@@ -144,14 +181,11 @@ defmodule ExDoc.DocAST do
   @doc """
   Remove ids from elements.
   """
-  def remove_ids({tag, attrs, inner, meta}),
-    do: {tag, Keyword.delete(attrs, :href), remove_ids(inner), meta}
-
-  def remove_ids(list) when is_list(list),
-    do: Enum.map(list, &remove_ids/1)
-
-  def remove_ids(other),
-    do: other
+  def remove_ids(ast) do
+    map_tags(ast, fn {tag, attrs, inner, meta} ->
+      {tag, Keyword.delete(attrs, :href), inner, meta}
+    end)
+  end
 
   @doc """
   Returns text content from the given AST.
@@ -199,57 +233,52 @@ defmodule ExDoc.DocAST do
   defp pivot([head | tail], acc, headers), do: pivot(tail, [head | acc], headers)
   defp pivot([], acc, _headers), do: Enum.reverse(acc)
 
-  def highlight(html, language, opts \\ []) do
-    do_highlight(html, language.highlight_info(), opts)
-  end
-
-  defp do_highlight(
-         {:pre, pre_attrs, [{:code, code_attrs, [code], code_meta}], pre_meta} = ast,
-         highlight_info,
-         opts
-       )
-       when is_binary(code) do
-    {lang, code_attrs} = Keyword.pop(code_attrs, :class, "")
-
-    case pick_language_and_lexer(lang, highlight_info, code) do
-      {_lang, nil, _lexer_opts} ->
-        ast
+  @doc """
+  Highlights the code blocks in the AST.
+  """
+  def highlight(ast, language, opts \\ []) do
+    highlight_info = language.highlight_info()
 
-      {lang, lexer, lexer_opts} ->
-        try do
-          Makeup.highlight_inner_html(code,
-            lexer: lexer,
-            lexer_options: lexer_opts,
-            formatter_options: opts
-          )
-        rescue
-          exception ->
-            ExDoc.Utils.warn(
-              [
-                "crashed while highlighting #{lang} snippet:\n\n",
-                ExDoc.DocAST.to_string(ast),
-                "\n\n",
-                Exception.format_banner(:error, exception, __STACKTRACE__)
-              ],
-              __STACKTRACE__
-            )
+    map_tags(ast, fn
+      {:pre, pre_attrs, [{:code, code_attrs, [code], code_meta}], pre_meta} = ast
+      when is_binary(code) ->
+        {lang, code_attrs} = Keyword.pop(code_attrs, :class, "")
 
+        case pick_language_and_lexer(lang, highlight_info, code) do
+          {_lang, nil, _lexer_opts} ->
             ast
-        else
-          highlighted ->
-            code_attrs = [class: "makeup #{lang}", translate: "no"] ++ code_attrs
-            code_meta = Map.put(code_meta, :verbatim, true)
-            {:pre, pre_attrs, [{:code, code_attrs, [highlighted], code_meta}], pre_meta}
-        end
-    end
-  end
 
-  defp do_highlight(list, highlight_info, opts) when is_list(list) do
-    Enum.map(list, &do_highlight(&1, highlight_info, opts))
-  end
+          {lang, lexer, lexer_opts} ->
+            try do
+              Makeup.highlight_inner_html(code,
+                lexer: lexer,
+                lexer_options: lexer_opts,
+                formatter_options: opts
+              )
+            rescue
+              exception ->
+                ExDoc.Utils.warn(
+                  [
+                    "crashed while highlighting #{lang} snippet:\n\n",
+                    ExDoc.DocAST.to_string(ast),
+                    "\n\n",
+                    Exception.format_banner(:error, exception, __STACKTRACE__)
+                  ],
+                  __STACKTRACE__
+                )
+
+                ast
+            else
+              highlighted ->
+                code_attrs = [class: "makeup #{lang}", translate: "no"] ++ code_attrs
+                code_meta = Map.put(code_meta, :verbatim, true)
+                {:pre, pre_attrs, [{:code, code_attrs, [highlighted], code_meta}], pre_meta}
+            end
+        end
 
-  defp do_highlight(other, _highlight_info, _opts) do
-    other
+      ast ->
+        ast
+    end)
   end
 
   defp pick_language_and_lexer("", _highlight_info, "$ " <> _) do
@@ -270,4 +299,44 @@ defmodule ExDoc.DocAST do
       :error -> {lang, nil, []}
     end
   end
+
+  ## Traversal helpers
+
+  @doc """
+  Maps the tags in the AST, first mapping children tags, then the tag itself.
+  """
+  def map_tags({tag, attrs, inner, meta}, fun),
+    do: fun.({tag, attrs, Enum.map(inner, &map_tags(&1, fun)), meta})
+
+  def map_tags(list, fun) when is_list(list),
+    do: Enum.map(list, &map_tags(&1, fun))
+
+  def map_tags(other, _fun),
+    do: other
+
+  @doc """
+  Reduces the tags in the AST, first reducing children tags, then the tag itself.
+  """
+  def reduce_tags({tag, attrs, inner, meta}, acc, fun),
+    do: fun.({tag, attrs, inner, meta}, Enum.reduce(inner, acc, &reduce_tags(&1, &2, fun)))
+
+  def reduce_tags(list, acc, fun) when is_list(list),
+    do: Enum.reduce(list, acc, &reduce_tags(&1, &2, fun))
+
+  def reduce_tags(_other, acc, _fun),
+    do: acc
+
+  @doc """
+  Map-reduces the tags in the AST, first mapping children tags, then the tag itself.
+  """
+  def map_reduce_tags({tag, attrs, inner, meta}, acc, fun) do
+    {inner, acc} = Enum.map_reduce(inner, acc, &map_reduce_tags(&1, &2, fun))
+    fun.({tag, attrs, inner, meta}, acc)
+  end
+
+  def map_reduce_tags(list, acc, fun) when is_list(list),
+    do: Enum.map_reduce(list, acc, &map_reduce_tags(&1, &2, fun))
+
+  def map_reduce_tags(other, acc, _fun),
+    do: {other, acc}
 end
diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex
index 51328d565..4843f533a 100644
--- a/lib/ex_doc/formatter/html.ex
+++ b/lib/ex_doc/formatter/html.ex
@@ -414,7 +414,7 @@ defmodule ExDoc.Formatter.HTML do
       case extension_name(input) do
         extension when extension in ["", ".txt"] ->
           source = File.read!(input)
-          ast = [{:pre, [], "\n" <> source, %{}}]
+          ast = [{:pre, [], ["\n" <> source], %{}}]
           {source, ast}
 
         extension when extension in [".md", ".livemd", ".cheatmd"] ->
diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs
index 73e5b6258..a892e871f 100644
--- a/test/ex_doc/doc_ast_test.exs
+++ b/test/ex_doc/doc_ast_test.exs
@@ -126,8 +126,8 @@ defmodule ExDoc.DocASTTest do
 
     defp synopsis(markdown) do
       markdown
-      |> ExDoc.DocAST.parse!("text/markdown")
-      |> ExDoc.DocAST.synopsis()
+      |> DocAST.parse!("text/markdown")
+      |> DocAST.synopsis()
     end
   end
 
@@ -151,8 +151,36 @@ defmodule ExDoc.DocASTTest do
 
     defp extract_headers(markdown) do
       markdown
-      |> ExDoc.DocAST.parse!("text/markdown")
-      |> ExDoc.DocAST.extract_headers([:h2])
+      |> DocAST.parse!("text/markdown")
+      |> DocAST.extract_headers([:h2])
+    end
+  end
+
+  describe "headers" do
+    test "adds and extracts anchored headers" do
+      assert """
+             # h1
+
+             ## h2
+
+             ### h3 repeat
+
+             ## h2 > h3
+
+             ### h3 repeat
+
+             > ## inside `blockquote`
+             """
+             |> DocAST.parse!("text/markdown")
+             |> DocAST.add_ids_to_headers([:h2, :h3])
+             |> DocAST.extract_headers_with_ids([:h2, :h3]) ==
+               [
+                 {:h2, "h2", "h2"},
+                 {:h3, "h3 repeat", "h3-repeat"},
+                 {:h2, "h2 > h3", "h2-h3"},
+                 {:h3, "h3 repeat", "h3-repeat-1"},
+                 {:h2, "inside blockquote", "inside-blockquote"}
+               ]
     end
   end
 
@@ -196,35 +224,55 @@ defmodule ExDoc.DocASTTest do
              ```
              """) =~
                ~r{
\$.*}
+
+      # Nested in another element
+      assert highlight("""
+             > ```elixir
+             > hello
+             > ```
+             """) =~
+               ~r{
.*}
     end
 
     defp highlight(markdown) do
       markdown
-      |> ExDoc.DocAST.parse!("text/markdown")
-      |> ExDoc.DocAST.highlight(ExDoc.Language.Elixir)
-      |> ExDoc.DocAST.to_string()
+      |> DocAST.parse!("text/markdown")
+      |> DocAST.highlight(ExDoc.Language.Elixir)
+      |> DocAST.to_string()
     end
   end
 
   describe "sectionize" do
     test "sectioninize" do
-      list = [
-        {:h1, [], ["H1"], %{}},
-        {:h2, [class: "example"], ["H2-1"], %{}},
-        {:p, [], ["p1"], %{}},
-        {:h3, [], ["H3-1"], %{}},
-        {:p, [], ["p2"], %{}},
-        {:h3, [], ["H3-2"], %{}},
-        {:p, [], ["p3"], %{}},
-        {:h3, [], ["H3-3"], %{}},
-        {:p, [], ["p4"], %{}},
-        {:h2, [], ["H2-2"], %{}},
-        {:p, [], ["p5"], %{}},
-        {:h3, [class: "last"], ["H3-1"], %{}},
-        {:p, [], ["p6"], %{}}
-      ]
-
-      assert DocAST.sectionize(list, [:h2, :h3]) ==
+      assert """
+             # H1
+
+             ## H2-1 {:class="example"}
+
+             p1
+
+             ### H3-1
+
+             p2
+
+             ### H3-2
+
+             p3
+
+             ### H3-3
+
+             p4
+
+             ## H2-2
+
+             p5
+
+             ### H3-1 {:class="last"}
+
+             p6
+             """
+             |> DocAST.parse!("text/markdown")
+             |> DocAST.sectionize([:h2, :h3]) ==
                [
                  {:h1, [], ["H1"], %{}},
                  {:section, [class: "h2 example"],

From bb2a1adefbadf0a170a0d4e801d977e60adbc5a1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= 
Date: Thu, 8 May 2025 13:25:17 +0200
Subject: [PATCH 08/17] Add IDs to nodes upfront

---
 lib/ex_doc/doc_ast.ex                  | 12 +++++++++---
 lib/ex_doc/formatter/html.ex           | 11 ++++++-----
 lib/ex_doc/formatter/html/templates.ex | 22 +++++-----------------
 lib/ex_doc/retriever.ex                | 18 +++++++++++++-----
 4 files changed, 33 insertions(+), 30 deletions(-)

diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex
index 5648706bb..81586ded7 100644
--- a/lib/ex_doc/doc_ast.ex
+++ b/lib/ex_doc/doc_ast.ex
@@ -142,16 +142,22 @@ defmodule ExDoc.DocAST do
 
   @doc """
   Adds an id attribute to the given headers.
+
+  A prefix for the id attribute can be given,
+  which is automatically URL encoded to avoid
+  issues.
   """
-  def add_ids_to_headers(doc_ast, headers) do
+  def add_ids_to_headers(doc_ast, headers, prefix \\ "") do
+    prefix = URI.encode(prefix)
+
     doc_ast
     |> map_reduce_tags(%{}, fn {tag, attrs, inner, meta} = ast, seen ->
       if tag in headers and not Keyword.has_key?(attrs, :id) do
         possible_id = inner |> text() |> ExDoc.Utils.text_to_id()
         id_count = Map.get(seen, possible_id, 0)
-        actual_id = if id_count >= 1, do: "#{possible_id}-#{id_count}", else: possible_id
+        partial_id = if id_count >= 1, do: "#{possible_id}-#{id_count}", else: possible_id
         seen = Map.put(seen, possible_id, id_count + 1)
-        {{tag, [id: actual_id] ++ attrs, inner, meta}, seen}
+        {{tag, [id: prefix <> partial_id] ++ attrs, inner, meta}, seen}
       else
         {ast, seen}
       end
diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex
index 4843f533a..a5700b789 100644
--- a/lib/ex_doc/formatter/html.ex
+++ b/lib/ex_doc/formatter/html.ex
@@ -322,8 +322,8 @@ defmodule ExDoc.Formatter.HTML do
       title: "API Reference",
       title_content: title_content,
       headers:
-        if(nodes_map.modules != [], do: ["Modules"], else: []) ++
-          if(nodes_map.tasks != [], do: ["Mix Tasks"], else: [])
+        if(nodes_map.modules != [], do: [{:h2, "Modules", "modules"}], else: []) ++
+          if(nodes_map.tasks != [], do: [{:h2, "Mix Tasks", "mix-tasks"}], else: [])
     }
   end
 
@@ -423,6 +423,7 @@ defmodule ExDoc.Formatter.HTML do
           ast =
             source
             |> Markdown.to_ast(opts)
+            |> ExDoc.DocAST.add_ids_to_headers([:h2, :h3])
             |> sectionize(extension)
 
           {source, ast}
@@ -447,12 +448,10 @@ defmodule ExDoc.Formatter.HTML do
 
     source_path = source_file |> Path.relative_to(File.cwd!()) |> String.replace_leading("./", "")
     source_url = source_url_pattern.(source_path, 1)
-
     search_data = normalize_search_data!(input_options[:search_data])
 
     %{
       source: source,
-      content: content_html,
       group: group,
       id: id,
       source_path: source_path,
@@ -460,7 +459,9 @@ defmodule ExDoc.Formatter.HTML do
       search_data: search_data,
       title: title,
       title_content: title_html || title,
-      headers: ExDoc.DocAST.extract_headers(ast, [:h2])
+      # TODO: Remove these fields but first we would need to make API reference return DocAST
+      content: content_html,
+      headers: ExDoc.DocAST.extract_headers_with_ids(ast, [:h2])
     }
   end
 
diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex
index 8ab6960e9..8d4d146a5 100644
--- a/lib/ex_doc/formatter/html/templates.ex
+++ b/lib/ex_doc/formatter/html/templates.ex
@@ -135,30 +135,18 @@ defmodule ExDoc.Formatter.HTML.Templates do
     %{key: text_to_id(group), name: group, nodes: nodes}
   end
 
-  defp module_sections(%ExDoc.ModuleNode{rendered_doc: nil}), do: [sections: []]
-
   defp module_sections(module) do
-    {sections, _} =
-      module.doc
-      |> ExDoc.DocAST.extract_headers([:h2])
+    sections =
+      (module.doc || [])
+      |> ExDoc.DocAST.extract_headers_with_ids([:h2])
       |> headers_to_id_and_anchors()
-      |> Enum.map_reduce(%{}, fn header, acc ->
-        # TODO Duplicates some of the logic of link_headings/3
-        case Map.fetch(acc, header.id) do
-          {:ok, id} ->
-            {%{header | anchor: "module-#{header.anchor}-#{id}"}, Map.put(acc, header.id, id + 1)}
-
-          :error ->
-            {%{header | anchor: "module-#{header.anchor}"}, Map.put(acc, header.id, 1)}
-        end
-      end)
 
     [sections: sections]
   end
 
   defp headers_to_id_and_anchors(headers) do
-    Enum.map(headers, fn text ->
-      %{id: text, anchor: URI.encode(text_to_id(text))}
+    Enum.map(headers, fn {:h2, text, anchor} ->
+      %{id: text, anchor: anchor}
     end)
   end
 
diff --git a/lib/ex_doc/retriever.ex b/lib/ex_doc/retriever.ex
index 128b4a18d..5c11ca385 100644
--- a/lib/ex_doc/retriever.ex
+++ b/lib/ex_doc/retriever.ex
@@ -135,7 +135,8 @@ defmodule ExDoc.Retriever do
       relative_path: path_relative_to_cwd(module_data.source_file)
     }
 
-    {doc_line, doc_file, format, source_doc, doc, metadata} = get_module_docs(module_data, source)
+    {doc_line, doc_file, format, source_doc, doc_ast, metadata} =
+      get_module_docs(module_data, source)
 
     group_for_doc = config.group_for_doc
     annotations_for_docs = config.annotations_for_docs
@@ -157,7 +158,7 @@ defmodule ExDoc.Retriever do
       docs_groups: config.docs_groups ++ module_data.default_groups,
       docs: ExDoc.Utils.natural_sort_by(docs, &"#{&1.name}/#{&1.arity}"),
       doc_format: format,
-      doc: doc,
+      doc: normalize_doc_ast(doc_ast, "module-"),
       source_doc: source_doc,
       moduledoc_line: doc_line,
       moduledoc_file: doc_file,
@@ -176,6 +177,12 @@ defmodule ExDoc.Retriever do
     nil
   end
 
+  # TODO: Consider perhaps moving auto-linking here.
+  defp normalize_doc_ast(doc_ast, prefix) do
+    doc_ast
+    |> DocAST.add_ids_to_headers([:h2, :h3], prefix)
+  end
+
   # Helpers
 
   defp get_module_docs(module_data, source) do
@@ -219,17 +226,18 @@ defmodule ExDoc.Retriever do
     defaults = get_defaults(name, arity, Map.get(metadata, :defaults, 0))
 
     doc_ast =
-      (source_doc && doc_ast(content_type, source_doc, file: doc_file, line: doc_line + 1)) ||
+      doc_ast(content_type, source_doc, file: doc_file, line: doc_line + 1) ||
         doc_data.doc_fallback.()
 
     group = group_for_doc.(metadata) || doc_data.default_group
+    id = doc_data.id_key <> nil_or_name(name, arity)
 
     %ExDoc.DocNode{
-      id: doc_data.id_key <> nil_or_name(name, arity),
+      id: id,
       name: name,
       arity: arity,
       deprecated: metadata[:deprecated],
-      doc: doc_ast,
+      doc: normalize_doc_ast(doc_ast, id <> "-"),
       source_doc: source_doc,
       doc_line: doc_line,
       doc_file: doc_file,

From 3efa2d70f267a8af4d98a7bbab0fb695d056d81c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= 
Date: Thu, 8 May 2025 14:06:09 +0200
Subject: [PATCH 09/17] Convert link headings into DocAST traversals

---
 assets/css/content/general.css                |   3 +-
 formatters/html/dist/html-elixir-J3PIVQVA.css |   6 +
 formatters/html/dist/html-elixir-M6JNNWMH.css |   6 -
 formatters/html/dist/html-erlang-5OIFJN4X.css |   6 -
 formatters/html/dist/html-erlang-ZK43ZOAC.css |   6 +
 lib/ex_doc/formatter/epub.ex                  |  10 +-
 lib/ex_doc/formatter/epub/templates.ex        |   5 +-
 .../epub/templates/extra_template.eex         |   6 +-
 .../epub/templates/module_template.eex        |   4 +-
 lib/ex_doc/formatter/html.ex                  |  16 +--
 lib/ex_doc/formatter/html/templates.ex        | 117 ++++++-----------
 .../html/templates/detail_template.eex        |   2 +-
 .../html/templates/extra_template.eex         |   2 +-
 .../html/templates/module_template.eex        |   4 +-
 lib/ex_doc/retriever.ex                       |   2 +-
 test/ex_doc/formatter/epub/templates_test.exs |   4 +-
 test/ex_doc/formatter/html/templates_test.exs | 122 +++---------------
 17 files changed, 93 insertions(+), 228 deletions(-)
 create mode 100644 formatters/html/dist/html-elixir-J3PIVQVA.css
 delete mode 100644 formatters/html/dist/html-elixir-M6JNNWMH.css
 delete mode 100644 formatters/html/dist/html-erlang-5OIFJN4X.css
 create mode 100644 formatters/html/dist/html-erlang-ZK43ZOAC.css

diff --git a/assets/css/content/general.css b/assets/css/content/general.css
index f2866591d..2b35e0857 100644
--- a/assets/css/content/general.css
+++ b/assets/css/content/general.css
@@ -205,9 +205,10 @@
 .content-inner .section-heading i {
   font-size: var(--icon-size);
   color: var(--mainLight);
-  margin-top: 0.1em;
+  top: -2px;
   margin-left: calc(-1 * (var(--icon-size) + var(--icon-spacing)));
   padding-right: var(--icon-spacing);
+  position: relative;
   opacity: 0;
 }
 
diff --git a/formatters/html/dist/html-elixir-J3PIVQVA.css b/formatters/html/dist/html-elixir-J3PIVQVA.css
new file mode 100644
index 000000000..a08bdc43d
--- /dev/null
+++ b/formatters/html/dist/html-elixir-J3PIVQVA.css
@@ -0,0 +1,6 @@
+:root{--main: hsl(250, 68%, 69%);--mainDark: hsl(250, 68%, 59%);--mainDarkest: hsl(250, 68%, 49%);--mainLight: hsl(250, 68%, 74%);--mainLightest: hsl(250, 68%, 79%);--searchBarFocusColor: #8E7CE6;--searchBarBorderColor: rgba(142, 124, 230, .25);--link-color: var(--mainDark);--link-visited-color: var(--mainDarkest)}body.dark{--link-color: var(--mainLightest);--link-visited-color: var(--mainLight)}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-ext-400-normal-N27NCBWW.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-400-normal-W7754I4D.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-ext-700-normal-Q2L5DVMW.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-700-normal-2XVSBPG4.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--content-width: 949px;--content-gutter: 60px;--borderRadius-lg: 14px;--borderRadius-base: 8px;--borderRadius-sm: 3px;--navTabBorderWidth: 2px;--sansFontFamily: "Lato", system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--monoFontFamily: ui-monospace, SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;--baseLineHeight: 1.5em;--gray25: hsl(207, 43%, 98%);--gray50: hsl(207, 43%, 96%);--gray100: hsl(212, 33%, 91%);--gray200: hsl(210, 29%, 88%);--gray300: hsl(210, 26%, 84%);--gray400: hsl(210, 21%, 64%);--gray450: hsl(210, 21%, 49%);--gray500: hsl(210, 21%, 34%);--gray600: hsl(210, 27%, 26%);--gray700: hsl(212, 35%, 17%);--gray750: hsl(214, 46%, 14%);--gray800: hsl(216, 52%, 11%);--gray800-opacity-0: hsla(216, 52%, 11%, 0%);--gray850: hsl(216, 63%, 8%);--gray900: hsl(218, 73%, 4%);--gray900-opacity-50: hsla(218, 73%, 4%, 50%);--gray900-opacity-0: hsla(218, 73%, 4%, 0%);--coldGrayFaint: hsl(240, 5%, 97%);--coldGrayLight: hsl(240, 5%, 88%);--coldGray-lightened-10: hsl(240, 5%, 56%);--coldGray: hsl(240, 5%, 46%);--coldGray-opacity-10: hsla(240, 5%, 46%, 10%);--coldGrayDark: hsl(240, 5%, 28%);--coldGrayDim: hsl(240, 5%, 18%);--yellowLight: hsl(43, 100%, 95%);--yellowDark: hsl(44, 100%, 15%);--yellow: hsl(60, 100%, 43%);--green-lightened-10: hsl(90, 100%, 45%);--green: hsl(90, 100%, 35%);--white: hsl(0, 0%, 100%);--white-opacity-50: hsla(0, 0%, 100%, 50%);--white-opacity-10: hsla(0, 0%, 100%, 10%);--white-opacity-0: hsla(0, 0%, 100%, 0%);--black: hsl(0, 0%, 0%);--black-opacity-10: hsla(0, 0%, 0%, 10%);--black-opacity-50: hsla(0, 0%, 0%, 50%);--orangeDark: hsl(30, 90%, 40%);--orangeLight: hsl(30, 80%, 50%);--text-xs: .75rem;--text-sm: .875rem;--text-md: 1rem;--text-lg: 1.125rem;--text-xl: 1.25rem;--transition-duration: .15s;--transition-timing: cubic-bezier(.4, 0, .2, 1);--transition-all: all var(--transition-duration) var(--transition-timing);--transition-colors: color var(--transition-duration) var(--transition-timing), background-color var(--transition-duration) var(--transition-timing), border-color var(--transition-duration) var(--transition-timing), text-decoration-color var(--transition-duration) var(--transition-timing), fill var(--transition-duration) var(--transition-timing), stroke var(--transition-duration) var(--transition-timing);--transition-opacity: opacity var(--transition-duration) var(--transition-timing)}@media screen and (max-width: 768px){:root{--content-width: 100%;--content-gutter: 20px}}option{background-color:var(--sidebarBackground)}:root{--background: var(--white);--contrast: var(--black);--textBody: var(--gray800);--textHeaders: var(--gray900);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--coldGrayFaint);--iconAction: var(--coldGray);--iconActionHover: var(--gray800);--blockquoteBackground: var(--coldGrayFaint);--blockquoteBorder: var(--coldGrayLight);--tableHeadBorder: var(--gray100);--tableBodyBorder: var(--gray50);--warningBackground: hsl( 33, 100%, 97%);--warningHeadingBackground: hsl( 33, 87%, 64%);--warningHeading: var(--black);--errorBackground: hsl( 7, 81%, 96%);--errorHeadingBackground: hsl( 6, 80%, 60%);--errorHeading: var(--white);--infoBackground: hsl(206, 91%, 96%);--infoHeadingBackground: hsl(213, 92%, 62%);--infoHeading: var(--white);--neutralBackground: hsl(212, 29%, 92%);--neutralHeadingBackground: hsl(220, 43%, 11%);--neutralHeading: var(--white);--tipBackground: hsl(142, 31%, 93%);--tipHeadingBackground: hsl(134, 39%, 36%);--tipHeading: var(--white);--fnSpecAttr: var(--coldGray);--fnDeprecated: var(--yellowLight);--blink: var(--yellowLight);--codeBackground: var(--gray25);--codeBorder: var(--gray100);--codeScrollThumb: var(--gray400);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray25);--admCodeBorder: var(--gray100);--admCodeColor: var(--black);--admInlineCodeColor: var(--black);--admInlineCodeBackground: var(--gray25);--admInlineCodeBorder: var(--gray100);--tabBorder: var(--gray300);--tabBorderTop: var(--gray100);--tabShadow: var(--gray25);--bottomActionsBtnBorder: var(--black-opacity-10);--bottomActionsBtnTitle: var(--mainDark);--modalBackground: var(--white);--settingsInput: var(--gray500);--settingsInputBackground: var(--white);--settingsInputBorder: var(--gray300);--settingsSectionBorder: var(--gray300);--quickSwitchInput: var(--gray500);--quickSwitchContour: var(--coldGray);--success: var(--green);--progressBarColor: var(--gray400);--sidebarAccentMain: var(--black);--sidebarBackground: var(--gray50);--sidebarHeader: var(--gray100);--sidebarMuted: var(--gray800);--sidebarHover: var(--black);--sidebarStaleVersion: var(--orangeDark);--sidebarSubheadings: var(--gray500);--sidebarItem: var(--black);--sidebarInactiveItemBorder: var(--gray500);--sidebarInactiveItemMarker: var(--gray200);--sidebarLanguageAccentBar: var(--mainDark);--sidebarActiveItem: var(--mainDarkest);--searchBarBorder: var(--gray200);--searchAccentMain: var(--gray600);--searchLanguageAccentBar: var(--main);--searchSearch: var(--white);--autocompleteBorder: rgba(3, 9, 19, .1);--autocompletePreview: var(--gray25);--autocompleteSelected: var(--gray25);--autocompleteHover: var(--gray50);--autocompleteBackground: var(--white);--suggestionBorder: var(--gray200);--autocompleteResults: var(--gray600);--autocompleteResultsBold: var(--gray800);--autocompleteLabelBack: var(--gray100);--autocompleteLabelFont: var(--gray600)}body.dark{--background: var(--gray900);--contrast: var(--white);--textBody: var(--gray200);--textHeaders: var(--gray100);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--gray700);--iconAction: var(--coldGray-lightened-10);--iconActionHover: var(--white);--blockquoteBackground: var(--coldGray-opacity-10);--blockquoteBorder: var(--coldGrayDim);--tableHeadBorder: var(--gray600);--tableBodyBorder: var(--gray700);--warningBackground: hsla( 33, 30%, 60%, 10%);--warningHeadingBackground: hsla( 33, 66%, 35%, 80%);--warningHeading: var(--white);--errorBackground: hsla( 7, 30%, 60%, 10%);--errorHeadingBackground: hsla( 6, 70%, 40%, 80%);--errorHeading: var(--white);--infoBackground: hsla(206, 30%, 60%, 10%);--infoHeadingBackground: hsla(213, 55%, 35%, 80%);--infoHeading: var(--white);--neutralBackground: hsl(210, 30%, 60%, 10%);--neutralHeadingBackground: var(--gray600);--neutralHeading: var(--white);--tipBackground: hsla(142, 30%, 60%, 10%);--tipHeadingBackground: hsla(134, 45%, 30%, 80%);--tipHeading: var(--white);--fnSpecAttr: var(--gray400);--fnDeprecated: var(--yellowDark);--blink: var(--gray600);--codeBackground: var(--gray750);--codeBorder: var(--gray600);--codeScrollThumb: var(--gray500);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray750);--admCodeBorder: var(--gray600);--admCodeColor: var(--gray100);--admInlineCodeColor: var(--gray100);--admInlineCodeBackground: var(--gray750);--admInlineCodeBorder: var(--gray600);--tabBorder: var(--gray700);--tabBorderTop: var(--gray700);--tabShadow: var(--black);--bottomActionsBtnBorder: var(--white-opacity-10);--bottomActionsBtnTitle: var(--mainLightest);--modalBackground: var(--gray800);--settingsInput: var(--white);--settingsInputBackground: var(--gray700);--settingsInputBorder: var(--gray700);--settingsSectionBorder: var(--gray700);--quickSwitchInput: var(--gray300);--quickSwitchContour: var(--gray500);--success: var(--green-lightened-10);--progressBarColor: var(--gray300);--sidebarAccentMain: var(--gray50);--sidebarBackground: var(--gray800);--sidebarHeader: var(--gray700);--sidebarMuted: var(--gray300);--sidebarHover: var(--white);--sidebarStaleVersion: var(--orangeLight);--sidebarSubheadings: var(--gray400);--sidebarItem: var(--gray200);--sidebarInactiveItemBorder: var(--gray400);--sidebarInactiveItemMarker: var(--gray600);--sidebarLanguageAccentBar: var(--mainLight);--sidebarActiveItem: var(--mainLightest);--searchBarBorder: var(--gray500);--searchAccentMain: var(--gray300);--searchSearch: var(--gray900);--autocompleteBorder: rgba(28,42,60,.75);--autocompletePreview: var(--gray750);--autocompleteSelected: var(--gray750);--autocompleteHover: var(--gray700);--autocompleteBackground: var(--gray800);--suggestionBorder: var(--gray600);--autocompleteResults: var(--gray200);--autocompleteResultsBold: var(--gray100);--autocompleteLabelBack: var(--gray600);--autocompleteLabelFont: rgba(255, 255, 255, .8)}:root:has(body.dark){color-scheme:dark}*,:before,:after{box-sizing:border-box}html{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}@font-face{font-family:remixicon;src:url(./remixicon-QPNJX265.woff2) format("woff2");font-display:swap}[class^=ri-],[class*=" ri-"],.remix-icon{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:root{--icon-arrow-up-s: "\ea78";--icon-arrow-down-s: "\ea4e";--icon-arrow-right-s: "\ea6e";--icon-add: "\ea13";--icon-subtract: "\f1af";--icon-error-warning: "\eca1";--icon-external-link-line: "\ecaf";--icon-information: "\ee59";--icon-alert: "\ea21";--icon-double-quotes-l: "\ec51";--icon-link-m: "\eeaf";--icon-close-line: "\eb99";--icon-code-s-slash-line: "\ebad";--icon-menu-line: "\ef3e";--icon-search-2-line: "\f0cd";--icon-settings-3-line: "\f0e6";--icon-printer-line: "\f029"}.ri-lg{font-size:1.3333em;line-height:.75em;vertical-align:-.0667em}.ri-settings-3-line:before{content:var(--icon-settings-3-line)}.ri-add-line:before{content:var(--icon-add)}.ri-subtract-line:before{content:var(--icon-subtract)}.ri-arrow-up-s-line:before{content:var(--icon-arrow-up-s)}.ri-arrow-down-s-line:before{content:var(--icon-arrow-down-s)}.ri-arrow-right-s-line:before{content:var(--icon-arrow-right-s)}.ri-external-link-line:before{content:var(--icon-external-link-line)}.ri-search-2-line:before{content:var(--icon-search-2-line)}.ri-menu-line:before{content:var(--icon-menu-line)}.ri-close-line:before{content:var(--icon-close-line)}.ri-link-m:before{content:var(--icon-link-m)}.ri-code-s-slash-line:before{content:var(--icon-code-s-slash-line)}.ri-error-warning-line:before{content:var(--icon-error-warning)}.ri-information-line:before{content:var(--icon-information)}.ri-alert-line:before{content:var(--icon-alert)}.ri-double-quotes-l:before{content:var(--icon-double-quotes-l)}.ri-printer-line:before{content:var(--icon-printer-line)}html,body{box-sizing:border-box;height:100%;width:100%}body{--sidebarWidth: 300px;--sidebarMinWidth: 300px;--sidebarTransitionDuration: .3s;background-color:var(--background);color:var(--textBody);font-size:var(--text-md);line-height:1.6875em;outline:none!important}*,*:before,*:after{box-sizing:inherit}.body-wrapper{display:flex;height:100%}.sidebar{display:none;flex-direction:column;width:var(--sidebarWidth);min-width:var(--sidebarMinWidth);max-width:50vw;height:100%;position:fixed;top:0;left:calc(-1 * var(--sidebarWidth));z-index:100;resize:horizontal}.sidebar-button{padding:26px 12px 18px 19px;position:fixed;z-index:200;top:0;left:0;will-change:transform;transform:translate(0)}.content{left:0;width:100%;height:100%;position:absolute}.content .content-inner{container:content / inline-size;max-width:var(--content-width);min-height:100%;margin:0 auto;padding:0 var(--content-gutter) 10px}.content-inner:focus{outline:none}.sidebar-transition .sidebar,.sidebar-transition .sidebar-button,.sidebar-transition .content{transition:all var(--sidebarTransitionDuration) ease-in-out allow-discrete}.sidebar-open .sidebar,.sidebar-transition .sidebar{display:flex}.sidebar-open .sidebar{left:0}.sidebar-open .sidebar-button{transform:translate(calc(var(--sidebarWidth) - 100%))}.sidebar-open .content{width:calc(100% - var(--sidebarWidth));left:var(--sidebarWidth)}@media screen and (max-width: 768px){.sidebar-open .content{left:0;width:100%}.sidebar{max-width:90vw}body:not(.sidebar-open) .sidebar-button{position:absolute}}.swup-progress-bar{height:2px;background-color:var(--progressBarColor)}.sidebar{--sidebarFontSize: 16px;--sidebarLineHeight: 20px;font-family:var(--sansFontFamily);font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);background-color:var(--sidebarBackground);color:var(--sidebarAccentMain);overflow:hidden;& .sidebar-tabpanel{scrollbar-width:thin}}.apple-os .sidebar{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sidebar ul{list-style:none}.sidebar ul li{margin:0;padding:0 10px}.sidebar a{color:var(--sidebarAccentMain);text-decoration:none;transition:var(--transition-colors)}.sidebar a:hover{color:var(--sidebarHover)}.sidebar .external-link{margin:0 2.5px 0 0}.sidebar .sidebar-header{background-color:var(--sidebarHeader);width:100%}.sidebar .sidebar-projectInfo{display:flex;justify-content:start;align-items:center;gap:8px;margin:12px 34px 12px 14px}.sidebar .sidebar-projectInfo>div{flex:1}.sidebar .sidebar-projectImage{align-self:flex-end}.sidebar .sidebar-projectImage img{display:block;max-width:48px;max-height:48px}.sidebar .sidebar-projectName{font-weight:700;font-size:var(--text-xl);line-height:24px;color:var(--sidebarAccentMain);margin:0;padding:0;word-wrap:break-word;display:block;width:calc(100% - 12px)}.sidebar .sidebar-projectVersion{display:block;position:relative;margin:0;padding:0;font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);color:var(--sidebarMuted);width:calc(100% - 12px)}.sidebar .sidebar-projectVersion form{display:flex}.sidebar .sidebar-projectVersion select{cursor:pointer;position:relative;margin:0;padding:0 0 0 10px;border:none;-webkit-appearance:none;appearance:none;background-color:transparent;color:var(--sidebarMuted);z-index:2}.sidebar .sidebar-projectVersion option{color:initial}.sidebar .sidebar-projectVersionsCaret{position:absolute;left:0;top:2px;z-index:1;font-size:8px;color:var(--sidebarMuted)}.sidebar .sidebar-projectVersion select::-ms-expand{display:none}.sidebar .sidebar-staleVersion{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--sidebarStaleVersion)}.sidebar .sidebar-staleVersion>a{color:var(--sidebarStaleVersion);font-weight:400}.sidebar .sidebar-staleIcon{font-size:var(--text-lg);position:relative;top:3px;line-height:0}.sidebar .sidebar-list-nav{display:flex;margin:0;padding:0;overflow:auto;scrollbar-width:thin}.sidebar .sidebar-list-nav :is(li,li button){text-transform:uppercase;letter-spacing:.02em;font-size:var(--text-sm);color:var(--sidebarSubheadings);white-space:nowrap}.sidebar .sidebar-list-nav li{display:inline-block;padding:0}.sidebar .sidebar-list-nav button{background:none;border:0;border-radius:0;-webkit-appearance:none;text-align:inherit;color:inherit;font-weight:inherit;cursor:pointer;display:inline-block;line-height:27px;padding:4px 14px;transition:var(--transition-all)}.sidebar .sidebar-list-nav button{border-bottom:var(--navTabBorderWidth) solid transparent}.sidebar .sidebar-list-nav button:not([aria-selected]):hover{border-bottom:var(--navTabBorderWidth) solid var(--sidebarInactiveItemBorder);color:var(--sidebarAccentMain);transition:var(--transition-all)}.sidebar .sidebar-list-nav button[aria-selected]{border-bottom:var(--navTabBorderWidth) solid var(--sidebarLanguageAccentBar);color:var(--sidebarAccentMain)}.sidebar .sidebar-tabpanel{flex:1 1 .01%;overflow-y:auto;overscroll-behavior:contain;position:relative;-webkit-overflow-scrolling:touch;padding-top:12px;scroll-padding-top:40px}.sidebar .full-list{margin:0;padding:0 0 20px;position:relative}.sidebar .full-list :is(li,a){display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.sidebar .full-list li{padding:0;line-height:27px}.sidebar .full-list li.group{text-transform:uppercase;font-weight:700;font-size:.8em;margin:1.5em 0 0;line-height:1.8em;color:var(--sidebarSubheadings);padding-left:15px}.sidebar .full-list li.nesting-context{font-weight:700;font-size:.9em;line-height:1.8em;color:var(--sidebarSubheadings);margin-top:10px;padding-left:15px}.sidebar .full-list a{margin-right:30px;padding:3px 0 3px 12px;border-left:var(--navTabBorderWidth) solid transparent;color:var(--sidebarItem)}.sidebar .full-list a[aria-selected]{color:var(--sidebarActiveItem)}.sidebar .full-list button{appearance:none;background-color:transparent;border:0;padding:0;cursor:pointer;color:inherit;width:20px;text-align:center;font-size:calc(1.2 * var(--sidebarFontSize));line-height:var(--sidebarLineHeight);position:absolute;display:block;right:10px;transform:translateY(-100%)}.sidebar .full-list a[aria-selected]+button{color:var(--sidebarActiveItem)}.sidebar .full-list button:after{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:var(--icon-arrow-down-s)}.sidebar .full-list button[aria-expanded=true]:after{content:var(--icon-arrow-up-s)}.sidebar .full-list ul{display:none;margin:10px 0 10px 10px;padding:0}.sidebar .full-list button[aria-expanded=true]+ul{display:block}.sidebar .full-list>li>a{height:27px;line-height:var(--sidebarLineHeight)}.sidebar .full-list>li>a:hover{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li>a[aria-selected]{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li:last-child{margin-bottom:30px}.sidebar .full-list>li.group:first-child{margin-top:0}.sidebar .full-list>li>ul>li:not(:has(li a[aria-selected=true]))>a[aria-selected=true]:before,.sidebar .full-list>li>ul>li>a:hover:before{content:"\2022";position:absolute;margin-left:-15px;color:var(--sidebarActiveItem)}.sidebar .full-list ul li{line-height:var(--sidebarFontSize);padding:0 8px}.sidebar .full-list ul a{padding-left:15px;height:24px}.sidebar .full-list ul button{font-size:var(--sidebarFontSize)}.sidebar .full-list ul button:after{content:var(--icon-add)}.sidebar .full-list ul button[aria-expanded=true]:after{content:var(--icon-subtract)}.sidebar .full-list ul ul{margin:9px 0 9px 10px}.sidebar .full-list ul ul li{height:20px;color:var(--sidebarAccentMain)}.sidebar .full-list ul ul a{border-left:1px solid var(--sidebarInactiveItemMarker);padding:0 10px;height:20px}.sidebar .full-list ul ul a:hover{border-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list ul ul a[aria-selected]{color:var(--sidebarActiveItem);border-color:var(--sidebarLanguageAccentBar)}.sidebar-button{cursor:pointer;background-color:transparent;border:none;font-size:var(--sidebarFontSize);color:var(--sidebarAccentMain)}.sidebar-button:hover{color:var(--sidebarHover)}body:not(.sidebar-open) .sidebar-button{color:var(--contrast)}@media screen and (max-height: 500px){.sidebar{overflow-y:auto}.sidebar .full-list{overflow:visible}}.top-search{background-color:var(--background);top:0;z-index:99;position:relative;width:100%;padding:10px 0}.search-settings{display:flex;column-gap:12px;align-items:center;width:100%;position:relative}.search-bar{border:1px solid var(--searchBarBorder);border-radius:var(--borderRadius-base);height:48px;position:relative;width:100%}.top-search .search-bar .search-input{background-color:var(--searchSearch);border:1px solid transparent;border-radius:var(--borderRadius-base);color:var(--searchAccentMain);position:relative;height:46px;padding:8px 35px 8px 43px;width:100%;transition:var(--transition-all)}.top-search .search-bar .search-input::placeholder{color:var(--searchAccentMain);opacity:.5}.top-search .search-bar .search-input:focus{border:1px solid var(--searchBarFocusColor);border-radius:calc(var(--borderRadius-base) - 1px);position:relative;box-shadow:0 4px 20px 0 var(--searchBarBorderColor) inset}.top-search .search-bar .search-label{position:relative}.top-search .search-bar .search-button{font-size:var(--text-sm);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;left:11px;opacity:.5;padding:5px 1px 5px 5px;position:absolute;top:60%;transform:translateY(-60%);z-index:99;transition:var(--transition-all)}.top-search .search-bar.selected .search-button,.top-search .search-bar .search-button:hover,.top-search .search-bar .search-button:focus{color:var(--top-searchLanguageAccentBar);opacity:1}.top-search .search-bar .search-close-button{font-size:var(--text-md);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;right:11px;margin:0;opacity:.5;padding:5px 1px 5px 0;position:absolute;transform:scaleY(0);top:calc(50% - 13px);transition:var(--transition-all);z-index:99}.top-search .search-bar .search-close-button:hover{opacity:.7}.top-search .search-settings button.icon-settings{display:flex;align-items:center;justify-content:flex-end}.top-search .search-settings .icon-settings{font-size:var(--text-xl);float:right;color:var(--iconAction);text-decoration:none;border:none;transition:color .3s ease-in-out;background-color:transparent;cursor:pointer;padding:0}.top-search .search-settings .icon-settings:hover{color:var(--iconActionHover)}.top-search .search-settings .icon-settings:visited{color:var(--iconAction)}@media screen and (max-width: 768px){.top-search{padding-left:calc(var(--content-gutter) + 36px);padding-right:var(--content-gutter);margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));width:calc(2 * var(--content-gutter) + 100%)}.search-settings{width:100%;box-sizing:border-box}}body.search-focused .search-bar .search-close-button{transform:scaleY(1);transition:var(--transition-all)}@media screen and (hover: hover){body.search-focused .top-search{position:sticky!important}body.search-focused .sidebar-button{position:fixed!important}}@media screen and (hover: none){body.scroll-sticky .top-search{position:sticky!important}body.scroll-sticky .sidebar-button{position:fixed!important}}*:focus,button:focus,[type=button]:focus,[type=reset]:focus,[type=submit]:focus{outline:2px solid var(--main);outline-offset:-2px}*:focus:not(:focus-visible),button:focus:not(:focus-visible),[type=button]:focus:not(:focus-visible),[type=reset]:focus:not(:focus-visible),[type=submit]:focus:not(:focus-visible){outline:0}input[type=text],input[type=number],input[type=date],input[type=datetime],input[type=datetime-local],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=time],input[type=url],input[type=week],textarea{outline:0}.content-inner{font-size:1em;line-height:1.6875em;position:relative;background-color:var(--background);color:var(--textBody)}.content-inner .heading-with-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px}.content-inner .heading-with-actions>*:not(h1){flex-shrink:0}.content-inner .heading-with-actions h1{flex-grow:1;justify-self:flex-start;max-width:100%;margin:0;overflow-wrap:break-word}.content-inner .heading-with-actions .icon-action{width:20px;height:20px;display:flex;justify-content:center;align-items:center;font-weight:400}.content-inner .heading-with-actions.top-heading .icon-action{font-size:1.2rem}@container content (width > 600px){.content-inner .heading-with-actions.top-heading{flex-wrap:nowrap;align-items:flex-start;& h1{padding-right:32px}& .icon-action{padding-top:1.7rem}}}.content-inner .top-heading{padding-top:1rem}.content-inner :is(h1,h2,h3,h4,h5,h6){font-family:var(--sansFontFamily);font-weight:700;line-height:1.5em;word-wrap:break-word;color:var(--textHeaders)}.content-inner h1{font-size:2em;margin:.5em 0}.content-inner h1.section-heading{margin:1.5em 0 .5em}.content-inner h1 small{font-weight:400}.content-inner h2{font-size:1.6em;padding-top:1em;margin-bottom:.5em}.content-inner h3{font-size:1.375em;margin:1em 0 .5em}.content-inner li+li{margin-top:.25em}.content-inner :is(a,.a-main){color:var(--link-color);text-decoration:underline;text-decoration-skip-ink:auto}.content-inner :is(a:visited,.a-main:visited){color:var(--link-visited-color)}.content-inner .icon-action{color:var(--iconAction);text-decoration:none;border:none;transition:var(--transition-colors);background-color:transparent;cursor:pointer}.content-inner .icon-action:hover{color:var(--iconActionHover)}.content-inner .icon-action:visited{color:var(--iconAction)}.content-inner .livebook-badge-container{display:flex}.content-inner a.livebook-badge{display:inline-flex}.content-inner .note{color:var(--iconAction);font-size:var(--text-xs);font-weight:400}.content-inner blockquote,.content-inner section.admonition{border-left:3px solid var(--blockquoteBorder);position:relative;margin:1.5625em 0;padding:0 1.2rem;overflow:auto;background-color:var(--blockquoteBackground);border-radius:var(--borderRadius-base)}.content-inner blockquote p:last-child,.content-inner section.admonition p:last-child{padding-bottom:1em;margin-bottom:0}.content-inner table{margin:2em 0;border-collapse:collapse;display:block;overflow:auto}.content-inner th{text-align:left;font-family:var(--sansFontFamily);font-weight:700;padding-bottom:.5em;white-space:nowrap}.content-inner thead tr{border-bottom:1px solid var(--tableHeadBorder)}.content-inner tbody tr{border-bottom:1px solid var(--tableBodyBorder)}.content-inner tbody tr:last-child{border-bottom:none}.content-inner tr{vertical-align:bottom;height:2.5em}.content-inner :is(td,th){padding:.25em .25em .25em 1em;line-height:2em;vertical-align:top}.content-inner .section-heading{--icon-size: 16px;--icon-spacing: 5px;display:grid;grid-template:1fr / 1fr}@media screen and (max-width: 768px){.content-inner .section-heading{--icon-spacing: 2px}}.content-inner .section-heading>:is(.hover-link,.text){grid-row:1;grid-column:1}.content-inner .section-heading .hover-link{text-decoration:none}.content-inner .section-heading i{font-size:var(--icon-size);color:var(--mainLight);top:-2px;margin-left:calc(-1 * (var(--icon-size) + var(--icon-spacing)));padding-right:var(--icon-spacing);position:relative;opacity:0}.content-inner :is(blockquote,section.admonition) .section-heading i{display:none}.content-inner .section-heading:is(:hover,:focus,:target) i{opacity:1}.content-inner .app-vsn{display:none!important;font-size:.6em;line-height:1.5em}@media screen and (max-width: 768px){.content-inner .app-vsn{display:block!important}}.content-inner img{max-width:100%}.content-inner strong>code{font-weight:700}.content-inner code{font-family:var(--monoFontFamily);font-style:normal;line-height:24px;font-weight:400;font-size:var(--text-sm)}@media screen and (max-width: 768px){.content-inner :is(ol,ul){padding-left:calc(1.5 * var(--content-gutter))}}.content-inner section.admonition{border-radius:var(--borderRadius-base);border-left:0}.content-inner section.admonition.warning{background-color:var(--warningBackground)}.content-inner section.admonition.error{background-color:var(--errorBackground)}.content-inner section.admonition.info{background-color:var(--infoBackground)}.content-inner section.admonition.neutral{background-color:var(--neutralBackground)}.content-inner section.admonition.tip{background-color:var(--tipBackground)}.content-inner section.admonition>.admonition-title{color:var(--contrast);margin:0 -1.2rem;padding:.7rem 1.2rem .7rem 3.3rem;font-weight:700;font-style:normal}.content-inner section.admonition>.admonition-title:before{color:var(--contrast);position:absolute;left:1rem;font-size:1.8rem;font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.content-inner section.admonition>.admonition-title.warning{background-color:var(--warningHeadingBackground);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.warning:before{content:var(--icon-error-warning);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.error{background-color:var(--errorHeadingBackground);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.error:before{content:var(--icon-error-warning);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.info{background-color:var(--infoHeadingBackground);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.info:before{content:var(--icon-information);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.neutral{background-color:var(--neutralHeadingBackground);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.neutral:before{content:var(--icon-double-quotes-l);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.tip{background-color:var(--tipHeadingBackground);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title.tip:before{content:var(--icon-information);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title code{margin:0 .5ch}.content-inner section.admonition code{background-color:var(--admInlineCodeBackground);border:1px solid var(--admInlineCodeBorder);color:var(--admInlineCodeColor)}.content-inner section.admonition pre code{background-color:var(--admCodeBackground);border:1px solid var(--admCodeBorder);color:var(--admCodeColor)}.content-inner section.admonition>.admonition-title :is(a,a:visited){color:inherit;text-decoration-color:currentColor}@media screen and (max-width: 768px){.content-inner section.admonition{margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0}.content-inner section.admonition>.admonition-title{margin:0 calc(-1 * var(--content-gutter))}}.content-inner .summary h2 a{text-decoration:none;border:none;color:var(--textHeaders)!important}.content-inner .summary span.deprecated{color:var(--darkDeprecated);font-weight:400}.content-inner .summary .summary-row .summary-signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700}.content-inner .summary .summary-row .summary-signature a{text-decoration:none;border:none}.content-inner .summary .summary-row .summary-synopsis{padding:0 1.2em;margin:0 0 .5em}.content-inner .summary .summary-row .summary-synopsis p{margin:0;padding:0}@font-face{font-family:Consolas;src:local("Consolas");size-adjust:110%}.content-inner.content-inner :is(a:has(code,img),pre a){color:var(--link-color);text-shadow:none;text-decoration:none;background-image:none}.content-inner.content-inner :is(a:has(code,img),pre a):is(:visited,:active,:focus,:hover){color:var(--link-visited-color)}.content-inner code{background-color:var(--codeBackground);vertical-align:baseline;border-radius:var(--borderRadius-sm);padding:.1em .2em;border:1px solid var(--codeBorder);text-transform:none}.content-inner code.inline{border-radius:var(--borderRadius-sm);word-wrap:break-word}.content-inner pre{margin:var(--baseLineHeight) 0}.content-inner pre code{display:block;overflow-x:auto;white-space:inherit;padding:1em;scrollbar-width:thin}.content-inner pre code.output{margin:0 12px;max-height:400px;overflow:auto}.content-inner pre code.output+.copy-button{margin-right:12px}.content-inner pre code.output:before{content:"Output";display:block;position:absolute;top:-16px;left:12px;padding:2px 4px;font-size:var(--text-xs);font-family:var(--monoFontFamily);line-height:1;color:var(--textHeaders);background-color:var(--codeBackground);border:1px solid var(--codeBorder);border-bottom:0;border-radius:2px}@media screen and (max-width: 768px){.content-inner>pre:has(code),.content-inner section>pre:has(code){margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter))}.content-inner>pre code,.content-inner section>pre code{padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0;border-left-width:0;border-right-width:0}}@keyframes blink-background{0%,to{background-color:var(--textDetailBackground)}50%{background-color:var(--blink)}}.content-inner .detail:target .detail-header{animation-duration:.55s;animation-name:blink-background;animation-iteration-count:1;animation-timing-function:ease-in-out}.content-inner .detail-header{margin:1em 0;padding:.5em .85em .5em 1em;background-color:var(--textDetailBackground);border-left:3px solid var(--textDetailAccent);font-size:1em;font-family:var(--monoFontFamily);position:relative}.content-inner .detail-header .signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700;line-height:2em}.content-inner .detail-header:hover a.detail-link,.content-inner .detail-header a.detail-link:focus{opacity:1;text-decoration:none}.content-inner .detail-header a.detail-link{transition:var(--transition-opacity);position:absolute;top:0;left:0;display:block;opacity:0;padding:.6em;line-height:1.5em;margin-left:-2.5em;text-decoration:none;border:none}@media screen and (max-width: 768px){.content-inner .detail-header a.detail-link{margin-left:-30px}}.content-inner .specs pre{font-family:var(--monoFontFamily);font-size:var(--text-xs);font-style:normal;line-height:24px;white-space:pre-wrap;margin:0;padding:0}.content-inner .specs .attribute{color:var(--fnSpecAttr)}.content-inner .docstring{margin:1.2em 0 3em 1.2em}@media screen and (max-width: 768px){.content-inner .docstring{margin-left:0}}.content-inner .docstring:is(h2,h3,h4,h5){font-weight:700}.content-inner .docstring h2{font-size:1.1em}.content-inner .docstring h3{font-size:1em}.content-inner .docstring h4{font-size:.95em}.content-inner .docstring h5{font-size:.9em}.content-inner div.deprecated{display:block;padding:1em;background-color:var(--fnDeprecated);border-radius:var(--borderRadius-sm);margin:var(--baseLineHeight) 0}.content-inner .footer{margin:4em auto 1em;text-align:center;font-size:var(--text-sm)}.content-inner .footer .line{display:inline-block}.content-inner .footer .footer-button{background-color:transparent;border:0;cursor:pointer;padding:0 4px}.content-inner .footer .footer-hex-package{margin-right:4px}.content-inner .bottom-actions{display:flex;justify-content:space-between;margin-top:4em;gap:12px}.bottom-actions-item{flex:1 1 0%}.content-inner .bottom-actions .bottom-actions-button{display:flex;text-decoration:none;flex-direction:column;border-radius:var(--borderRadius-sm);border:1px solid var(--bottomActionsBtnBorder);padding:12px 16px;min-width:150px;transition:var(--transition-all)}.content-inner .bottom-actions .bottom-actions-button:hover{border-color:var(--mainLight)}.content-inner .bottom-actions .bottom-actions-button .subheader{font-size:.8em;color:var(--textHeaders);white-space:nowrap}.content-inner .bottom-actions .bottom-actions-button .title{color:var(--bottomActionsBtnTitle)}.content-inner .bottom-actions .bottom-actions-button[rel=prev]{text-align:start}.content-inner .bottom-actions .bottom-actions-button[rel=next]{text-align:end}@media screen and (max-width: 768px){.content-inner .bottom-actions{flex-direction:column-reverse}}.page-cheatmd .content-inner{--horizontal-space: 1.5em;--vertical-space: 1em}@media (max-width: 600px){.page-cheatmd .content-inner{--horizontal-space: 1em;--vertical-space: .75em}}.page-cheatmd .content-inner{max-width:1200px}.page-cheatmd .content-inner h1{margin-bottom:var(--vertical-space)}.page-cheatmd .content-inner h2{margin:var(--vertical-space) 0;column-span:all;color:var(--gray700);font-weight:500}.dark .page-cheatmd .content-inner h2{color:var(--gray200)}.page-cheatmd .content-inner h3{margin:0 0 1em;font-weight:400}.page-cheatmd .content-inner section.h3{min-width:300px;margin:0;padding:0 0 calc(var(--vertical-space) * 2) 0;break-inside:avoid}.page-cheatmd .content-inner h3 .text{overflow:hidden}.page-cheatmd .content-inner h3 .text:after{content:"";margin-left:calc(var(--horizontal-space) / 2);vertical-align:baseline;display:inline-block;width:100%;height:1px;margin-right:-100%;margin-bottom:5px;background-color:var(--codeBorder)}.page-cheatmd .content-inner h4{display:block;margin:0;padding:.25em var(--horizontal-space);font-weight:400;background:var(--gray100);color:#567;border:solid 1px 1px 0 1px var(--gray100)}.dark .page-cheatmd .content-inner h4{background:#192f50;color:var(--textBody);border:1px solid #192f50;border-bottom:0}.page-cheatmd .content-inner .h2 p{margin:0;display:block;background:var(--gray50);padding:var(--vertical-space) var(--horizontal-space)}.dark .page-cheatmd .content-inner .h2 p{background:var(--gray700)}.page-cheatmd .content-inner .h2 p>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner pre code{padding:var(--vertical-space) var(--horizontal-space)}.page-cheatmd .content-inner .h2 pre{margin:0}.page-cheatmd .content-inner .h2 pre+pre{margin-top:-1px}.page-cheatmd .content-inner pre.wrap{white-space:break-spaces}@media screen and (max-width: 768px){.page-cheatmd .content-inner pre code{border-left-width:1px!important;border-right-width:1px!important}}.page-cheatmd .content-inner .h2 table{display:table;box-sizing:border-box;width:100%;border-collapse:collapse;margin:0}.page-cheatmd .content-inner .h2 th{padding:var(--vertical-space) var(--horizontal-space);line-height:inherit;margin-bottom:-1px;vertical-align:middle;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td{padding:var(--vertical-space) var(--horizontal-space);border:0;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 tr:first-child{border-top:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner .h2 thead{background-color:var(--gray50)}.dark .page-cheatmd .content-inner .h2 thead{background-color:var(--gray700)}.page-cheatmd .content-inner .h2 tbody{background-color:var(--codeBackground)}.page-cheatmd .content-inner .h2 :is(ul,ol){margin:0;padding:0}.page-cheatmd .content-inner .h2 li{list-style-position:inside;padding:.5em var(--horizontal-space);line-height:2em;vertical-align:middle;background-color:var(--codeBackground);border-bottom:1px solid var(--codeBorder);margin-top:0}.page-cheatmd .content-inner .h2 :is(ul,ol)+pre code{border-top:0}.page-cheatmd .content-inner .h2 li>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner section.width-50{display:block;width:50%;margin:0}.page-cheatmd .content-inner section.width-50>section>table{width:100%}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:40px}.page-cheatmd .content-inner section.col-2{column-count:2;height:auto}.page-cheatmd .content-inner section.col-2-left{display:grid;grid-template-columns:calc(100% / 3) auto}.page-cheatmd .content-inner section.col-2-left>h2{grid-column-end:span 2}.page-cheatmd .content-inner section.col-3{column-count:3;height:auto}.page-cheatmd .content-inner section.list-4>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-4>ul>li{flex:0 0 25%}.page-cheatmd .content-inner section.list-6>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 calc(100% / 6)}@media screen and (max-width: 1400px){.page-cheatmd .content-inner section.col-3{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:flex;flex-direction:column}}@media screen and (max-width: 1200px){.page-cheatmd .content-inner section:is(.col-2,.col-3){display:flex;flex-direction:column}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 25%}}@media screen and (max-width: 1000px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 calc(100% / 3)}}@media screen and (max-width: 600px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 50%}.page-cheatmd .content-inner section.width-50{width:100%}}#search{min-height:200px;position:relative}#search .loading{height:64px;width:64px;position:absolute;top:50%;left:calc(50% - 32px)}#search .loading div{box-sizing:border-box;display:block;position:absolute;width:51px;height:51px;margin:6px;border:6px solid var(--coldGray);border-radius:50%;animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:var(--coldGray) transparent transparent transparent}#search .loading div:nth-child(1){animation-delay:-.45s}#search .loading div:nth-child(2){animation-delay:-.3s}#search .loading div:nth-child(3){animation-delay:-.15s}@keyframes loading{0%{transform:rotate(0)}to{transform:rotate(360deg)}}#search .result{margin:2em 0 2.5em}#search .result p{margin:0}#search .result-id{font-size:1.4em;margin:0}#search .result-id a{text-decoration:none;color:var(--textHeaders);transition:var(--transition-colors)}#search .result-id a:is(:visited,:active){color:var(--textHeaders)}#search .result-id a:is(:hover,:focus){color:var(--main)}#search :is(.result-id,.result-elem) em{font-style:normal;color:var(--main)}#search .result-id small{font-weight:400}@keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}.modal{animation-duration:.15s;animation-name:keyboard-shortcuts-show;animation-iteration-count:1;animation-timing-function:ease-in-out;display:none;background-color:#000000bf;position:fixed;inset:0;z-index:300}.modal.shown{display:block}.modal .modal-contents{margin:75px auto 0;max-width:500px;background-color:var(--modalBackground);border-radius:var(--borderRadius-sm);box-shadow:2px 2px 8px #0003;padding:25px 35px 35px}@media screen and (max-width: 768px){.modal .modal-contents{padding:20px}}.modal .modal-header{display:flex;align-items:start}.modal .modal-title{display:inline-block;flex-grow:1;font-size:1.2rem;font-weight:700;margin-bottom:20px}.modal .modal-title button{border:none;background-color:transparent;color:var(--textHeaders);font-weight:700;margin-right:30px;padding-left:0;text-align:left;transition:var(--transition-colors)}.modal .modal-title button:hover{color:var(--main);cursor:pointer}.modal .modal-title button.active{color:var(--main)}.modal .modal-close{cursor:pointer;display:block;font-size:1.5rem;margin:-8px -8px 0 0;padding:8px;opacity:.7;background-color:transparent;color:var(--textHeaders);border:none;transition:var(--transition-opacity)}.modal .modal-close:hover{opacity:1}#keyboard-shortcuts-content dl.shortcut-row{display:flex;align-items:center;justify-content:space-between;margin:0;padding:6px 0 8px;border-bottom:1px solid var(--settingsSectionBorder)}#keyboard-shortcuts-content dl.shortcut-row:last-of-type{border-bottom-style:none}#keyboard-shortcuts-content dl.shortcut-row:first-child{padding-top:0}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){display:inline-block}#keyboard-shortcuts-content kbd>kbd{background-color:var(--settingsInputBorder);color:var(--contrast);border-radius:var(--borderRadius-sm);font-family:inherit;font-weight:700;display:inline-block;line-height:1;padding:4px 7px 6px;min-width:26px;text-align:center;font-size:var(--text-sm)}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){margin:0}#quick-switch-modal-body{width:100%;position:relative}#quick-switch-modal-body .ri-search-2-line{position:absolute;left:0;top:0;padding:4px 10px;color:var(--quickSwitchContour);font-weight:700}#quick-switch-modal-body #quick-switch-input{width:100%;padding:8px 6px 8px 38px;border:none;color:var(--quickSwitchInput);background-color:transparent;border-bottom:1px solid var(--quickSwitchContour);box-sizing:border-box;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-results{margin:0}#quick-switch-modal-body .quick-switch-result{padding:2px 5px;border-bottom:1px dotted var(--quickSwitchContour);transition:all .12s ease-out}#quick-switch-modal-body .quick-switch-result:last-child{border-bottom:none}#quick-switch-modal-body .quick-switch-result:hover{cursor:pointer}#quick-switch-modal-body .quick-switch-result:is(:hover,.selected){border-left:4px solid var(--main);background-color:var(--codeBackground)}.autocomplete{display:none;position:absolute;width:calc(100% - 32px);top:55px}.autocomplete .triangle{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;border-bottom:12px solid var(--autocompleteBackground);position:absolute;top:8px;left:26px;transform:translate(-50%);z-index:100;background-color:transparent}.autocomplete-preview{width:100%;margin:0;height:100%;line-height:20px;background-color:var(--background);font-family:var(--sansFontFamily);border:4px solid var(--autocompleteBorder);padding:12px 16px}.autocomplete-preview div,.autocomplete-preview span{display:none}.autocomplete-preview.loading div{float:left;display:block;border:5px solid var(--autocompleteBorder);border-radius:50%;border-top:5px solid var(--textDetailAccent);width:20px;height:20px;animation:spinner 4s linear infinite}.autocomplete-preview.loading span{color:var(--autocompleteResults);display:inline;margin-left:6px}.autocomplete-preview.loading span:after{color:var(--autocompleteResults);content:"Loading"}@keyframes spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.autocomplete-preview.loading iframe{height:0}.autocomplete-preview iframe{width:100%;height:100%;border:0}.autocomplete-results{list-style:none;margin:0;padding:15px 20px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;color:var(--autocompleteResults);font-family:var(--sansFontFamily);font-weight:300;font-size:.9rem}.autocomplete-results .query{margin-right:auto}.autocomplete-results .bold{color:var(--autocompleteResultsBold);font-weight:400}.autocomplete.shown{display:block}.autocomplete-container{position:absolute;top:15px;width:100%;z-index:200}.autocomplete-suggestions{background-color:var(--autocompleteBackground);border-radius:var(--borderRadius-base);box-shadow:0 15px 99px 0 var(--autocompleteBorder);overflow-y:auto;max-height:450px;white-space:normal;overflow-x:hidden;overscroll-behavior-y:contain;scrollbar-width:thin}.autocomplete-suggestions.previewing:has(.selected){max-height:80vh}.autocomplete-suggestions.previewing:has(.selected) .autocomplete-suggestion:not(.selected){display:none}.autocomplete-suggestions.previewing:not(:has(.selected)) .autocomplete-preview{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview{display:none}.autocomplete-suggestion{color:var(--textHeaders)!important;display:block;padding:12px 20px;text-decoration:none!important;transition:var(--transition-colors);border-top:1px solid var(--suggestionBorder);font-size:.9rem}.autocomplete-suggestion.selected{background-color:var(--autocompleteSelected);box-shadow:inset 2px 0 var(--main)}.autocomplete-suggestion:hover{background-color:var(--autocompleteHover)}.autocomplete-suggestion:not(.selected) .autocomplete-preview-indicator{display:none}.autocomplete-preview-indicator{float:right}.autocomplete-preview-indicator button{color:var(--iconAction);display:flex;align-items:center;text-decoration:none;border:1px solid var(--suggestionBorder);border-radius:var(--borderRadius-base);transition:var(--transition-colors);background-color:var(--autocompletePreview);cursor:pointer;padding:4px 8px;font-size:var(--text-sm)}.autocomplete-preview-indicator button:hover{color:var(--iconActionHover);background-color:var(--autocompleteHover)}.autocomplete-preview-indicator button i{margin-right:4px}.autocomplete-suggestions.previewing .autocomplete-preview-indicator-closed{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview-indicator-open{display:none}.autocomplete-suggestion:hover:not(.selected) .autocomplete-preview-indicator-closed{display:block}.autocomplete-suggestion em{font-style:normal;font-weight:700}.autocomplete-suggestion .description{opacity:.6;padding-top:3px}.autocomplete-suggestion .label{background-color:var(--autocompleteLabelBack);opacity:.6;color:var(--autocompleteLabelFont);padding:4px 8px;border-radius:4px;margin-left:5px;text-transform:uppercase;font-family:var(--sansFontFamily);font-size:.7rem}.autocomplete-suggestion .header{margin-right:5px}.autocomplete-suggestion .title,.autocomplete-suggestion .description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}@media screen and (hover: none){.autocomplete-preview-indicator,.autocomplete-results .press-return{display:none!important}}.tooltip{box-shadow:0 0 10px var(--black-opacity-10);max-height:300px;max-width:500px;padding:0;position:absolute;pointer-events:none;margin:0;z-index:99;top:0;left:0;visibility:hidden;transform:translateY(20px);opacity:0;transition:.2s visibility ease-out,.2s transform ease-out,.2s opacity ease-out}.tooltip.tooltip-shown{visibility:visible;transform:translateY(0);opacity:1}.tooltip .tooltip-body{border:1px solid var(--codeBorder);border-radius:var(--borderRadius-sm);overflow:auto}.tooltip .tooltip-body .signature{min-width:320px;width:100%;line-height:1em}.tooltip .tooltip-body .detail-header{border-left:0;margin-bottom:0;margin-top:0}.tooltip .tooltip-body .docstring{background-color:var(--background);padding:1.2em;margin:0;width:498px}.tooltip .tooltip-body .docstring-plain{max-width:498px;width:auto}.tooltip .tooltip-body .version-info{float:right;font-family:var(--monoFontFamily);font-weight:400;opacity:.3;padding-left:.3em}pre{position:relative}pre:hover .copy-button,pre .copy-button:focus{opacity:1}.copy-button{display:flex;opacity:0;position:absolute;top:7px;right:8px;padding:8px;background-color:transparent;backdrop-filter:blur(8px);border-radius:var(--borderRadius-sm);border:1px solid var(--codeBorder);cursor:pointer;transition:var(--transition-all);font-size:var(--text-sm);line-height:24px;color:currentColor;& svg[aria-live=polite]{display:none}}.copy-button svg{opacity:.5;transition:var(--transition-all)}pre .copy-button:hover svg,pre .copy-button:focus-visible svg{opacity:1}.copy-button svg{width:20px}.copy-button.clicked{opacity:1;color:var(--success);& svg[aria-live=polite]{display:block}}.copy-button.clicked svg{display:none;color:currentColor}#settings-modal-content{margin-top:10px}#settings-modal-content .hidden{display:none}#settings-modal-content .input{box-sizing:border-box;width:80%;padding:8px;font-size:var(--text-sm);background-color:var(--settingsInputBackground);color:var(--settingsInput);border:1px solid var(--settingsInputBorder);border-radius:var(--borderRadius-base);transition:var(--transition-all)}#settings-modal-content .input:focus{border-color:var(--main)}#settings-modal-content .input::placeholder{color:var(--gray400)}#settings-modal-content .switch-button-container{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--settingsSectionBorder);padding:10px 0}#settings-modal-content .switch-button-container:first-of-type{border-top-style:none;padding-top:0}#settings-modal-content .switch-button-container>div>span{font-size:var(--text-md)}#settings-modal-content .switch-button-container>div>p{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--text-sm);line-height:1.4;margin:0;padding-bottom:6px;padding-right:10px}#settings-modal-content .switch-button{position:relative;display:inline-block;flex-shrink:0;width:40px;height:20px;user-select:none;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox{appearance:none;position:absolute;display:block;width:20px;height:20px;border-radius:1000px;background-color:#91a4b7;border:3px solid #e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__bg{display:block;width:100%;height:100%;border-radius:1000px;background-color:#e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox:checked{background-color:#fff;border-color:var(--main);transform:translate(100%)}#settings-modal-content .switch-button__checkbox:checked+.switch-button__bg{background-color:var(--main)}#settings-modal-content .switch-button__checkbox:focus{outline:0}#settings-modal-content .switch-button__checkbox:focus+.switch-button__bg{outline:2px solid var(--main);outline-offset:2px}#settings-modal-content .switch-button__checkbox:focus:not(:focus-visible)+.switch-button__bg{outline:0}#settings-modal-content .settings-select{cursor:pointer;position:relative;border:none;background-color:transparent;color:var(--textBody)}#settings-modal-content .settings-select option{color:initial}#toast{visibility:hidden;opacity:0;position:fixed;z-index:1;left:50%;bottom:1rem;min-width:3rem;margin:0 -1.2rem;padding:.7rem 1.2rem;text-align:center;font-weight:700;border-radius:var(--borderRadius-base);border:1px solid var(--codeBorder);background-color:var(--codeBackground);color:var(--textBody);transition:opacity .4s ease-in-out,transform .3s ease-out;cursor:default}#toast.show{visibility:visible;opacity:1;transform:translateY(-.75rem)}@media (prefers-reduced-motion: reduce){#toast{transition:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;user-select:none}@media print{.body-wrapper{display:block}.sidebar,.sidebar-button,.top-search{display:none}.content{padding-left:0;overflow:visible;left:0;width:100%}.summary-row{break-inside:avoid}#toast{display:none}.content-inner{padding:0}.content-inner .section-heading a.hover-link,.content-inner button.icon-action,.content-inner a.icon-action,.content-inner .bottom-actions{display:none}.footer p:first-of-type{display:none}.content-inner section.admonition{border:2px solid var(--gray400)}.content-inner section.admonition>.admonition-title{color:var(--textHeaders);border-bottom:2px solid var(--gray400)}.content-inner pre code.makeup{border-color:var(--gray400);white-space:break-spaces;break-inside:avoid}.content-inner blockquote code.inline,.content-inner code.inline{border-color:var(--gray400)}}@media print{.page-cheatmd .content-inner *{background-color:transparent!important;border-color:var(--gray400)!important}.page-cheatmd .content-inner{max-width:100%;width:100%;padding:0;font-size:.7em}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:30px}.page-cheatmd .content-inner section.col-2{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:grid}.page-cheatmd .content-inner section.col-3{column-count:3}.page-cheatmd .content-inner h1{margin-top:0;margin-bottom:.5em}.page-cheatmd .content-inner h2.section-heading{font-weight:700;margin-top:1em;column-span:all}.page-cheatmd .content-inner section.h2{break-inside:avoid}.page-cheatmd .content-inner h3{font-weight:700;color:var(--mainDark)}.page-cheatmd .content-inner h3:after{height:2px;background-color:var(--gray400)}.page-cheatmd .content-inner section.h3{min-width:300px;break-inside:avoid}.page-cheatmd .content-inner h4{padding:.5em 0;border:none;font-weight:700;color:#000}.page-cheatmd .content-inner .h2 p{padding-left:0;padding-right:0;border:none!important}.page-cheatmd .content-inner code{line-height:1.5em}.page-cheatmd .content-inner .h2 table{font-variant-numeric:tabular-nums;break-inside:avoid}.page-cheatmd .content-inner .h2 :is(th,td){vertical-align:top;padding-left:0;padding-right:0}.page-cheatmd .content-inner .h2 thead{border-style:solid none;border-width:1px}.page-cheatmd .content-inner .h2 tr{border-bottom:none}.page-cheatmd .content-inner .h2 th{font-weight:700}.page-cheatmd .content-inner .h2 li{padding-left:0;padding-right:0;vertical-align:middle;border-bottom:none}.page-cheatmd .content-inner pre:hover button.copy-button,.page-cheatmd .content-inner div.tooltip{display:none}.page-cheatmd .content-inner footer p:not(.built-using){display:none}}code.makeup .unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.makeup .hll{background-color:#ffc}.makeup .bp{color:#3465a4}.makeup .c,.makeup .c1,.makeup .ch,.makeup .cm,.makeup .cp,.makeup .cpf,.makeup .cs{color:#4d4d4d}.makeup .dl{color:#408200}.makeup .err{color:#a40000;border:#ef2929}.makeup .fm,.makeup .g{color:#4d4d4c}.makeup .gd{color:#a40000}.makeup .ge{color:#4d4d4c;font-style:italic}.makeup .gh{color:navy;font-weight:700}.makeup .gi{color:#00a000}.makeup .go{color:#4d4d4c;font-style:italic}.makeup .gp{color:#4d4d4d}.makeup .gr{color:#ef2929}.makeup .gs{color:#4d4d4c;font-weight:700}.makeup .gt{color:#a40000;font-weight:700}.makeup .gu{color:purple;font-weight:700}.makeup .il{color:#0000cf;font-weight:700}.makeup .k,.makeup .kc,.makeup .kd,.makeup .kn,.makeup .kp,.makeup .kr,.makeup .kt{color:#204a87}.makeup .l{color:#4d4d4c}.makeup .ld{color:#c00}.makeup .m,.makeup .mb,.makeup .mf,.makeup .mh,.makeup .mi,.makeup .mo{color:#2937ab}.makeup .n{color:#4d4d4c}.makeup .na{color:#8a7000}.makeup .nb{color:#204a87}.makeup .nc{color:#0000cf}.makeup .nd{color:#5c35cc;font-weight:700}.makeup .ne{color:#c00;font-weight:700}.makeup .nf{color:#b65800}.makeup .ni{color:#bc5400}.makeup .nl{color:#b65800}.makeup .nn{color:#4d4d4c}.makeup .no{color:#a06600}.makeup .nt{color:#204a87;font-weight:700}.makeup .nv,.makeup .nx{color:#4d4d4c}.makeup .o{color:#bc5400}.makeup .ow{color:#204a87}.makeup .p,.makeup .py{color:#4d4d4c}.makeup .s,.makeup .s1,.makeup .s2,.makeup .sa,.makeup .sb,.makeup .sc{color:#408200}.makeup .sd{color:#8f5902;font-style:italic}.makeup .se{color:#204a87}.makeup .sh{color:#408200}.makeup .si{color:#204a87}.makeup .sr{color:#c00}.makeup .ss{color:#a06600}.makeup .sx{color:#408200}.makeup .vc,.makeup .vg,.makeup .vi,.makeup .vm,.makeup .x{color:#4d4d4c}.dark .makeup{color:#dce1e6}.dark .makeup .hll{background-color:#49483e}.dark .makeup .bp{color:#dce1e6}.dark .makeup .c,.dark .makeup .c1,.dark .makeup .ch,.dark .makeup .cm,.dark .makeup .cp,.dark .makeup .cpf,.dark .makeup .cs{color:#969386}.dark .makeup .dl{color:#e6db74}.dark .makeup .err{color:#960050;background-color:#1e0010}.dark .makeup .fm{color:#a6e22e}.dark .makeup .gd{color:#ff5385}.dark .makeup .ge{font-style:italic}.dark .makeup .gi{color:#a6e22e}.dark .makeup .gp{color:#969386}.dark .makeup .gs{font-weight:700}.dark .makeup .gu{color:#969386}.dark .makeup .gt{color:#ff5385;font-weight:700}.dark .makeup .il{color:#ae81ff}.dark .makeup .k,.dark .makeup .kc,.dark .makeup .kd{color:#66d9ef}.dark .makeup .kn{color:#ff5385}.dark .makeup .kp,.dark .makeup .kr,.dark .makeup .kt{color:#66d9ef}.dark .makeup .l,.dark .makeup .ld,.dark .makeup .m,.dark .makeup .mb,.dark .makeup .mf,.dark .makeup .mh,.dark .makeup .mi,.dark .makeup .mo{color:#ae81ff}.dark .makeup .n{color:#dce1e6}.dark .makeup .na{color:#a6e22e}.dark .makeup .nb{color:#dce1e6}.dark .makeup .nc,.dark .makeup .nd,.dark .makeup .ne,.dark .makeup .nf{color:#a6e22e}.dark .makeup .ni,.dark .makeup .nl,.dark .makeup .nn{color:#dce1e6}.dark .makeup .no{color:#66d9ef}.dark .makeup .nt{color:#ff5385}.dark .makeup .nv{color:#dce1e6}.dark .makeup .nx{color:#a6e22e}.dark .makeup .o,.dark .makeup .ow{color:#ff5385}.dark .makeup .p,.dark .makeup .py{color:#dce1e6}.dark .makeup .s,.dark .makeup .s1,.dark .makeup .s2,.dark .makeup .sa,.dark .makeup .sb,.dark .makeup .sc,.dark .makeup .sd{color:#e6db74}.dark .makeup .se{color:#ae81ff}.dark .makeup .sh,.dark .makeup .si,.dark .makeup .sr,.dark .makeup .ss,.dark .makeup .sx{color:#e6db74}.dark .makeup .vc,.dark .makeup .vg,.dark .makeup .vi,.dark .makeup .vm{color:#dce1e6}.tabset{--borderWidth: 1px;--tabsetPadding: var(--baseLineHeight);margin:var(--baseLineHeight) 0;border:var(--borderWidth) solid var(--tabBorder);padding:0 var(--tabsetPadding);border-radius:var(--borderRadius-lg)}.tabset-tablist{display:flex;overflow:auto;scrollbar-width:thin;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--tabBorderTop)}.tabset-tab{padding:1.1rem var(--tabsetPadding);font-family:var(--sansFontFamily);color:var(--textColor);margin-right:calc(-1 * var(--borderWidth));background-color:transparent;border:0;box-shadow:none;cursor:pointer;border-bottom-width:2px;border-bottom-style:solid;border-bottom-color:transparent;transition:var(--transition-all)}:hover.tabset-tab{border-bottom-color:var(--tabBorderTop);color:var(--textHeaders)}.tabset-tab[aria-selected=true]{border-bottom-color:var(--mainLight);color:var(--textHeaders)}.tabset-tab[aria-selected=true]:focus-visible{background-color:var(--mainLight);border-color:var(--mainLight);color:var(--white)}@media screen and (max-width: 768px){.tabset{--tabsetPadding: calc(var(--baseLineHeight) / 2)}.tabset-panel{padding-top:calc(var(--tabsetPadding) / 2);padding-bottom:calc(var(--tabsetPadding) / 2)}.tabset-panel pre,.tabset-panel blockquote,.tabset-panel section.admonition{margin-left:calc(-1 * var(--tabsetPadding))!important;margin-right:calc(-1 * var(--tabsetPadding))!important}.tabset-panel>pre code{border-left-width:0;border-right-width:0}}@media screen and (max-width: 768px){.tabset-panel>:is(:first-child){&:is(table){margin:.5em 0}}}@media screen and (min-width: 769px){.tabset-panel>:is(:first-child){&:is(blockquote,.admonition){margin-top:1.5em}&:is(p:has(img)){margin-top:1.25em}&:is(table){margin-top:.75em}}.tabset-panel>:is(:last-child){&:is(blockquote,.admonition){margin-bottom:1.5em}&:is(p:not(:has(img)),ul,ol){margin-bottom:1.25em}&:is(table){margin-bottom:.75em}}}body.preview{--sidebarWidth: 0px;overflow:hidden}body.preview .content{height:auto}body.preview .content-inner{padding:0}body.preview .sidebar,body.preview #sidebar-menu,body.preview .hover-link,body.preview .detail-link{display:none}body.preview :is(h1,h2,h3):first-of-type{margin-top:0}body:not(.dark) .content-inner img[src*="#gh-dark-mode-only"],body.dark .content-inner img[src*="#gh-light-mode-only"]{display:none}
+/*! Bundled license information:
+
+modern-normalize/modern-normalize.css:
+  (*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize *)
+*/
diff --git a/formatters/html/dist/html-elixir-M6JNNWMH.css b/formatters/html/dist/html-elixir-M6JNNWMH.css
deleted file mode 100644
index 9e510853a..000000000
--- a/formatters/html/dist/html-elixir-M6JNNWMH.css
+++ /dev/null
@@ -1,6 +0,0 @@
-:root{--main: hsl(250, 68%, 69%);--mainDark: hsl(250, 68%, 59%);--mainDarkest: hsl(250, 68%, 49%);--mainLight: hsl(250, 68%, 74%);--mainLightest: hsl(250, 68%, 79%);--searchBarFocusColor: #8E7CE6;--searchBarBorderColor: rgba(142, 124, 230, .25);--link-color: var(--mainDark);--link-visited-color: var(--mainDarkest)}body.dark{--link-color: var(--mainLightest);--link-visited-color: var(--mainLight)}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-ext-400-normal-N27NCBWW.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-400-normal-W7754I4D.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-ext-700-normal-Q2L5DVMW.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-700-normal-2XVSBPG4.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--content-width: 949px;--content-gutter: 60px;--borderRadius-lg: 14px;--borderRadius-base: 8px;--borderRadius-sm: 3px;--navTabBorderWidth: 2px;--sansFontFamily: "Lato", system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--monoFontFamily: ui-monospace, SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;--baseLineHeight: 1.5em;--gray25: hsl(207, 43%, 98%);--gray50: hsl(207, 43%, 96%);--gray100: hsl(212, 33%, 91%);--gray200: hsl(210, 29%, 88%);--gray300: hsl(210, 26%, 84%);--gray400: hsl(210, 21%, 64%);--gray450: hsl(210, 21%, 49%);--gray500: hsl(210, 21%, 34%);--gray600: hsl(210, 27%, 26%);--gray700: hsl(212, 35%, 17%);--gray750: hsl(214, 46%, 14%);--gray800: hsl(216, 52%, 11%);--gray800-opacity-0: hsla(216, 52%, 11%, 0%);--gray850: hsl(216, 63%, 8%);--gray900: hsl(218, 73%, 4%);--gray900-opacity-50: hsla(218, 73%, 4%, 50%);--gray900-opacity-0: hsla(218, 73%, 4%, 0%);--coldGrayFaint: hsl(240, 5%, 97%);--coldGrayLight: hsl(240, 5%, 88%);--coldGray-lightened-10: hsl(240, 5%, 56%);--coldGray: hsl(240, 5%, 46%);--coldGray-opacity-10: hsla(240, 5%, 46%, 10%);--coldGrayDark: hsl(240, 5%, 28%);--coldGrayDim: hsl(240, 5%, 18%);--yellowLight: hsl(43, 100%, 95%);--yellowDark: hsl(44, 100%, 15%);--yellow: hsl(60, 100%, 43%);--green-lightened-10: hsl(90, 100%, 45%);--green: hsl(90, 100%, 35%);--white: hsl(0, 0%, 100%);--white-opacity-50: hsla(0, 0%, 100%, 50%);--white-opacity-10: hsla(0, 0%, 100%, 10%);--white-opacity-0: hsla(0, 0%, 100%, 0%);--black: hsl(0, 0%, 0%);--black-opacity-10: hsla(0, 0%, 0%, 10%);--black-opacity-50: hsla(0, 0%, 0%, 50%);--orangeDark: hsl(30, 90%, 40%);--orangeLight: hsl(30, 80%, 50%);--text-xs: .75rem;--text-sm: .875rem;--text-md: 1rem;--text-lg: 1.125rem;--text-xl: 1.25rem;--transition-duration: .15s;--transition-timing: cubic-bezier(.4, 0, .2, 1);--transition-all: all var(--transition-duration) var(--transition-timing);--transition-colors: color var(--transition-duration) var(--transition-timing), background-color var(--transition-duration) var(--transition-timing), border-color var(--transition-duration) var(--transition-timing), text-decoration-color var(--transition-duration) var(--transition-timing), fill var(--transition-duration) var(--transition-timing), stroke var(--transition-duration) var(--transition-timing);--transition-opacity: opacity var(--transition-duration) var(--transition-timing)}@media screen and (max-width: 768px){:root{--content-width: 100%;--content-gutter: 20px}}option{background-color:var(--sidebarBackground)}:root{--background: var(--white);--contrast: var(--black);--textBody: var(--gray800);--textHeaders: var(--gray900);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--coldGrayFaint);--iconAction: var(--coldGray);--iconActionHover: var(--gray800);--blockquoteBackground: var(--coldGrayFaint);--blockquoteBorder: var(--coldGrayLight);--tableHeadBorder: var(--gray100);--tableBodyBorder: var(--gray50);--warningBackground: hsl( 33, 100%, 97%);--warningHeadingBackground: hsl( 33, 87%, 64%);--warningHeading: var(--black);--errorBackground: hsl( 7, 81%, 96%);--errorHeadingBackground: hsl( 6, 80%, 60%);--errorHeading: var(--white);--infoBackground: hsl(206, 91%, 96%);--infoHeadingBackground: hsl(213, 92%, 62%);--infoHeading: var(--white);--neutralBackground: hsl(212, 29%, 92%);--neutralHeadingBackground: hsl(220, 43%, 11%);--neutralHeading: var(--white);--tipBackground: hsl(142, 31%, 93%);--tipHeadingBackground: hsl(134, 39%, 36%);--tipHeading: var(--white);--fnSpecAttr: var(--coldGray);--fnDeprecated: var(--yellowLight);--blink: var(--yellowLight);--codeBackground: var(--gray25);--codeBorder: var(--gray100);--codeScrollThumb: var(--gray400);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray25);--admCodeBorder: var(--gray100);--admCodeColor: var(--black);--admInlineCodeColor: var(--black);--admInlineCodeBackground: var(--gray25);--admInlineCodeBorder: var(--gray100);--tabBorder: var(--gray300);--tabBorderTop: var(--gray100);--tabShadow: var(--gray25);--bottomActionsBtnBorder: var(--black-opacity-10);--bottomActionsBtnTitle: var(--mainDark);--modalBackground: var(--white);--settingsInput: var(--gray500);--settingsInputBackground: var(--white);--settingsInputBorder: var(--gray300);--settingsSectionBorder: var(--gray300);--quickSwitchInput: var(--gray500);--quickSwitchContour: var(--coldGray);--success: var(--green);--progressBarColor: var(--gray400);--sidebarAccentMain: var(--black);--sidebarBackground: var(--gray50);--sidebarHeader: var(--gray100);--sidebarMuted: var(--gray800);--sidebarHover: var(--black);--sidebarStaleVersion: var(--orangeDark);--sidebarSubheadings: var(--gray500);--sidebarItem: var(--black);--sidebarInactiveItemBorder: var(--gray500);--sidebarInactiveItemMarker: var(--gray200);--sidebarLanguageAccentBar: var(--mainDark);--sidebarActiveItem: var(--mainDarkest);--searchBarBorder: var(--gray200);--searchAccentMain: var(--gray600);--searchLanguageAccentBar: var(--main);--searchSearch: var(--white);--autocompleteBorder: rgba(3, 9, 19, .1);--autocompletePreview: var(--gray25);--autocompleteSelected: var(--gray25);--autocompleteHover: var(--gray50);--autocompleteBackground: var(--white);--suggestionBorder: var(--gray200);--autocompleteResults: var(--gray600);--autocompleteResultsBold: var(--gray800);--autocompleteLabelBack: var(--gray100);--autocompleteLabelFont: var(--gray600)}body.dark{--background: var(--gray900);--contrast: var(--white);--textBody: var(--gray200);--textHeaders: var(--gray100);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--gray700);--iconAction: var(--coldGray-lightened-10);--iconActionHover: var(--white);--blockquoteBackground: var(--coldGray-opacity-10);--blockquoteBorder: var(--coldGrayDim);--tableHeadBorder: var(--gray600);--tableBodyBorder: var(--gray700);--warningBackground: hsla( 33, 30%, 60%, 10%);--warningHeadingBackground: hsla( 33, 66%, 35%, 80%);--warningHeading: var(--white);--errorBackground: hsla( 7, 30%, 60%, 10%);--errorHeadingBackground: hsla( 6, 70%, 40%, 80%);--errorHeading: var(--white);--infoBackground: hsla(206, 30%, 60%, 10%);--infoHeadingBackground: hsla(213, 55%, 35%, 80%);--infoHeading: var(--white);--neutralBackground: hsl(210, 30%, 60%, 10%);--neutralHeadingBackground: var(--gray600);--neutralHeading: var(--white);--tipBackground: hsla(142, 30%, 60%, 10%);--tipHeadingBackground: hsla(134, 45%, 30%, 80%);--tipHeading: var(--white);--fnSpecAttr: var(--gray400);--fnDeprecated: var(--yellowDark);--blink: var(--gray600);--codeBackground: var(--gray750);--codeBorder: var(--gray600);--codeScrollThumb: var(--gray500);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray750);--admCodeBorder: var(--gray600);--admCodeColor: var(--gray100);--admInlineCodeColor: var(--gray100);--admInlineCodeBackground: var(--gray750);--admInlineCodeBorder: var(--gray600);--tabBorder: var(--gray700);--tabBorderTop: var(--gray700);--tabShadow: var(--black);--bottomActionsBtnBorder: var(--white-opacity-10);--bottomActionsBtnTitle: var(--mainLightest);--modalBackground: var(--gray800);--settingsInput: var(--white);--settingsInputBackground: var(--gray700);--settingsInputBorder: var(--gray700);--settingsSectionBorder: var(--gray700);--quickSwitchInput: var(--gray300);--quickSwitchContour: var(--gray500);--success: var(--green-lightened-10);--progressBarColor: var(--gray300);--sidebarAccentMain: var(--gray50);--sidebarBackground: var(--gray800);--sidebarHeader: var(--gray700);--sidebarMuted: var(--gray300);--sidebarHover: var(--white);--sidebarStaleVersion: var(--orangeLight);--sidebarSubheadings: var(--gray400);--sidebarItem: var(--gray200);--sidebarInactiveItemBorder: var(--gray400);--sidebarInactiveItemMarker: var(--gray600);--sidebarLanguageAccentBar: var(--mainLight);--sidebarActiveItem: var(--mainLightest);--searchBarBorder: var(--gray500);--searchAccentMain: var(--gray300);--searchSearch: var(--gray900);--autocompleteBorder: rgba(28,42,60,.75);--autocompletePreview: var(--gray750);--autocompleteSelected: var(--gray750);--autocompleteHover: var(--gray700);--autocompleteBackground: var(--gray800);--suggestionBorder: var(--gray600);--autocompleteResults: var(--gray200);--autocompleteResultsBold: var(--gray100);--autocompleteLabelBack: var(--gray600);--autocompleteLabelFont: rgba(255, 255, 255, .8)}:root:has(body.dark){color-scheme:dark}*,:before,:after{box-sizing:border-box}html{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}@font-face{font-family:remixicon;src:url(./remixicon-QPNJX265.woff2) format("woff2");font-display:swap}[class^=ri-],[class*=" ri-"],.remix-icon{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:root{--icon-arrow-up-s: "\ea78";--icon-arrow-down-s: "\ea4e";--icon-arrow-right-s: "\ea6e";--icon-add: "\ea13";--icon-subtract: "\f1af";--icon-error-warning: "\eca1";--icon-external-link-line: "\ecaf";--icon-information: "\ee59";--icon-alert: "\ea21";--icon-double-quotes-l: "\ec51";--icon-link-m: "\eeaf";--icon-close-line: "\eb99";--icon-code-s-slash-line: "\ebad";--icon-menu-line: "\ef3e";--icon-search-2-line: "\f0cd";--icon-settings-3-line: "\f0e6";--icon-printer-line: "\f029"}.ri-lg{font-size:1.3333em;line-height:.75em;vertical-align:-.0667em}.ri-settings-3-line:before{content:var(--icon-settings-3-line)}.ri-add-line:before{content:var(--icon-add)}.ri-subtract-line:before{content:var(--icon-subtract)}.ri-arrow-up-s-line:before{content:var(--icon-arrow-up-s)}.ri-arrow-down-s-line:before{content:var(--icon-arrow-down-s)}.ri-arrow-right-s-line:before{content:var(--icon-arrow-right-s)}.ri-external-link-line:before{content:var(--icon-external-link-line)}.ri-search-2-line:before{content:var(--icon-search-2-line)}.ri-menu-line:before{content:var(--icon-menu-line)}.ri-close-line:before{content:var(--icon-close-line)}.ri-link-m:before{content:var(--icon-link-m)}.ri-code-s-slash-line:before{content:var(--icon-code-s-slash-line)}.ri-error-warning-line:before{content:var(--icon-error-warning)}.ri-information-line:before{content:var(--icon-information)}.ri-alert-line:before{content:var(--icon-alert)}.ri-double-quotes-l:before{content:var(--icon-double-quotes-l)}.ri-printer-line:before{content:var(--icon-printer-line)}html,body{box-sizing:border-box;height:100%;width:100%}body{--sidebarWidth: 300px;--sidebarMinWidth: 300px;--sidebarTransitionDuration: .3s;background-color:var(--background);color:var(--textBody);font-size:var(--text-md);line-height:1.6875em;outline:none!important}*,*:before,*:after{box-sizing:inherit}.body-wrapper{display:flex;height:100%}.sidebar{display:none;flex-direction:column;width:var(--sidebarWidth);min-width:var(--sidebarMinWidth);max-width:50vw;height:100%;position:fixed;top:0;left:calc(-1 * var(--sidebarWidth));z-index:100;resize:horizontal}.sidebar-button{padding:26px 12px 18px 19px;position:fixed;z-index:200;top:0;left:0;will-change:transform;transform:translate(0)}.content{left:0;width:100%;height:100%;position:absolute}.content .content-inner{container:content / inline-size;max-width:var(--content-width);min-height:100%;margin:0 auto;padding:0 var(--content-gutter) 10px}.content-inner:focus{outline:none}.sidebar-transition .sidebar,.sidebar-transition .sidebar-button,.sidebar-transition .content{transition:all var(--sidebarTransitionDuration) ease-in-out allow-discrete}.sidebar-open .sidebar,.sidebar-transition .sidebar{display:flex}.sidebar-open .sidebar{left:0}.sidebar-open .sidebar-button{transform:translate(calc(var(--sidebarWidth) - 100%))}.sidebar-open .content{width:calc(100% - var(--sidebarWidth));left:var(--sidebarWidth)}@media screen and (max-width: 768px){.sidebar-open .content{left:0;width:100%}.sidebar{max-width:90vw}body:not(.sidebar-open) .sidebar-button{position:absolute}}.swup-progress-bar{height:2px;background-color:var(--progressBarColor)}.sidebar{--sidebarFontSize: 16px;--sidebarLineHeight: 20px;font-family:var(--sansFontFamily);font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);background-color:var(--sidebarBackground);color:var(--sidebarAccentMain);overflow:hidden;& .sidebar-tabpanel{scrollbar-width:thin}}.apple-os .sidebar{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sidebar ul{list-style:none}.sidebar ul li{margin:0;padding:0 10px}.sidebar a{color:var(--sidebarAccentMain);text-decoration:none;transition:var(--transition-colors)}.sidebar a:hover{color:var(--sidebarHover)}.sidebar .external-link{margin:0 2.5px 0 0}.sidebar .sidebar-header{background-color:var(--sidebarHeader);width:100%}.sidebar .sidebar-projectInfo{display:flex;justify-content:start;align-items:center;gap:8px;margin:12px 34px 12px 14px}.sidebar .sidebar-projectInfo>div{flex:1}.sidebar .sidebar-projectImage{align-self:flex-end}.sidebar .sidebar-projectImage img{display:block;max-width:48px;max-height:48px}.sidebar .sidebar-projectName{font-weight:700;font-size:var(--text-xl);line-height:24px;color:var(--sidebarAccentMain);margin:0;padding:0;word-wrap:break-word;display:block;width:calc(100% - 12px)}.sidebar .sidebar-projectVersion{display:block;position:relative;margin:0;padding:0;font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);color:var(--sidebarMuted);width:calc(100% - 12px)}.sidebar .sidebar-projectVersion form{display:flex}.sidebar .sidebar-projectVersion select{cursor:pointer;position:relative;margin:0;padding:0 0 0 10px;border:none;-webkit-appearance:none;appearance:none;background-color:transparent;color:var(--sidebarMuted);z-index:2}.sidebar .sidebar-projectVersion option{color:initial}.sidebar .sidebar-projectVersionsCaret{position:absolute;left:0;top:2px;z-index:1;font-size:8px;color:var(--sidebarMuted)}.sidebar .sidebar-projectVersion select::-ms-expand{display:none}.sidebar .sidebar-staleVersion{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--sidebarStaleVersion)}.sidebar .sidebar-staleVersion>a{color:var(--sidebarStaleVersion);font-weight:400}.sidebar .sidebar-staleIcon{font-size:var(--text-lg);position:relative;top:3px;line-height:0}.sidebar .sidebar-list-nav{display:flex;margin:0;padding:0;overflow:auto;scrollbar-width:thin}.sidebar .sidebar-list-nav :is(li,li button){text-transform:uppercase;letter-spacing:.02em;font-size:var(--text-sm);color:var(--sidebarSubheadings);white-space:nowrap}.sidebar .sidebar-list-nav li{display:inline-block;padding:0}.sidebar .sidebar-list-nav button{background:none;border:0;border-radius:0;-webkit-appearance:none;text-align:inherit;color:inherit;font-weight:inherit;cursor:pointer;display:inline-block;line-height:27px;padding:4px 14px;transition:var(--transition-all)}.sidebar .sidebar-list-nav button{border-bottom:var(--navTabBorderWidth) solid transparent}.sidebar .sidebar-list-nav button:not([aria-selected]):hover{border-bottom:var(--navTabBorderWidth) solid var(--sidebarInactiveItemBorder);color:var(--sidebarAccentMain);transition:var(--transition-all)}.sidebar .sidebar-list-nav button[aria-selected]{border-bottom:var(--navTabBorderWidth) solid var(--sidebarLanguageAccentBar);color:var(--sidebarAccentMain)}.sidebar .sidebar-tabpanel{flex:1 1 .01%;overflow-y:auto;overscroll-behavior:contain;position:relative;-webkit-overflow-scrolling:touch;padding-top:12px;scroll-padding-top:40px}.sidebar .full-list{margin:0;padding:0 0 20px;position:relative}.sidebar .full-list :is(li,a){display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.sidebar .full-list li{padding:0;line-height:27px}.sidebar .full-list li.group{text-transform:uppercase;font-weight:700;font-size:.8em;margin:1.5em 0 0;line-height:1.8em;color:var(--sidebarSubheadings);padding-left:15px}.sidebar .full-list li.nesting-context{font-weight:700;font-size:.9em;line-height:1.8em;color:var(--sidebarSubheadings);margin-top:10px;padding-left:15px}.sidebar .full-list a{margin-right:30px;padding:3px 0 3px 12px;border-left:var(--navTabBorderWidth) solid transparent;color:var(--sidebarItem)}.sidebar .full-list a[aria-selected]{color:var(--sidebarActiveItem)}.sidebar .full-list button{appearance:none;background-color:transparent;border:0;padding:0;cursor:pointer;color:inherit;width:20px;text-align:center;font-size:calc(1.2 * var(--sidebarFontSize));line-height:var(--sidebarLineHeight);position:absolute;display:block;right:10px;transform:translateY(-100%)}.sidebar .full-list a[aria-selected]+button{color:var(--sidebarActiveItem)}.sidebar .full-list button:after{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:var(--icon-arrow-down-s)}.sidebar .full-list button[aria-expanded=true]:after{content:var(--icon-arrow-up-s)}.sidebar .full-list ul{display:none;margin:10px 0 10px 10px;padding:0}.sidebar .full-list button[aria-expanded=true]+ul{display:block}.sidebar .full-list>li>a{height:27px;line-height:var(--sidebarLineHeight)}.sidebar .full-list>li>a:hover{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li>a[aria-selected]{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li:last-child{margin-bottom:30px}.sidebar .full-list>li.group:first-child{margin-top:0}.sidebar .full-list>li>ul>li:not(:has(li a[aria-selected=true]))>a[aria-selected=true]:before,.sidebar .full-list>li>ul>li>a:hover:before{content:"\2022";position:absolute;margin-left:-15px;color:var(--sidebarActiveItem)}.sidebar .full-list ul li{line-height:var(--sidebarFontSize);padding:0 8px}.sidebar .full-list ul a{padding-left:15px;height:24px}.sidebar .full-list ul button{font-size:var(--sidebarFontSize)}.sidebar .full-list ul button:after{content:var(--icon-add)}.sidebar .full-list ul button[aria-expanded=true]:after{content:var(--icon-subtract)}.sidebar .full-list ul ul{margin:9px 0 9px 10px}.sidebar .full-list ul ul li{height:20px;color:var(--sidebarAccentMain)}.sidebar .full-list ul ul a{border-left:1px solid var(--sidebarInactiveItemMarker);padding:0 10px;height:20px}.sidebar .full-list ul ul a:hover{border-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list ul ul a[aria-selected]{color:var(--sidebarActiveItem);border-color:var(--sidebarLanguageAccentBar)}.sidebar-button{cursor:pointer;background-color:transparent;border:none;font-size:var(--sidebarFontSize);color:var(--sidebarAccentMain)}.sidebar-button:hover{color:var(--sidebarHover)}body:not(.sidebar-open) .sidebar-button{color:var(--contrast)}@media screen and (max-height: 500px){.sidebar{overflow-y:auto}.sidebar .full-list{overflow:visible}}.top-search{background-color:var(--background);top:0;z-index:99;position:relative;width:100%;padding:10px 0}.search-settings{display:flex;column-gap:12px;align-items:center;width:100%;position:relative}.search-bar{border:1px solid var(--searchBarBorder);border-radius:var(--borderRadius-base);height:48px;position:relative;width:100%}.top-search .search-bar .search-input{background-color:var(--searchSearch);border:1px solid transparent;border-radius:var(--borderRadius-base);color:var(--searchAccentMain);position:relative;height:46px;padding:8px 35px 8px 43px;width:100%;transition:var(--transition-all)}.top-search .search-bar .search-input::placeholder{color:var(--searchAccentMain);opacity:.5}.top-search .search-bar .search-input:focus{border:1px solid var(--searchBarFocusColor);border-radius:calc(var(--borderRadius-base) - 1px);position:relative;box-shadow:0 4px 20px 0 var(--searchBarBorderColor) inset}.top-search .search-bar .search-label{position:relative}.top-search .search-bar .search-button{font-size:var(--text-sm);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;left:11px;opacity:.5;padding:5px 1px 5px 5px;position:absolute;top:60%;transform:translateY(-60%);z-index:99;transition:var(--transition-all)}.top-search .search-bar.selected .search-button,.top-search .search-bar .search-button:hover,.top-search .search-bar .search-button:focus{color:var(--top-searchLanguageAccentBar);opacity:1}.top-search .search-bar .search-close-button{font-size:var(--text-md);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;right:11px;margin:0;opacity:.5;padding:5px 1px 5px 0;position:absolute;transform:scaleY(0);top:calc(50% - 13px);transition:var(--transition-all);z-index:99}.top-search .search-bar .search-close-button:hover{opacity:.7}.top-search .search-settings button.icon-settings{display:flex;align-items:center;justify-content:flex-end}.top-search .search-settings .icon-settings{font-size:var(--text-xl);float:right;color:var(--iconAction);text-decoration:none;border:none;transition:color .3s ease-in-out;background-color:transparent;cursor:pointer;padding:0}.top-search .search-settings .icon-settings:hover{color:var(--iconActionHover)}.top-search .search-settings .icon-settings:visited{color:var(--iconAction)}@media screen and (max-width: 768px){.top-search{padding-left:calc(var(--content-gutter) + 36px);padding-right:var(--content-gutter);margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));width:calc(2 * var(--content-gutter) + 100%)}.search-settings{width:100%;box-sizing:border-box}}body.search-focused .search-bar .search-close-button{transform:scaleY(1);transition:var(--transition-all)}@media screen and (hover: hover){body.search-focused .top-search{position:sticky!important}body.search-focused .sidebar-button{position:fixed!important}}@media screen and (hover: none){body.scroll-sticky .top-search{position:sticky!important}body.scroll-sticky .sidebar-button{position:fixed!important}}*:focus,button:focus,[type=button]:focus,[type=reset]:focus,[type=submit]:focus{outline:2px solid var(--main);outline-offset:-2px}*:focus:not(:focus-visible),button:focus:not(:focus-visible),[type=button]:focus:not(:focus-visible),[type=reset]:focus:not(:focus-visible),[type=submit]:focus:not(:focus-visible){outline:0}input[type=text],input[type=number],input[type=date],input[type=datetime],input[type=datetime-local],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=time],input[type=url],input[type=week],textarea{outline:0}.content-inner{font-size:1em;line-height:1.6875em;position:relative;background-color:var(--background);color:var(--textBody)}.content-inner .heading-with-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px}.content-inner .heading-with-actions>*:not(h1){flex-shrink:0}.content-inner .heading-with-actions h1{flex-grow:1;justify-self:flex-start;max-width:100%;margin:0;overflow-wrap:break-word}.content-inner .heading-with-actions .icon-action{width:20px;height:20px;display:flex;justify-content:center;align-items:center;font-weight:400}.content-inner .heading-with-actions.top-heading .icon-action{font-size:1.2rem}@container content (width > 600px){.content-inner .heading-with-actions.top-heading{flex-wrap:nowrap;align-items:flex-start;& h1{padding-right:32px}& .icon-action{padding-top:1.7rem}}}.content-inner .top-heading{padding-top:1rem}.content-inner :is(h1,h2,h3,h4,h5,h6){font-family:var(--sansFontFamily);font-weight:700;line-height:1.5em;word-wrap:break-word;color:var(--textHeaders)}.content-inner h1{font-size:2em;margin:.5em 0}.content-inner h1.section-heading{margin:1.5em 0 .5em}.content-inner h1 small{font-weight:400}.content-inner h2{font-size:1.6em;padding-top:1em;margin-bottom:.5em}.content-inner h3{font-size:1.375em;margin:1em 0 .5em}.content-inner li+li{margin-top:.25em}.content-inner :is(a,.a-main){color:var(--link-color);text-decoration:underline;text-decoration-skip-ink:auto}.content-inner :is(a:visited,.a-main:visited){color:var(--link-visited-color)}.content-inner .icon-action{color:var(--iconAction);text-decoration:none;border:none;transition:var(--transition-colors);background-color:transparent;cursor:pointer}.content-inner .icon-action:hover{color:var(--iconActionHover)}.content-inner .icon-action:visited{color:var(--iconAction)}.content-inner .livebook-badge-container{display:flex}.content-inner a.livebook-badge{display:inline-flex}.content-inner .note{color:var(--iconAction);font-size:var(--text-xs);font-weight:400}.content-inner blockquote,.content-inner section.admonition{border-left:3px solid var(--blockquoteBorder);position:relative;margin:1.5625em 0;padding:0 1.2rem;overflow:auto;background-color:var(--blockquoteBackground);border-radius:var(--borderRadius-base)}.content-inner blockquote p:last-child,.content-inner section.admonition p:last-child{padding-bottom:1em;margin-bottom:0}.content-inner table{margin:2em 0;border-collapse:collapse;display:block;overflow:auto}.content-inner th{text-align:left;font-family:var(--sansFontFamily);font-weight:700;padding-bottom:.5em;white-space:nowrap}.content-inner thead tr{border-bottom:1px solid var(--tableHeadBorder)}.content-inner tbody tr{border-bottom:1px solid var(--tableBodyBorder)}.content-inner tbody tr:last-child{border-bottom:none}.content-inner tr{vertical-align:bottom;height:2.5em}.content-inner :is(td,th){padding:.25em .25em .25em 1em;line-height:2em;vertical-align:top}.content-inner .section-heading{--icon-size: 16px;--icon-spacing: 5px;display:grid;grid-template:1fr / 1fr}@media screen and (max-width: 768px){.content-inner .section-heading{--icon-spacing: 2px}}.content-inner .section-heading>:is(.hover-link,.text){grid-row:1;grid-column:1}.content-inner .section-heading .hover-link{text-decoration:none}.content-inner .section-heading i{font-size:var(--icon-size);color:var(--mainLight);margin-top:.1em;margin-left:calc(-1 * (var(--icon-size) + var(--icon-spacing)));padding-right:var(--icon-spacing);opacity:0}.content-inner :is(blockquote,section.admonition) .section-heading i{display:none}.content-inner .section-heading:is(:hover,:focus,:target) i{opacity:1}.content-inner .app-vsn{display:none!important;font-size:.6em;line-height:1.5em}@media screen and (max-width: 768px){.content-inner .app-vsn{display:block!important}}.content-inner img{max-width:100%}.content-inner strong>code{font-weight:700}.content-inner code{font-family:var(--monoFontFamily);font-style:normal;line-height:24px;font-weight:400;font-size:var(--text-sm)}@media screen and (max-width: 768px){.content-inner :is(ol,ul){padding-left:calc(1.5 * var(--content-gutter))}}.content-inner section.admonition{border-radius:var(--borderRadius-base);border-left:0}.content-inner section.admonition.warning{background-color:var(--warningBackground)}.content-inner section.admonition.error{background-color:var(--errorBackground)}.content-inner section.admonition.info{background-color:var(--infoBackground)}.content-inner section.admonition.neutral{background-color:var(--neutralBackground)}.content-inner section.admonition.tip{background-color:var(--tipBackground)}.content-inner section.admonition>.admonition-title{color:var(--contrast);margin:0 -1.2rem;padding:.7rem 1.2rem .7rem 3.3rem;font-weight:700;font-style:normal}.content-inner section.admonition>.admonition-title:before{color:var(--contrast);position:absolute;left:1rem;font-size:1.8rem;font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.content-inner section.admonition>.admonition-title.warning{background-color:var(--warningHeadingBackground);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.warning:before{content:var(--icon-error-warning);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.error{background-color:var(--errorHeadingBackground);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.error:before{content:var(--icon-error-warning);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.info{background-color:var(--infoHeadingBackground);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.info:before{content:var(--icon-information);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.neutral{background-color:var(--neutralHeadingBackground);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.neutral:before{content:var(--icon-double-quotes-l);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.tip{background-color:var(--tipHeadingBackground);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title.tip:before{content:var(--icon-information);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title code{margin:0 .5ch}.content-inner section.admonition code{background-color:var(--admInlineCodeBackground);border:1px solid var(--admInlineCodeBorder);color:var(--admInlineCodeColor)}.content-inner section.admonition pre code{background-color:var(--admCodeBackground);border:1px solid var(--admCodeBorder);color:var(--admCodeColor)}.content-inner section.admonition>.admonition-title :is(a,a:visited){color:inherit;text-decoration-color:currentColor}@media screen and (max-width: 768px){.content-inner section.admonition{margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0}.content-inner section.admonition>.admonition-title{margin:0 calc(-1 * var(--content-gutter))}}.content-inner .summary h2 a{text-decoration:none;border:none;color:var(--textHeaders)!important}.content-inner .summary span.deprecated{color:var(--darkDeprecated);font-weight:400}.content-inner .summary .summary-row .summary-signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700}.content-inner .summary .summary-row .summary-signature a{text-decoration:none;border:none}.content-inner .summary .summary-row .summary-synopsis{padding:0 1.2em;margin:0 0 .5em}.content-inner .summary .summary-row .summary-synopsis p{margin:0;padding:0}@font-face{font-family:Consolas;src:local("Consolas");size-adjust:110%}.content-inner.content-inner :is(a:has(code,img),pre a){color:var(--link-color);text-shadow:none;text-decoration:none;background-image:none}.content-inner.content-inner :is(a:has(code,img),pre a):is(:visited,:active,:focus,:hover){color:var(--link-visited-color)}.content-inner code{background-color:var(--codeBackground);vertical-align:baseline;border-radius:var(--borderRadius-sm);padding:.1em .2em;border:1px solid var(--codeBorder);text-transform:none}.content-inner code.inline{border-radius:var(--borderRadius-sm);word-wrap:break-word}.content-inner pre{margin:var(--baseLineHeight) 0}.content-inner pre code{display:block;overflow-x:auto;white-space:inherit;padding:1em;scrollbar-width:thin}.content-inner pre code.output{margin:0 12px;max-height:400px;overflow:auto}.content-inner pre code.output+.copy-button{margin-right:12px}.content-inner pre code.output:before{content:"Output";display:block;position:absolute;top:-16px;left:12px;padding:2px 4px;font-size:var(--text-xs);font-family:var(--monoFontFamily);line-height:1;color:var(--textHeaders);background-color:var(--codeBackground);border:1px solid var(--codeBorder);border-bottom:0;border-radius:2px}@media screen and (max-width: 768px){.content-inner>pre:has(code),.content-inner section>pre:has(code){margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter))}.content-inner>pre code,.content-inner section>pre code{padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0;border-left-width:0;border-right-width:0}}@keyframes blink-background{0%,to{background-color:var(--textDetailBackground)}50%{background-color:var(--blink)}}.content-inner .detail:target .detail-header{animation-duration:.55s;animation-name:blink-background;animation-iteration-count:1;animation-timing-function:ease-in-out}.content-inner .detail-header{margin:1em 0;padding:.5em .85em .5em 1em;background-color:var(--textDetailBackground);border-left:3px solid var(--textDetailAccent);font-size:1em;font-family:var(--monoFontFamily);position:relative}.content-inner .detail-header .signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700;line-height:2em}.content-inner .detail-header:hover a.detail-link,.content-inner .detail-header a.detail-link:focus{opacity:1;text-decoration:none}.content-inner .detail-header a.detail-link{transition:var(--transition-opacity);position:absolute;top:0;left:0;display:block;opacity:0;padding:.6em;line-height:1.5em;margin-left:-2.5em;text-decoration:none;border:none}@media screen and (max-width: 768px){.content-inner .detail-header a.detail-link{margin-left:-30px}}.content-inner .specs pre{font-family:var(--monoFontFamily);font-size:var(--text-xs);font-style:normal;line-height:24px;white-space:pre-wrap;margin:0;padding:0}.content-inner .specs .attribute{color:var(--fnSpecAttr)}.content-inner .docstring{margin:1.2em 0 3em 1.2em}@media screen and (max-width: 768px){.content-inner .docstring{margin-left:0}}.content-inner .docstring:is(h2,h3,h4,h5){font-weight:700}.content-inner .docstring h2{font-size:1.1em}.content-inner .docstring h3{font-size:1em}.content-inner .docstring h4{font-size:.95em}.content-inner .docstring h5{font-size:.9em}.content-inner div.deprecated{display:block;padding:1em;background-color:var(--fnDeprecated);border-radius:var(--borderRadius-sm);margin:var(--baseLineHeight) 0}.content-inner .footer{margin:4em auto 1em;text-align:center;font-size:var(--text-sm)}.content-inner .footer .line{display:inline-block}.content-inner .footer .footer-button{background-color:transparent;border:0;cursor:pointer;padding:0 4px}.content-inner .footer .footer-hex-package{margin-right:4px}.content-inner .bottom-actions{display:flex;justify-content:space-between;margin-top:4em;gap:12px}.bottom-actions-item{flex:1 1 0%}.content-inner .bottom-actions .bottom-actions-button{display:flex;text-decoration:none;flex-direction:column;border-radius:var(--borderRadius-sm);border:1px solid var(--bottomActionsBtnBorder);padding:12px 16px;min-width:150px;transition:var(--transition-all)}.content-inner .bottom-actions .bottom-actions-button:hover{border-color:var(--mainLight)}.content-inner .bottom-actions .bottom-actions-button .subheader{font-size:.8em;color:var(--textHeaders);white-space:nowrap}.content-inner .bottom-actions .bottom-actions-button .title{color:var(--bottomActionsBtnTitle)}.content-inner .bottom-actions .bottom-actions-button[rel=prev]{text-align:start}.content-inner .bottom-actions .bottom-actions-button[rel=next]{text-align:end}@media screen and (max-width: 768px){.content-inner .bottom-actions{flex-direction:column-reverse}}.page-cheatmd .content-inner{--horizontal-space: 1.5em;--vertical-space: 1em}@media (max-width: 600px){.page-cheatmd .content-inner{--horizontal-space: 1em;--vertical-space: .75em}}.page-cheatmd .content-inner{max-width:1200px}.page-cheatmd .content-inner h1{margin-bottom:var(--vertical-space)}.page-cheatmd .content-inner h2{margin:var(--vertical-space) 0;column-span:all;color:var(--gray700);font-weight:500}.dark .page-cheatmd .content-inner h2{color:var(--gray200)}.page-cheatmd .content-inner h3{margin:0 0 1em;font-weight:400}.page-cheatmd .content-inner section.h3{min-width:300px;margin:0;padding:0 0 calc(var(--vertical-space) * 2) 0;break-inside:avoid}.page-cheatmd .content-inner h3 .text{overflow:hidden}.page-cheatmd .content-inner h3 .text:after{content:"";margin-left:calc(var(--horizontal-space) / 2);vertical-align:baseline;display:inline-block;width:100%;height:1px;margin-right:-100%;margin-bottom:5px;background-color:var(--codeBorder)}.page-cheatmd .content-inner h4{display:block;margin:0;padding:.25em var(--horizontal-space);font-weight:400;background:var(--gray100);color:#567;border:solid 1px 1px 0 1px var(--gray100)}.dark .page-cheatmd .content-inner h4{background:#192f50;color:var(--textBody);border:1px solid #192f50;border-bottom:0}.page-cheatmd .content-inner .h2 p{margin:0;display:block;background:var(--gray50);padding:var(--vertical-space) var(--horizontal-space)}.dark .page-cheatmd .content-inner .h2 p{background:var(--gray700)}.page-cheatmd .content-inner .h2 p>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner pre code{padding:var(--vertical-space) var(--horizontal-space)}.page-cheatmd .content-inner .h2 pre{margin:0}.page-cheatmd .content-inner .h2 pre+pre{margin-top:-1px}.page-cheatmd .content-inner pre.wrap{white-space:break-spaces}@media screen and (max-width: 768px){.page-cheatmd .content-inner pre code{border-left-width:1px!important;border-right-width:1px!important}}.page-cheatmd .content-inner .h2 table{display:table;box-sizing:border-box;width:100%;border-collapse:collapse;margin:0}.page-cheatmd .content-inner .h2 th{padding:var(--vertical-space) var(--horizontal-space);line-height:inherit;margin-bottom:-1px;vertical-align:middle;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td{padding:var(--vertical-space) var(--horizontal-space);border:0;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 tr:first-child{border-top:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner .h2 thead{background-color:var(--gray50)}.dark .page-cheatmd .content-inner .h2 thead{background-color:var(--gray700)}.page-cheatmd .content-inner .h2 tbody{background-color:var(--codeBackground)}.page-cheatmd .content-inner .h2 :is(ul,ol){margin:0;padding:0}.page-cheatmd .content-inner .h2 li{list-style-position:inside;padding:.5em var(--horizontal-space);line-height:2em;vertical-align:middle;background-color:var(--codeBackground);border-bottom:1px solid var(--codeBorder);margin-top:0}.page-cheatmd .content-inner .h2 :is(ul,ol)+pre code{border-top:0}.page-cheatmd .content-inner .h2 li>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner section.width-50{display:block;width:50%;margin:0}.page-cheatmd .content-inner section.width-50>section>table{width:100%}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:40px}.page-cheatmd .content-inner section.col-2{column-count:2;height:auto}.page-cheatmd .content-inner section.col-2-left{display:grid;grid-template-columns:calc(100% / 3) auto}.page-cheatmd .content-inner section.col-2-left>h2{grid-column-end:span 2}.page-cheatmd .content-inner section.col-3{column-count:3;height:auto}.page-cheatmd .content-inner section.list-4>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-4>ul>li{flex:0 0 25%}.page-cheatmd .content-inner section.list-6>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 calc(100% / 6)}@media screen and (max-width: 1400px){.page-cheatmd .content-inner section.col-3{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:flex;flex-direction:column}}@media screen and (max-width: 1200px){.page-cheatmd .content-inner section:is(.col-2,.col-3){display:flex;flex-direction:column}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 25%}}@media screen and (max-width: 1000px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 calc(100% / 3)}}@media screen and (max-width: 600px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 50%}.page-cheatmd .content-inner section.width-50{width:100%}}#search{min-height:200px;position:relative}#search .loading{height:64px;width:64px;position:absolute;top:50%;left:calc(50% - 32px)}#search .loading div{box-sizing:border-box;display:block;position:absolute;width:51px;height:51px;margin:6px;border:6px solid var(--coldGray);border-radius:50%;animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:var(--coldGray) transparent transparent transparent}#search .loading div:nth-child(1){animation-delay:-.45s}#search .loading div:nth-child(2){animation-delay:-.3s}#search .loading div:nth-child(3){animation-delay:-.15s}@keyframes loading{0%{transform:rotate(0)}to{transform:rotate(360deg)}}#search .result{margin:2em 0 2.5em}#search .result p{margin:0}#search .result-id{font-size:1.4em;margin:0}#search .result-id a{text-decoration:none;color:var(--textHeaders);transition:var(--transition-colors)}#search .result-id a:is(:visited,:active){color:var(--textHeaders)}#search .result-id a:is(:hover,:focus){color:var(--main)}#search :is(.result-id,.result-elem) em{font-style:normal;color:var(--main)}#search .result-id small{font-weight:400}@keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}.modal{animation-duration:.15s;animation-name:keyboard-shortcuts-show;animation-iteration-count:1;animation-timing-function:ease-in-out;display:none;background-color:#000000bf;position:fixed;inset:0;z-index:300}.modal.shown{display:block}.modal .modal-contents{margin:75px auto 0;max-width:500px;background-color:var(--modalBackground);border-radius:var(--borderRadius-sm);box-shadow:2px 2px 8px #0003;padding:25px 35px 35px}@media screen and (max-width: 768px){.modal .modal-contents{padding:20px}}.modal .modal-header{display:flex;align-items:start}.modal .modal-title{display:inline-block;flex-grow:1;font-size:1.2rem;font-weight:700;margin-bottom:20px}.modal .modal-title button{border:none;background-color:transparent;color:var(--textHeaders);font-weight:700;margin-right:30px;padding-left:0;text-align:left;transition:var(--transition-colors)}.modal .modal-title button:hover{color:var(--main);cursor:pointer}.modal .modal-title button.active{color:var(--main)}.modal .modal-close{cursor:pointer;display:block;font-size:1.5rem;margin:-8px -8px 0 0;padding:8px;opacity:.7;background-color:transparent;color:var(--textHeaders);border:none;transition:var(--transition-opacity)}.modal .modal-close:hover{opacity:1}#keyboard-shortcuts-content dl.shortcut-row{display:flex;align-items:center;justify-content:space-between;margin:0;padding:6px 0 8px;border-bottom:1px solid var(--settingsSectionBorder)}#keyboard-shortcuts-content dl.shortcut-row:last-of-type{border-bottom-style:none}#keyboard-shortcuts-content dl.shortcut-row:first-child{padding-top:0}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){display:inline-block}#keyboard-shortcuts-content kbd>kbd{background-color:var(--settingsInputBorder);color:var(--contrast);border-radius:var(--borderRadius-sm);font-family:inherit;font-weight:700;display:inline-block;line-height:1;padding:4px 7px 6px;min-width:26px;text-align:center;font-size:var(--text-sm)}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){margin:0}#quick-switch-modal-body{width:100%;position:relative}#quick-switch-modal-body .ri-search-2-line{position:absolute;left:0;top:0;padding:4px 10px;color:var(--quickSwitchContour);font-weight:700}#quick-switch-modal-body #quick-switch-input{width:100%;padding:8px 6px 8px 38px;border:none;color:var(--quickSwitchInput);background-color:transparent;border-bottom:1px solid var(--quickSwitchContour);box-sizing:border-box;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-results{margin:0}#quick-switch-modal-body .quick-switch-result{padding:2px 5px;border-bottom:1px dotted var(--quickSwitchContour);transition:all .12s ease-out}#quick-switch-modal-body .quick-switch-result:last-child{border-bottom:none}#quick-switch-modal-body .quick-switch-result:hover{cursor:pointer}#quick-switch-modal-body .quick-switch-result:is(:hover,.selected){border-left:4px solid var(--main);background-color:var(--codeBackground)}.autocomplete{display:none;position:absolute;width:calc(100% - 32px);top:55px}.autocomplete .triangle{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;border-bottom:12px solid var(--autocompleteBackground);position:absolute;top:8px;left:26px;transform:translate(-50%);z-index:100;background-color:transparent}.autocomplete-preview{width:100%;margin:0;height:100%;line-height:20px;background-color:var(--background);font-family:var(--sansFontFamily);border:4px solid var(--autocompleteBorder);padding:12px 16px}.autocomplete-preview div,.autocomplete-preview span{display:none}.autocomplete-preview.loading div{float:left;display:block;border:5px solid var(--autocompleteBorder);border-radius:50%;border-top:5px solid var(--textDetailAccent);width:20px;height:20px;animation:spinner 4s linear infinite}.autocomplete-preview.loading span{color:var(--autocompleteResults);display:inline;margin-left:6px}.autocomplete-preview.loading span:after{color:var(--autocompleteResults);content:"Loading"}@keyframes spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.autocomplete-preview.loading iframe{height:0}.autocomplete-preview iframe{width:100%;height:100%;border:0}.autocomplete-results{list-style:none;margin:0;padding:15px 20px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;color:var(--autocompleteResults);font-family:var(--sansFontFamily);font-weight:300;font-size:.9rem}.autocomplete-results .query{margin-right:auto}.autocomplete-results .bold{color:var(--autocompleteResultsBold);font-weight:400}.autocomplete.shown{display:block}.autocomplete-container{position:absolute;top:15px;width:100%;z-index:200}.autocomplete-suggestions{background-color:var(--autocompleteBackground);border-radius:var(--borderRadius-base);box-shadow:0 15px 99px 0 var(--autocompleteBorder);overflow-y:auto;max-height:450px;white-space:normal;overflow-x:hidden;overscroll-behavior-y:contain;scrollbar-width:thin}.autocomplete-suggestions.previewing:has(.selected){max-height:80vh}.autocomplete-suggestions.previewing:has(.selected) .autocomplete-suggestion:not(.selected){display:none}.autocomplete-suggestions.previewing:not(:has(.selected)) .autocomplete-preview{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview{display:none}.autocomplete-suggestion{color:var(--textHeaders)!important;display:block;padding:12px 20px;text-decoration:none!important;transition:var(--transition-colors);border-top:1px solid var(--suggestionBorder);font-size:.9rem}.autocomplete-suggestion.selected{background-color:var(--autocompleteSelected);box-shadow:inset 2px 0 var(--main)}.autocomplete-suggestion:hover{background-color:var(--autocompleteHover)}.autocomplete-suggestion:not(.selected) .autocomplete-preview-indicator{display:none}.autocomplete-preview-indicator{float:right}.autocomplete-preview-indicator button{color:var(--iconAction);display:flex;align-items:center;text-decoration:none;border:1px solid var(--suggestionBorder);border-radius:var(--borderRadius-base);transition:var(--transition-colors);background-color:var(--autocompletePreview);cursor:pointer;padding:4px 8px;font-size:var(--text-sm)}.autocomplete-preview-indicator button:hover{color:var(--iconActionHover);background-color:var(--autocompleteHover)}.autocomplete-preview-indicator button i{margin-right:4px}.autocomplete-suggestions.previewing .autocomplete-preview-indicator-closed{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview-indicator-open{display:none}.autocomplete-suggestion:hover:not(.selected) .autocomplete-preview-indicator-closed{display:block}.autocomplete-suggestion em{font-style:normal;font-weight:700}.autocomplete-suggestion .description{opacity:.6;padding-top:3px}.autocomplete-suggestion .label{background-color:var(--autocompleteLabelBack);opacity:.6;color:var(--autocompleteLabelFont);padding:4px 8px;border-radius:4px;margin-left:5px;text-transform:uppercase;font-family:var(--sansFontFamily);font-size:.7rem}.autocomplete-suggestion .header{margin-right:5px}.autocomplete-suggestion .title,.autocomplete-suggestion .description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}@media screen and (hover: none){.autocomplete-preview-indicator,.autocomplete-results .press-return{display:none!important}}.tooltip{box-shadow:0 0 10px var(--black-opacity-10);max-height:300px;max-width:500px;padding:0;position:absolute;pointer-events:none;margin:0;z-index:99;top:0;left:0;visibility:hidden;transform:translateY(20px);opacity:0;transition:.2s visibility ease-out,.2s transform ease-out,.2s opacity ease-out}.tooltip.tooltip-shown{visibility:visible;transform:translateY(0);opacity:1}.tooltip .tooltip-body{border:1px solid var(--codeBorder);border-radius:var(--borderRadius-sm);overflow:auto}.tooltip .tooltip-body .signature{min-width:320px;width:100%;line-height:1em}.tooltip .tooltip-body .detail-header{border-left:0;margin-bottom:0;margin-top:0}.tooltip .tooltip-body .docstring{background-color:var(--background);padding:1.2em;margin:0;width:498px}.tooltip .tooltip-body .docstring-plain{max-width:498px;width:auto}.tooltip .tooltip-body .version-info{float:right;font-family:var(--monoFontFamily);font-weight:400;opacity:.3;padding-left:.3em}pre{position:relative}pre:hover .copy-button,pre .copy-button:focus{opacity:1}.copy-button{display:flex;opacity:0;position:absolute;top:7px;right:8px;padding:8px;background-color:transparent;backdrop-filter:blur(8px);border-radius:var(--borderRadius-sm);border:1px solid var(--codeBorder);cursor:pointer;transition:var(--transition-all);font-size:var(--text-sm);line-height:24px;color:currentColor;& svg[aria-live=polite]{display:none}}.copy-button svg{opacity:.5;transition:var(--transition-all)}pre .copy-button:hover svg,pre .copy-button:focus-visible svg{opacity:1}.copy-button svg{width:20px}.copy-button.clicked{opacity:1;color:var(--success);& svg[aria-live=polite]{display:block}}.copy-button.clicked svg{display:none;color:currentColor}#settings-modal-content{margin-top:10px}#settings-modal-content .hidden{display:none}#settings-modal-content .input{box-sizing:border-box;width:80%;padding:8px;font-size:var(--text-sm);background-color:var(--settingsInputBackground);color:var(--settingsInput);border:1px solid var(--settingsInputBorder);border-radius:var(--borderRadius-base);transition:var(--transition-all)}#settings-modal-content .input:focus{border-color:var(--main)}#settings-modal-content .input::placeholder{color:var(--gray400)}#settings-modal-content .switch-button-container{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--settingsSectionBorder);padding:10px 0}#settings-modal-content .switch-button-container:first-of-type{border-top-style:none;padding-top:0}#settings-modal-content .switch-button-container>div>span{font-size:var(--text-md)}#settings-modal-content .switch-button-container>div>p{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--text-sm);line-height:1.4;margin:0;padding-bottom:6px;padding-right:10px}#settings-modal-content .switch-button{position:relative;display:inline-block;flex-shrink:0;width:40px;height:20px;user-select:none;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox{appearance:none;position:absolute;display:block;width:20px;height:20px;border-radius:1000px;background-color:#91a4b7;border:3px solid #e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__bg{display:block;width:100%;height:100%;border-radius:1000px;background-color:#e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox:checked{background-color:#fff;border-color:var(--main);transform:translate(100%)}#settings-modal-content .switch-button__checkbox:checked+.switch-button__bg{background-color:var(--main)}#settings-modal-content .switch-button__checkbox:focus{outline:0}#settings-modal-content .switch-button__checkbox:focus+.switch-button__bg{outline:2px solid var(--main);outline-offset:2px}#settings-modal-content .switch-button__checkbox:focus:not(:focus-visible)+.switch-button__bg{outline:0}#settings-modal-content .settings-select{cursor:pointer;position:relative;border:none;background-color:transparent;color:var(--textBody)}#settings-modal-content .settings-select option{color:initial}#toast{visibility:hidden;opacity:0;position:fixed;z-index:1;left:50%;bottom:1rem;min-width:3rem;margin:0 -1.2rem;padding:.7rem 1.2rem;text-align:center;font-weight:700;border-radius:var(--borderRadius-base);border:1px solid var(--codeBorder);background-color:var(--codeBackground);color:var(--textBody);transition:opacity .4s ease-in-out,transform .3s ease-out;cursor:default}#toast.show{visibility:visible;opacity:1;transform:translateY(-.75rem)}@media (prefers-reduced-motion: reduce){#toast{transition:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;user-select:none}@media print{.body-wrapper{display:block}.sidebar,.sidebar-button,.top-search{display:none}.content{padding-left:0;overflow:visible;left:0;width:100%}.summary-row{break-inside:avoid}#toast{display:none}.content-inner{padding:0}.content-inner .section-heading a.hover-link,.content-inner button.icon-action,.content-inner a.icon-action,.content-inner .bottom-actions{display:none}.footer p:first-of-type{display:none}.content-inner section.admonition{border:2px solid var(--gray400)}.content-inner section.admonition>.admonition-title{color:var(--textHeaders);border-bottom:2px solid var(--gray400)}.content-inner pre code.makeup{border-color:var(--gray400);white-space:break-spaces;break-inside:avoid}.content-inner blockquote code.inline,.content-inner code.inline{border-color:var(--gray400)}}@media print{.page-cheatmd .content-inner *{background-color:transparent!important;border-color:var(--gray400)!important}.page-cheatmd .content-inner{max-width:100%;width:100%;padding:0;font-size:.7em}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:30px}.page-cheatmd .content-inner section.col-2{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:grid}.page-cheatmd .content-inner section.col-3{column-count:3}.page-cheatmd .content-inner h1{margin-top:0;margin-bottom:.5em}.page-cheatmd .content-inner h2.section-heading{font-weight:700;margin-top:1em;column-span:all}.page-cheatmd .content-inner section.h2{break-inside:avoid}.page-cheatmd .content-inner h3{font-weight:700;color:var(--mainDark)}.page-cheatmd .content-inner h3:after{height:2px;background-color:var(--gray400)}.page-cheatmd .content-inner section.h3{min-width:300px;break-inside:avoid}.page-cheatmd .content-inner h4{padding:.5em 0;border:none;font-weight:700;color:#000}.page-cheatmd .content-inner .h2 p{padding-left:0;padding-right:0;border:none!important}.page-cheatmd .content-inner code{line-height:1.5em}.page-cheatmd .content-inner .h2 table{font-variant-numeric:tabular-nums;break-inside:avoid}.page-cheatmd .content-inner .h2 :is(th,td){vertical-align:top;padding-left:0;padding-right:0}.page-cheatmd .content-inner .h2 thead{border-style:solid none;border-width:1px}.page-cheatmd .content-inner .h2 tr{border-bottom:none}.page-cheatmd .content-inner .h2 th{font-weight:700}.page-cheatmd .content-inner .h2 li{padding-left:0;padding-right:0;vertical-align:middle;border-bottom:none}.page-cheatmd .content-inner pre:hover button.copy-button,.page-cheatmd .content-inner div.tooltip{display:none}.page-cheatmd .content-inner footer p:not(.built-using){display:none}}code.makeup .unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.makeup .hll{background-color:#ffc}.makeup .bp{color:#3465a4}.makeup .c,.makeup .c1,.makeup .ch,.makeup .cm,.makeup .cp,.makeup .cpf,.makeup .cs{color:#4d4d4d}.makeup .dl{color:#408200}.makeup .err{color:#a40000;border:#ef2929}.makeup .fm,.makeup .g{color:#4d4d4c}.makeup .gd{color:#a40000}.makeup .ge{color:#4d4d4c;font-style:italic}.makeup .gh{color:navy;font-weight:700}.makeup .gi{color:#00a000}.makeup .go{color:#4d4d4c;font-style:italic}.makeup .gp{color:#4d4d4d}.makeup .gr{color:#ef2929}.makeup .gs{color:#4d4d4c;font-weight:700}.makeup .gt{color:#a40000;font-weight:700}.makeup .gu{color:purple;font-weight:700}.makeup .il{color:#0000cf;font-weight:700}.makeup .k,.makeup .kc,.makeup .kd,.makeup .kn,.makeup .kp,.makeup .kr,.makeup .kt{color:#204a87}.makeup .l{color:#4d4d4c}.makeup .ld{color:#c00}.makeup .m,.makeup .mb,.makeup .mf,.makeup .mh,.makeup .mi,.makeup .mo{color:#2937ab}.makeup .n{color:#4d4d4c}.makeup .na{color:#8a7000}.makeup .nb{color:#204a87}.makeup .nc{color:#0000cf}.makeup .nd{color:#5c35cc;font-weight:700}.makeup .ne{color:#c00;font-weight:700}.makeup .nf{color:#b65800}.makeup .ni{color:#bc5400}.makeup .nl{color:#b65800}.makeup .nn{color:#4d4d4c}.makeup .no{color:#a06600}.makeup .nt{color:#204a87;font-weight:700}.makeup .nv,.makeup .nx{color:#4d4d4c}.makeup .o{color:#bc5400}.makeup .ow{color:#204a87}.makeup .p,.makeup .py{color:#4d4d4c}.makeup .s,.makeup .s1,.makeup .s2,.makeup .sa,.makeup .sb,.makeup .sc{color:#408200}.makeup .sd{color:#8f5902;font-style:italic}.makeup .se{color:#204a87}.makeup .sh{color:#408200}.makeup .si{color:#204a87}.makeup .sr{color:#c00}.makeup .ss{color:#a06600}.makeup .sx{color:#408200}.makeup .vc,.makeup .vg,.makeup .vi,.makeup .vm,.makeup .x{color:#4d4d4c}.dark .makeup{color:#dce1e6}.dark .makeup .hll{background-color:#49483e}.dark .makeup .bp{color:#dce1e6}.dark .makeup .c,.dark .makeup .c1,.dark .makeup .ch,.dark .makeup .cm,.dark .makeup .cp,.dark .makeup .cpf,.dark .makeup .cs{color:#969386}.dark .makeup .dl{color:#e6db74}.dark .makeup .err{color:#960050;background-color:#1e0010}.dark .makeup .fm{color:#a6e22e}.dark .makeup .gd{color:#ff5385}.dark .makeup .ge{font-style:italic}.dark .makeup .gi{color:#a6e22e}.dark .makeup .gp{color:#969386}.dark .makeup .gs{font-weight:700}.dark .makeup .gu{color:#969386}.dark .makeup .gt{color:#ff5385;font-weight:700}.dark .makeup .il{color:#ae81ff}.dark .makeup .k,.dark .makeup .kc,.dark .makeup .kd{color:#66d9ef}.dark .makeup .kn{color:#ff5385}.dark .makeup .kp,.dark .makeup .kr,.dark .makeup .kt{color:#66d9ef}.dark .makeup .l,.dark .makeup .ld,.dark .makeup .m,.dark .makeup .mb,.dark .makeup .mf,.dark .makeup .mh,.dark .makeup .mi,.dark .makeup .mo{color:#ae81ff}.dark .makeup .n{color:#dce1e6}.dark .makeup .na{color:#a6e22e}.dark .makeup .nb{color:#dce1e6}.dark .makeup .nc,.dark .makeup .nd,.dark .makeup .ne,.dark .makeup .nf{color:#a6e22e}.dark .makeup .ni,.dark .makeup .nl,.dark .makeup .nn{color:#dce1e6}.dark .makeup .no{color:#66d9ef}.dark .makeup .nt{color:#ff5385}.dark .makeup .nv{color:#dce1e6}.dark .makeup .nx{color:#a6e22e}.dark .makeup .o,.dark .makeup .ow{color:#ff5385}.dark .makeup .p,.dark .makeup .py{color:#dce1e6}.dark .makeup .s,.dark .makeup .s1,.dark .makeup .s2,.dark .makeup .sa,.dark .makeup .sb,.dark .makeup .sc,.dark .makeup .sd{color:#e6db74}.dark .makeup .se{color:#ae81ff}.dark .makeup .sh,.dark .makeup .si,.dark .makeup .sr,.dark .makeup .ss,.dark .makeup .sx{color:#e6db74}.dark .makeup .vc,.dark .makeup .vg,.dark .makeup .vi,.dark .makeup .vm{color:#dce1e6}.tabset{--borderWidth: 1px;--tabsetPadding: var(--baseLineHeight);margin:var(--baseLineHeight) 0;border:var(--borderWidth) solid var(--tabBorder);padding:0 var(--tabsetPadding);border-radius:var(--borderRadius-lg)}.tabset-tablist{display:flex;overflow:auto;scrollbar-width:thin;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--tabBorderTop)}.tabset-tab{padding:1.1rem var(--tabsetPadding);font-family:var(--sansFontFamily);color:var(--textColor);margin-right:calc(-1 * var(--borderWidth));background-color:transparent;border:0;box-shadow:none;cursor:pointer;border-bottom-width:2px;border-bottom-style:solid;border-bottom-color:transparent;transition:var(--transition-all)}:hover.tabset-tab{border-bottom-color:var(--tabBorderTop);color:var(--textHeaders)}.tabset-tab[aria-selected=true]{border-bottom-color:var(--mainLight);color:var(--textHeaders)}.tabset-tab[aria-selected=true]:focus-visible{background-color:var(--mainLight);border-color:var(--mainLight);color:var(--white)}@media screen and (max-width: 768px){.tabset{--tabsetPadding: calc(var(--baseLineHeight) / 2)}.tabset-panel{padding-top:calc(var(--tabsetPadding) / 2);padding-bottom:calc(var(--tabsetPadding) / 2)}.tabset-panel pre,.tabset-panel blockquote,.tabset-panel section.admonition{margin-left:calc(-1 * var(--tabsetPadding))!important;margin-right:calc(-1 * var(--tabsetPadding))!important}.tabset-panel>pre code{border-left-width:0;border-right-width:0}}@media screen and (max-width: 768px){.tabset-panel>:is(:first-child){&:is(table){margin:.5em 0}}}@media screen and (min-width: 769px){.tabset-panel>:is(:first-child){&:is(blockquote,.admonition){margin-top:1.5em}&:is(p:has(img)){margin-top:1.25em}&:is(table){margin-top:.75em}}.tabset-panel>:is(:last-child){&:is(blockquote,.admonition){margin-bottom:1.5em}&:is(p:not(:has(img)),ul,ol){margin-bottom:1.25em}&:is(table){margin-bottom:.75em}}}body.preview{--sidebarWidth: 0px;overflow:hidden}body.preview .content{height:auto}body.preview .content-inner{padding:0}body.preview .sidebar,body.preview #sidebar-menu,body.preview .hover-link,body.preview .detail-link{display:none}body.preview :is(h1,h2,h3):first-of-type{margin-top:0}body:not(.dark) .content-inner img[src*="#gh-dark-mode-only"],body.dark .content-inner img[src*="#gh-light-mode-only"]{display:none}
-/*! Bundled license information:
-
-modern-normalize/modern-normalize.css:
-  (*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize *)
-*/
diff --git a/formatters/html/dist/html-erlang-5OIFJN4X.css b/formatters/html/dist/html-erlang-5OIFJN4X.css
deleted file mode 100644
index 3e0214361..000000000
--- a/formatters/html/dist/html-erlang-5OIFJN4X.css
+++ /dev/null
@@ -1,6 +0,0 @@
-:root{--main: hsl(0, 100%, 44%);--mainDark: hsl(0, 100%, 34%);--mainDarkest: hsl(0, 100%, 24%);--mainLight: hsl(0, 100%, 64%);--mainLightest: hsl(0, 100%, 74%);--searchBarFocusColor: hsl(0, 100%, 50%);--searchBarBorderColor: rgb(255, 71, 71, .1);--link-color: hsl(212, 96%, 45%);--link-visited-color: hsl(212, 96%, 40%)}body.dark{--link-color: hsl(212, 56%, 72%);--link-visited-color: hsl(212, 56%, 67%)}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-ext-400-normal-N27NCBWW.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-400-normal-W7754I4D.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-ext-700-normal-Q2L5DVMW.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-700-normal-2XVSBPG4.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--content-width: 949px;--content-gutter: 60px;--borderRadius-lg: 14px;--borderRadius-base: 8px;--borderRadius-sm: 3px;--navTabBorderWidth: 2px;--sansFontFamily: "Lato", system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--monoFontFamily: ui-monospace, SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;--baseLineHeight: 1.5em;--gray25: hsl(207, 43%, 98%);--gray50: hsl(207, 43%, 96%);--gray100: hsl(212, 33%, 91%);--gray200: hsl(210, 29%, 88%);--gray300: hsl(210, 26%, 84%);--gray400: hsl(210, 21%, 64%);--gray450: hsl(210, 21%, 49%);--gray500: hsl(210, 21%, 34%);--gray600: hsl(210, 27%, 26%);--gray700: hsl(212, 35%, 17%);--gray750: hsl(214, 46%, 14%);--gray800: hsl(216, 52%, 11%);--gray800-opacity-0: hsla(216, 52%, 11%, 0%);--gray850: hsl(216, 63%, 8%);--gray900: hsl(218, 73%, 4%);--gray900-opacity-50: hsla(218, 73%, 4%, 50%);--gray900-opacity-0: hsla(218, 73%, 4%, 0%);--coldGrayFaint: hsl(240, 5%, 97%);--coldGrayLight: hsl(240, 5%, 88%);--coldGray-lightened-10: hsl(240, 5%, 56%);--coldGray: hsl(240, 5%, 46%);--coldGray-opacity-10: hsla(240, 5%, 46%, 10%);--coldGrayDark: hsl(240, 5%, 28%);--coldGrayDim: hsl(240, 5%, 18%);--yellowLight: hsl(43, 100%, 95%);--yellowDark: hsl(44, 100%, 15%);--yellow: hsl(60, 100%, 43%);--green-lightened-10: hsl(90, 100%, 45%);--green: hsl(90, 100%, 35%);--white: hsl(0, 0%, 100%);--white-opacity-50: hsla(0, 0%, 100%, 50%);--white-opacity-10: hsla(0, 0%, 100%, 10%);--white-opacity-0: hsla(0, 0%, 100%, 0%);--black: hsl(0, 0%, 0%);--black-opacity-10: hsla(0, 0%, 0%, 10%);--black-opacity-50: hsla(0, 0%, 0%, 50%);--orangeDark: hsl(30, 90%, 40%);--orangeLight: hsl(30, 80%, 50%);--text-xs: .75rem;--text-sm: .875rem;--text-md: 1rem;--text-lg: 1.125rem;--text-xl: 1.25rem;--transition-duration: .15s;--transition-timing: cubic-bezier(.4, 0, .2, 1);--transition-all: all var(--transition-duration) var(--transition-timing);--transition-colors: color var(--transition-duration) var(--transition-timing), background-color var(--transition-duration) var(--transition-timing), border-color var(--transition-duration) var(--transition-timing), text-decoration-color var(--transition-duration) var(--transition-timing), fill var(--transition-duration) var(--transition-timing), stroke var(--transition-duration) var(--transition-timing);--transition-opacity: opacity var(--transition-duration) var(--transition-timing)}@media screen and (max-width: 768px){:root{--content-width: 100%;--content-gutter: 20px}}option{background-color:var(--sidebarBackground)}:root{--background: var(--white);--contrast: var(--black);--textBody: var(--gray800);--textHeaders: var(--gray900);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--coldGrayFaint);--iconAction: var(--coldGray);--iconActionHover: var(--gray800);--blockquoteBackground: var(--coldGrayFaint);--blockquoteBorder: var(--coldGrayLight);--tableHeadBorder: var(--gray100);--tableBodyBorder: var(--gray50);--warningBackground: hsl( 33, 100%, 97%);--warningHeadingBackground: hsl( 33, 87%, 64%);--warningHeading: var(--black);--errorBackground: hsl( 7, 81%, 96%);--errorHeadingBackground: hsl( 6, 80%, 60%);--errorHeading: var(--white);--infoBackground: hsl(206, 91%, 96%);--infoHeadingBackground: hsl(213, 92%, 62%);--infoHeading: var(--white);--neutralBackground: hsl(212, 29%, 92%);--neutralHeadingBackground: hsl(220, 43%, 11%);--neutralHeading: var(--white);--tipBackground: hsl(142, 31%, 93%);--tipHeadingBackground: hsl(134, 39%, 36%);--tipHeading: var(--white);--fnSpecAttr: var(--coldGray);--fnDeprecated: var(--yellowLight);--blink: var(--yellowLight);--codeBackground: var(--gray25);--codeBorder: var(--gray100);--codeScrollThumb: var(--gray400);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray25);--admCodeBorder: var(--gray100);--admCodeColor: var(--black);--admInlineCodeColor: var(--black);--admInlineCodeBackground: var(--gray25);--admInlineCodeBorder: var(--gray100);--tabBorder: var(--gray300);--tabBorderTop: var(--gray100);--tabShadow: var(--gray25);--bottomActionsBtnBorder: var(--black-opacity-10);--bottomActionsBtnTitle: var(--mainDark);--modalBackground: var(--white);--settingsInput: var(--gray500);--settingsInputBackground: var(--white);--settingsInputBorder: var(--gray300);--settingsSectionBorder: var(--gray300);--quickSwitchInput: var(--gray500);--quickSwitchContour: var(--coldGray);--success: var(--green);--progressBarColor: var(--gray400);--sidebarAccentMain: var(--black);--sidebarBackground: var(--gray50);--sidebarHeader: var(--gray100);--sidebarMuted: var(--gray800);--sidebarHover: var(--black);--sidebarStaleVersion: var(--orangeDark);--sidebarSubheadings: var(--gray500);--sidebarItem: var(--black);--sidebarInactiveItemBorder: var(--gray500);--sidebarInactiveItemMarker: var(--gray200);--sidebarLanguageAccentBar: var(--mainDark);--sidebarActiveItem: var(--mainDarkest);--searchBarBorder: var(--gray200);--searchAccentMain: var(--gray600);--searchLanguageAccentBar: var(--main);--searchSearch: var(--white);--autocompleteBorder: rgba(3, 9, 19, .1);--autocompletePreview: var(--gray25);--autocompleteSelected: var(--gray25);--autocompleteHover: var(--gray50);--autocompleteBackground: var(--white);--suggestionBorder: var(--gray200);--autocompleteResults: var(--gray600);--autocompleteResultsBold: var(--gray800);--autocompleteLabelBack: var(--gray100);--autocompleteLabelFont: var(--gray600)}body.dark{--background: var(--gray900);--contrast: var(--white);--textBody: var(--gray200);--textHeaders: var(--gray100);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--gray700);--iconAction: var(--coldGray-lightened-10);--iconActionHover: var(--white);--blockquoteBackground: var(--coldGray-opacity-10);--blockquoteBorder: var(--coldGrayDim);--tableHeadBorder: var(--gray600);--tableBodyBorder: var(--gray700);--warningBackground: hsla( 33, 30%, 60%, 10%);--warningHeadingBackground: hsla( 33, 66%, 35%, 80%);--warningHeading: var(--white);--errorBackground: hsla( 7, 30%, 60%, 10%);--errorHeadingBackground: hsla( 6, 70%, 40%, 80%);--errorHeading: var(--white);--infoBackground: hsla(206, 30%, 60%, 10%);--infoHeadingBackground: hsla(213, 55%, 35%, 80%);--infoHeading: var(--white);--neutralBackground: hsl(210, 30%, 60%, 10%);--neutralHeadingBackground: var(--gray600);--neutralHeading: var(--white);--tipBackground: hsla(142, 30%, 60%, 10%);--tipHeadingBackground: hsla(134, 45%, 30%, 80%);--tipHeading: var(--white);--fnSpecAttr: var(--gray400);--fnDeprecated: var(--yellowDark);--blink: var(--gray600);--codeBackground: var(--gray750);--codeBorder: var(--gray600);--codeScrollThumb: var(--gray500);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray750);--admCodeBorder: var(--gray600);--admCodeColor: var(--gray100);--admInlineCodeColor: var(--gray100);--admInlineCodeBackground: var(--gray750);--admInlineCodeBorder: var(--gray600);--tabBorder: var(--gray700);--tabBorderTop: var(--gray700);--tabShadow: var(--black);--bottomActionsBtnBorder: var(--white-opacity-10);--bottomActionsBtnTitle: var(--mainLightest);--modalBackground: var(--gray800);--settingsInput: var(--white);--settingsInputBackground: var(--gray700);--settingsInputBorder: var(--gray700);--settingsSectionBorder: var(--gray700);--quickSwitchInput: var(--gray300);--quickSwitchContour: var(--gray500);--success: var(--green-lightened-10);--progressBarColor: var(--gray300);--sidebarAccentMain: var(--gray50);--sidebarBackground: var(--gray800);--sidebarHeader: var(--gray700);--sidebarMuted: var(--gray300);--sidebarHover: var(--white);--sidebarStaleVersion: var(--orangeLight);--sidebarSubheadings: var(--gray400);--sidebarItem: var(--gray200);--sidebarInactiveItemBorder: var(--gray400);--sidebarInactiveItemMarker: var(--gray600);--sidebarLanguageAccentBar: var(--mainLight);--sidebarActiveItem: var(--mainLightest);--searchBarBorder: var(--gray500);--searchAccentMain: var(--gray300);--searchSearch: var(--gray900);--autocompleteBorder: rgba(28,42,60,.75);--autocompletePreview: var(--gray750);--autocompleteSelected: var(--gray750);--autocompleteHover: var(--gray700);--autocompleteBackground: var(--gray800);--suggestionBorder: var(--gray600);--autocompleteResults: var(--gray200);--autocompleteResultsBold: var(--gray100);--autocompleteLabelBack: var(--gray600);--autocompleteLabelFont: rgba(255, 255, 255, .8)}:root:has(body.dark){color-scheme:dark}*,:before,:after{box-sizing:border-box}html{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}@font-face{font-family:remixicon;src:url(./remixicon-QPNJX265.woff2) format("woff2");font-display:swap}[class^=ri-],[class*=" ri-"],.remix-icon{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:root{--icon-arrow-up-s: "\ea78";--icon-arrow-down-s: "\ea4e";--icon-arrow-right-s: "\ea6e";--icon-add: "\ea13";--icon-subtract: "\f1af";--icon-error-warning: "\eca1";--icon-external-link-line: "\ecaf";--icon-information: "\ee59";--icon-alert: "\ea21";--icon-double-quotes-l: "\ec51";--icon-link-m: "\eeaf";--icon-close-line: "\eb99";--icon-code-s-slash-line: "\ebad";--icon-menu-line: "\ef3e";--icon-search-2-line: "\f0cd";--icon-settings-3-line: "\f0e6";--icon-printer-line: "\f029"}.ri-lg{font-size:1.3333em;line-height:.75em;vertical-align:-.0667em}.ri-settings-3-line:before{content:var(--icon-settings-3-line)}.ri-add-line:before{content:var(--icon-add)}.ri-subtract-line:before{content:var(--icon-subtract)}.ri-arrow-up-s-line:before{content:var(--icon-arrow-up-s)}.ri-arrow-down-s-line:before{content:var(--icon-arrow-down-s)}.ri-arrow-right-s-line:before{content:var(--icon-arrow-right-s)}.ri-external-link-line:before{content:var(--icon-external-link-line)}.ri-search-2-line:before{content:var(--icon-search-2-line)}.ri-menu-line:before{content:var(--icon-menu-line)}.ri-close-line:before{content:var(--icon-close-line)}.ri-link-m:before{content:var(--icon-link-m)}.ri-code-s-slash-line:before{content:var(--icon-code-s-slash-line)}.ri-error-warning-line:before{content:var(--icon-error-warning)}.ri-information-line:before{content:var(--icon-information)}.ri-alert-line:before{content:var(--icon-alert)}.ri-double-quotes-l:before{content:var(--icon-double-quotes-l)}.ri-printer-line:before{content:var(--icon-printer-line)}html,body{box-sizing:border-box;height:100%;width:100%}body{--sidebarWidth: 300px;--sidebarMinWidth: 300px;--sidebarTransitionDuration: .3s;background-color:var(--background);color:var(--textBody);font-size:var(--text-md);line-height:1.6875em;outline:none!important}*,*:before,*:after{box-sizing:inherit}.body-wrapper{display:flex;height:100%}.sidebar{display:none;flex-direction:column;width:var(--sidebarWidth);min-width:var(--sidebarMinWidth);max-width:50vw;height:100%;position:fixed;top:0;left:calc(-1 * var(--sidebarWidth));z-index:100;resize:horizontal}.sidebar-button{padding:26px 12px 18px 19px;position:fixed;z-index:200;top:0;left:0;will-change:transform;transform:translate(0)}.content{left:0;width:100%;height:100%;position:absolute}.content .content-inner{container:content / inline-size;max-width:var(--content-width);min-height:100%;margin:0 auto;padding:0 var(--content-gutter) 10px}.content-inner:focus{outline:none}.sidebar-transition .sidebar,.sidebar-transition .sidebar-button,.sidebar-transition .content{transition:all var(--sidebarTransitionDuration) ease-in-out allow-discrete}.sidebar-open .sidebar,.sidebar-transition .sidebar{display:flex}.sidebar-open .sidebar{left:0}.sidebar-open .sidebar-button{transform:translate(calc(var(--sidebarWidth) - 100%))}.sidebar-open .content{width:calc(100% - var(--sidebarWidth));left:var(--sidebarWidth)}@media screen and (max-width: 768px){.sidebar-open .content{left:0;width:100%}.sidebar{max-width:90vw}body:not(.sidebar-open) .sidebar-button{position:absolute}}.swup-progress-bar{height:2px;background-color:var(--progressBarColor)}.sidebar{--sidebarFontSize: 16px;--sidebarLineHeight: 20px;font-family:var(--sansFontFamily);font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);background-color:var(--sidebarBackground);color:var(--sidebarAccentMain);overflow:hidden;& .sidebar-tabpanel{scrollbar-width:thin}}.apple-os .sidebar{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sidebar ul{list-style:none}.sidebar ul li{margin:0;padding:0 10px}.sidebar a{color:var(--sidebarAccentMain);text-decoration:none;transition:var(--transition-colors)}.sidebar a:hover{color:var(--sidebarHover)}.sidebar .external-link{margin:0 2.5px 0 0}.sidebar .sidebar-header{background-color:var(--sidebarHeader);width:100%}.sidebar .sidebar-projectInfo{display:flex;justify-content:start;align-items:center;gap:8px;margin:12px 34px 12px 14px}.sidebar .sidebar-projectInfo>div{flex:1}.sidebar .sidebar-projectImage{align-self:flex-end}.sidebar .sidebar-projectImage img{display:block;max-width:48px;max-height:48px}.sidebar .sidebar-projectName{font-weight:700;font-size:var(--text-xl);line-height:24px;color:var(--sidebarAccentMain);margin:0;padding:0;word-wrap:break-word;display:block;width:calc(100% - 12px)}.sidebar .sidebar-projectVersion{display:block;position:relative;margin:0;padding:0;font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);color:var(--sidebarMuted);width:calc(100% - 12px)}.sidebar .sidebar-projectVersion form{display:flex}.sidebar .sidebar-projectVersion select{cursor:pointer;position:relative;margin:0;padding:0 0 0 10px;border:none;-webkit-appearance:none;appearance:none;background-color:transparent;color:var(--sidebarMuted);z-index:2}.sidebar .sidebar-projectVersion option{color:initial}.sidebar .sidebar-projectVersionsCaret{position:absolute;left:0;top:2px;z-index:1;font-size:8px;color:var(--sidebarMuted)}.sidebar .sidebar-projectVersion select::-ms-expand{display:none}.sidebar .sidebar-staleVersion{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--sidebarStaleVersion)}.sidebar .sidebar-staleVersion>a{color:var(--sidebarStaleVersion);font-weight:400}.sidebar .sidebar-staleIcon{font-size:var(--text-lg);position:relative;top:3px;line-height:0}.sidebar .sidebar-list-nav{display:flex;margin:0;padding:0;overflow:auto;scrollbar-width:thin}.sidebar .sidebar-list-nav :is(li,li button){text-transform:uppercase;letter-spacing:.02em;font-size:var(--text-sm);color:var(--sidebarSubheadings);white-space:nowrap}.sidebar .sidebar-list-nav li{display:inline-block;padding:0}.sidebar .sidebar-list-nav button{background:none;border:0;border-radius:0;-webkit-appearance:none;text-align:inherit;color:inherit;font-weight:inherit;cursor:pointer;display:inline-block;line-height:27px;padding:4px 14px;transition:var(--transition-all)}.sidebar .sidebar-list-nav button{border-bottom:var(--navTabBorderWidth) solid transparent}.sidebar .sidebar-list-nav button:not([aria-selected]):hover{border-bottom:var(--navTabBorderWidth) solid var(--sidebarInactiveItemBorder);color:var(--sidebarAccentMain);transition:var(--transition-all)}.sidebar .sidebar-list-nav button[aria-selected]{border-bottom:var(--navTabBorderWidth) solid var(--sidebarLanguageAccentBar);color:var(--sidebarAccentMain)}.sidebar .sidebar-tabpanel{flex:1 1 .01%;overflow-y:auto;overscroll-behavior:contain;position:relative;-webkit-overflow-scrolling:touch;padding-top:12px;scroll-padding-top:40px}.sidebar .full-list{margin:0;padding:0 0 20px;position:relative}.sidebar .full-list :is(li,a){display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.sidebar .full-list li{padding:0;line-height:27px}.sidebar .full-list li.group{text-transform:uppercase;font-weight:700;font-size:.8em;margin:1.5em 0 0;line-height:1.8em;color:var(--sidebarSubheadings);padding-left:15px}.sidebar .full-list li.nesting-context{font-weight:700;font-size:.9em;line-height:1.8em;color:var(--sidebarSubheadings);margin-top:10px;padding-left:15px}.sidebar .full-list a{margin-right:30px;padding:3px 0 3px 12px;border-left:var(--navTabBorderWidth) solid transparent;color:var(--sidebarItem)}.sidebar .full-list a[aria-selected]{color:var(--sidebarActiveItem)}.sidebar .full-list button{appearance:none;background-color:transparent;border:0;padding:0;cursor:pointer;color:inherit;width:20px;text-align:center;font-size:calc(1.2 * var(--sidebarFontSize));line-height:var(--sidebarLineHeight);position:absolute;display:block;right:10px;transform:translateY(-100%)}.sidebar .full-list a[aria-selected]+button{color:var(--sidebarActiveItem)}.sidebar .full-list button:after{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:var(--icon-arrow-down-s)}.sidebar .full-list button[aria-expanded=true]:after{content:var(--icon-arrow-up-s)}.sidebar .full-list ul{display:none;margin:10px 0 10px 10px;padding:0}.sidebar .full-list button[aria-expanded=true]+ul{display:block}.sidebar .full-list>li>a{height:27px;line-height:var(--sidebarLineHeight)}.sidebar .full-list>li>a:hover{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li>a[aria-selected]{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li:last-child{margin-bottom:30px}.sidebar .full-list>li.group:first-child{margin-top:0}.sidebar .full-list>li>ul>li:not(:has(li a[aria-selected=true]))>a[aria-selected=true]:before,.sidebar .full-list>li>ul>li>a:hover:before{content:"\2022";position:absolute;margin-left:-15px;color:var(--sidebarActiveItem)}.sidebar .full-list ul li{line-height:var(--sidebarFontSize);padding:0 8px}.sidebar .full-list ul a{padding-left:15px;height:24px}.sidebar .full-list ul button{font-size:var(--sidebarFontSize)}.sidebar .full-list ul button:after{content:var(--icon-add)}.sidebar .full-list ul button[aria-expanded=true]:after{content:var(--icon-subtract)}.sidebar .full-list ul ul{margin:9px 0 9px 10px}.sidebar .full-list ul ul li{height:20px;color:var(--sidebarAccentMain)}.sidebar .full-list ul ul a{border-left:1px solid var(--sidebarInactiveItemMarker);padding:0 10px;height:20px}.sidebar .full-list ul ul a:hover{border-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list ul ul a[aria-selected]{color:var(--sidebarActiveItem);border-color:var(--sidebarLanguageAccentBar)}.sidebar-button{cursor:pointer;background-color:transparent;border:none;font-size:var(--sidebarFontSize);color:var(--sidebarAccentMain)}.sidebar-button:hover{color:var(--sidebarHover)}body:not(.sidebar-open) .sidebar-button{color:var(--contrast)}@media screen and (max-height: 500px){.sidebar{overflow-y:auto}.sidebar .full-list{overflow:visible}}.top-search{background-color:var(--background);top:0;z-index:99;position:relative;width:100%;padding:10px 0}.search-settings{display:flex;column-gap:12px;align-items:center;width:100%;position:relative}.search-bar{border:1px solid var(--searchBarBorder);border-radius:var(--borderRadius-base);height:48px;position:relative;width:100%}.top-search .search-bar .search-input{background-color:var(--searchSearch);border:1px solid transparent;border-radius:var(--borderRadius-base);color:var(--searchAccentMain);position:relative;height:46px;padding:8px 35px 8px 43px;width:100%;transition:var(--transition-all)}.top-search .search-bar .search-input::placeholder{color:var(--searchAccentMain);opacity:.5}.top-search .search-bar .search-input:focus{border:1px solid var(--searchBarFocusColor);border-radius:calc(var(--borderRadius-base) - 1px);position:relative;box-shadow:0 4px 20px 0 var(--searchBarBorderColor) inset}.top-search .search-bar .search-label{position:relative}.top-search .search-bar .search-button{font-size:var(--text-sm);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;left:11px;opacity:.5;padding:5px 1px 5px 5px;position:absolute;top:60%;transform:translateY(-60%);z-index:99;transition:var(--transition-all)}.top-search .search-bar.selected .search-button,.top-search .search-bar .search-button:hover,.top-search .search-bar .search-button:focus{color:var(--top-searchLanguageAccentBar);opacity:1}.top-search .search-bar .search-close-button{font-size:var(--text-md);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;right:11px;margin:0;opacity:.5;padding:5px 1px 5px 0;position:absolute;transform:scaleY(0);top:calc(50% - 13px);transition:var(--transition-all);z-index:99}.top-search .search-bar .search-close-button:hover{opacity:.7}.top-search .search-settings button.icon-settings{display:flex;align-items:center;justify-content:flex-end}.top-search .search-settings .icon-settings{font-size:var(--text-xl);float:right;color:var(--iconAction);text-decoration:none;border:none;transition:color .3s ease-in-out;background-color:transparent;cursor:pointer;padding:0}.top-search .search-settings .icon-settings:hover{color:var(--iconActionHover)}.top-search .search-settings .icon-settings:visited{color:var(--iconAction)}@media screen and (max-width: 768px){.top-search{padding-left:calc(var(--content-gutter) + 36px);padding-right:var(--content-gutter);margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));width:calc(2 * var(--content-gutter) + 100%)}.search-settings{width:100%;box-sizing:border-box}}body.search-focused .search-bar .search-close-button{transform:scaleY(1);transition:var(--transition-all)}@media screen and (hover: hover){body.search-focused .top-search{position:sticky!important}body.search-focused .sidebar-button{position:fixed!important}}@media screen and (hover: none){body.scroll-sticky .top-search{position:sticky!important}body.scroll-sticky .sidebar-button{position:fixed!important}}*:focus,button:focus,[type=button]:focus,[type=reset]:focus,[type=submit]:focus{outline:2px solid var(--main);outline-offset:-2px}*:focus:not(:focus-visible),button:focus:not(:focus-visible),[type=button]:focus:not(:focus-visible),[type=reset]:focus:not(:focus-visible),[type=submit]:focus:not(:focus-visible){outline:0}input[type=text],input[type=number],input[type=date],input[type=datetime],input[type=datetime-local],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=time],input[type=url],input[type=week],textarea{outline:0}.content-inner{font-size:1em;line-height:1.6875em;position:relative;background-color:var(--background);color:var(--textBody)}.content-inner .heading-with-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px}.content-inner .heading-with-actions>*:not(h1){flex-shrink:0}.content-inner .heading-with-actions h1{flex-grow:1;justify-self:flex-start;max-width:100%;margin:0;overflow-wrap:break-word}.content-inner .heading-with-actions .icon-action{width:20px;height:20px;display:flex;justify-content:center;align-items:center;font-weight:400}.content-inner .heading-with-actions.top-heading .icon-action{font-size:1.2rem}@container content (width > 600px){.content-inner .heading-with-actions.top-heading{flex-wrap:nowrap;align-items:flex-start;& h1{padding-right:32px}& .icon-action{padding-top:1.7rem}}}.content-inner .top-heading{padding-top:1rem}.content-inner :is(h1,h2,h3,h4,h5,h6){font-family:var(--sansFontFamily);font-weight:700;line-height:1.5em;word-wrap:break-word;color:var(--textHeaders)}.content-inner h1{font-size:2em;margin:.5em 0}.content-inner h1.section-heading{margin:1.5em 0 .5em}.content-inner h1 small{font-weight:400}.content-inner h2{font-size:1.6em;padding-top:1em;margin-bottom:.5em}.content-inner h3{font-size:1.375em;margin:1em 0 .5em}.content-inner li+li{margin-top:.25em}.content-inner :is(a,.a-main){color:var(--link-color);text-decoration:underline;text-decoration-skip-ink:auto}.content-inner :is(a:visited,.a-main:visited){color:var(--link-visited-color)}.content-inner .icon-action{color:var(--iconAction);text-decoration:none;border:none;transition:var(--transition-colors);background-color:transparent;cursor:pointer}.content-inner .icon-action:hover{color:var(--iconActionHover)}.content-inner .icon-action:visited{color:var(--iconAction)}.content-inner .livebook-badge-container{display:flex}.content-inner a.livebook-badge{display:inline-flex}.content-inner .note{color:var(--iconAction);font-size:var(--text-xs);font-weight:400}.content-inner blockquote,.content-inner section.admonition{border-left:3px solid var(--blockquoteBorder);position:relative;margin:1.5625em 0;padding:0 1.2rem;overflow:auto;background-color:var(--blockquoteBackground);border-radius:var(--borderRadius-base)}.content-inner blockquote p:last-child,.content-inner section.admonition p:last-child{padding-bottom:1em;margin-bottom:0}.content-inner table{margin:2em 0;border-collapse:collapse;display:block;overflow:auto}.content-inner th{text-align:left;font-family:var(--sansFontFamily);font-weight:700;padding-bottom:.5em;white-space:nowrap}.content-inner thead tr{border-bottom:1px solid var(--tableHeadBorder)}.content-inner tbody tr{border-bottom:1px solid var(--tableBodyBorder)}.content-inner tbody tr:last-child{border-bottom:none}.content-inner tr{vertical-align:bottom;height:2.5em}.content-inner :is(td,th){padding:.25em .25em .25em 1em;line-height:2em;vertical-align:top}.content-inner .section-heading{--icon-size: 16px;--icon-spacing: 5px;display:grid;grid-template:1fr / 1fr}@media screen and (max-width: 768px){.content-inner .section-heading{--icon-spacing: 2px}}.content-inner .section-heading>:is(.hover-link,.text){grid-row:1;grid-column:1}.content-inner .section-heading .hover-link{text-decoration:none}.content-inner .section-heading i{font-size:var(--icon-size);color:var(--mainLight);margin-top:.1em;margin-left:calc(-1 * (var(--icon-size) + var(--icon-spacing)));padding-right:var(--icon-spacing);opacity:0}.content-inner :is(blockquote,section.admonition) .section-heading i{display:none}.content-inner .section-heading:is(:hover,:focus,:target) i{opacity:1}.content-inner .app-vsn{display:none!important;font-size:.6em;line-height:1.5em}@media screen and (max-width: 768px){.content-inner .app-vsn{display:block!important}}.content-inner img{max-width:100%}.content-inner strong>code{font-weight:700}.content-inner code{font-family:var(--monoFontFamily);font-style:normal;line-height:24px;font-weight:400;font-size:var(--text-sm)}@media screen and (max-width: 768px){.content-inner :is(ol,ul){padding-left:calc(1.5 * var(--content-gutter))}}.content-inner section.admonition{border-radius:var(--borderRadius-base);border-left:0}.content-inner section.admonition.warning{background-color:var(--warningBackground)}.content-inner section.admonition.error{background-color:var(--errorBackground)}.content-inner section.admonition.info{background-color:var(--infoBackground)}.content-inner section.admonition.neutral{background-color:var(--neutralBackground)}.content-inner section.admonition.tip{background-color:var(--tipBackground)}.content-inner section.admonition>.admonition-title{color:var(--contrast);margin:0 -1.2rem;padding:.7rem 1.2rem .7rem 3.3rem;font-weight:700;font-style:normal}.content-inner section.admonition>.admonition-title:before{color:var(--contrast);position:absolute;left:1rem;font-size:1.8rem;font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.content-inner section.admonition>.admonition-title.warning{background-color:var(--warningHeadingBackground);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.warning:before{content:var(--icon-error-warning);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.error{background-color:var(--errorHeadingBackground);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.error:before{content:var(--icon-error-warning);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.info{background-color:var(--infoHeadingBackground);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.info:before{content:var(--icon-information);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.neutral{background-color:var(--neutralHeadingBackground);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.neutral:before{content:var(--icon-double-quotes-l);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.tip{background-color:var(--tipHeadingBackground);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title.tip:before{content:var(--icon-information);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title code{margin:0 .5ch}.content-inner section.admonition code{background-color:var(--admInlineCodeBackground);border:1px solid var(--admInlineCodeBorder);color:var(--admInlineCodeColor)}.content-inner section.admonition pre code{background-color:var(--admCodeBackground);border:1px solid var(--admCodeBorder);color:var(--admCodeColor)}.content-inner section.admonition>.admonition-title :is(a,a:visited){color:inherit;text-decoration-color:currentColor}@media screen and (max-width: 768px){.content-inner section.admonition{margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0}.content-inner section.admonition>.admonition-title{margin:0 calc(-1 * var(--content-gutter))}}.content-inner .summary h2 a{text-decoration:none;border:none;color:var(--textHeaders)!important}.content-inner .summary span.deprecated{color:var(--darkDeprecated);font-weight:400}.content-inner .summary .summary-row .summary-signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700}.content-inner .summary .summary-row .summary-signature a{text-decoration:none;border:none}.content-inner .summary .summary-row .summary-synopsis{padding:0 1.2em;margin:0 0 .5em}.content-inner .summary .summary-row .summary-synopsis p{margin:0;padding:0}@font-face{font-family:Consolas;src:local("Consolas");size-adjust:110%}.content-inner.content-inner :is(a:has(code,img),pre a){color:var(--link-color);text-shadow:none;text-decoration:none;background-image:none}.content-inner.content-inner :is(a:has(code,img),pre a):is(:visited,:active,:focus,:hover){color:var(--link-visited-color)}.content-inner code{background-color:var(--codeBackground);vertical-align:baseline;border-radius:var(--borderRadius-sm);padding:.1em .2em;border:1px solid var(--codeBorder);text-transform:none}.content-inner code.inline{border-radius:var(--borderRadius-sm);word-wrap:break-word}.content-inner pre{margin:var(--baseLineHeight) 0}.content-inner pre code{display:block;overflow-x:auto;white-space:inherit;padding:1em;scrollbar-width:thin}.content-inner pre code.output{margin:0 12px;max-height:400px;overflow:auto}.content-inner pre code.output+.copy-button{margin-right:12px}.content-inner pre code.output:before{content:"Output";display:block;position:absolute;top:-16px;left:12px;padding:2px 4px;font-size:var(--text-xs);font-family:var(--monoFontFamily);line-height:1;color:var(--textHeaders);background-color:var(--codeBackground);border:1px solid var(--codeBorder);border-bottom:0;border-radius:2px}@media screen and (max-width: 768px){.content-inner>pre:has(code),.content-inner section>pre:has(code){margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter))}.content-inner>pre code,.content-inner section>pre code{padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0;border-left-width:0;border-right-width:0}}@keyframes blink-background{0%,to{background-color:var(--textDetailBackground)}50%{background-color:var(--blink)}}.content-inner .detail:target .detail-header{animation-duration:.55s;animation-name:blink-background;animation-iteration-count:1;animation-timing-function:ease-in-out}.content-inner .detail-header{margin:1em 0;padding:.5em .85em .5em 1em;background-color:var(--textDetailBackground);border-left:3px solid var(--textDetailAccent);font-size:1em;font-family:var(--monoFontFamily);position:relative}.content-inner .detail-header .signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700;line-height:2em}.content-inner .detail-header:hover a.detail-link,.content-inner .detail-header a.detail-link:focus{opacity:1;text-decoration:none}.content-inner .detail-header a.detail-link{transition:var(--transition-opacity);position:absolute;top:0;left:0;display:block;opacity:0;padding:.6em;line-height:1.5em;margin-left:-2.5em;text-decoration:none;border:none}@media screen and (max-width: 768px){.content-inner .detail-header a.detail-link{margin-left:-30px}}.content-inner .specs pre{font-family:var(--monoFontFamily);font-size:var(--text-xs);font-style:normal;line-height:24px;white-space:pre-wrap;margin:0;padding:0}.content-inner .specs .attribute{color:var(--fnSpecAttr)}.content-inner .docstring{margin:1.2em 0 3em 1.2em}@media screen and (max-width: 768px){.content-inner .docstring{margin-left:0}}.content-inner .docstring:is(h2,h3,h4,h5){font-weight:700}.content-inner .docstring h2{font-size:1.1em}.content-inner .docstring h3{font-size:1em}.content-inner .docstring h4{font-size:.95em}.content-inner .docstring h5{font-size:.9em}.content-inner div.deprecated{display:block;padding:1em;background-color:var(--fnDeprecated);border-radius:var(--borderRadius-sm);margin:var(--baseLineHeight) 0}.content-inner .footer{margin:4em auto 1em;text-align:center;font-size:var(--text-sm)}.content-inner .footer .line{display:inline-block}.content-inner .footer .footer-button{background-color:transparent;border:0;cursor:pointer;padding:0 4px}.content-inner .footer .footer-hex-package{margin-right:4px}.content-inner .bottom-actions{display:flex;justify-content:space-between;margin-top:4em;gap:12px}.bottom-actions-item{flex:1 1 0%}.content-inner .bottom-actions .bottom-actions-button{display:flex;text-decoration:none;flex-direction:column;border-radius:var(--borderRadius-sm);border:1px solid var(--bottomActionsBtnBorder);padding:12px 16px;min-width:150px;transition:var(--transition-all)}.content-inner .bottom-actions .bottom-actions-button:hover{border-color:var(--mainLight)}.content-inner .bottom-actions .bottom-actions-button .subheader{font-size:.8em;color:var(--textHeaders);white-space:nowrap}.content-inner .bottom-actions .bottom-actions-button .title{color:var(--bottomActionsBtnTitle)}.content-inner .bottom-actions .bottom-actions-button[rel=prev]{text-align:start}.content-inner .bottom-actions .bottom-actions-button[rel=next]{text-align:end}@media screen and (max-width: 768px){.content-inner .bottom-actions{flex-direction:column-reverse}}.page-cheatmd .content-inner{--horizontal-space: 1.5em;--vertical-space: 1em}@media (max-width: 600px){.page-cheatmd .content-inner{--horizontal-space: 1em;--vertical-space: .75em}}.page-cheatmd .content-inner{max-width:1200px}.page-cheatmd .content-inner h1{margin-bottom:var(--vertical-space)}.page-cheatmd .content-inner h2{margin:var(--vertical-space) 0;column-span:all;color:var(--gray700);font-weight:500}.dark .page-cheatmd .content-inner h2{color:var(--gray200)}.page-cheatmd .content-inner h3{margin:0 0 1em;font-weight:400}.page-cheatmd .content-inner section.h3{min-width:300px;margin:0;padding:0 0 calc(var(--vertical-space) * 2) 0;break-inside:avoid}.page-cheatmd .content-inner h3 .text{overflow:hidden}.page-cheatmd .content-inner h3 .text:after{content:"";margin-left:calc(var(--horizontal-space) / 2);vertical-align:baseline;display:inline-block;width:100%;height:1px;margin-right:-100%;margin-bottom:5px;background-color:var(--codeBorder)}.page-cheatmd .content-inner h4{display:block;margin:0;padding:.25em var(--horizontal-space);font-weight:400;background:var(--gray100);color:#567;border:solid 1px 1px 0 1px var(--gray100)}.dark .page-cheatmd .content-inner h4{background:#192f50;color:var(--textBody);border:1px solid #192f50;border-bottom:0}.page-cheatmd .content-inner .h2 p{margin:0;display:block;background:var(--gray50);padding:var(--vertical-space) var(--horizontal-space)}.dark .page-cheatmd .content-inner .h2 p{background:var(--gray700)}.page-cheatmd .content-inner .h2 p>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner pre code{padding:var(--vertical-space) var(--horizontal-space)}.page-cheatmd .content-inner .h2 pre{margin:0}.page-cheatmd .content-inner .h2 pre+pre{margin-top:-1px}.page-cheatmd .content-inner pre.wrap{white-space:break-spaces}@media screen and (max-width: 768px){.page-cheatmd .content-inner pre code{border-left-width:1px!important;border-right-width:1px!important}}.page-cheatmd .content-inner .h2 table{display:table;box-sizing:border-box;width:100%;border-collapse:collapse;margin:0}.page-cheatmd .content-inner .h2 th{padding:var(--vertical-space) var(--horizontal-space);line-height:inherit;margin-bottom:-1px;vertical-align:middle;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td{padding:var(--vertical-space) var(--horizontal-space);border:0;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 tr:first-child{border-top:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner .h2 thead{background-color:var(--gray50)}.dark .page-cheatmd .content-inner .h2 thead{background-color:var(--gray700)}.page-cheatmd .content-inner .h2 tbody{background-color:var(--codeBackground)}.page-cheatmd .content-inner .h2 :is(ul,ol){margin:0;padding:0}.page-cheatmd .content-inner .h2 li{list-style-position:inside;padding:.5em var(--horizontal-space);line-height:2em;vertical-align:middle;background-color:var(--codeBackground);border-bottom:1px solid var(--codeBorder);margin-top:0}.page-cheatmd .content-inner .h2 :is(ul,ol)+pre code{border-top:0}.page-cheatmd .content-inner .h2 li>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner section.width-50{display:block;width:50%;margin:0}.page-cheatmd .content-inner section.width-50>section>table{width:100%}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:40px}.page-cheatmd .content-inner section.col-2{column-count:2;height:auto}.page-cheatmd .content-inner section.col-2-left{display:grid;grid-template-columns:calc(100% / 3) auto}.page-cheatmd .content-inner section.col-2-left>h2{grid-column-end:span 2}.page-cheatmd .content-inner section.col-3{column-count:3;height:auto}.page-cheatmd .content-inner section.list-4>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-4>ul>li{flex:0 0 25%}.page-cheatmd .content-inner section.list-6>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 calc(100% / 6)}@media screen and (max-width: 1400px){.page-cheatmd .content-inner section.col-3{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:flex;flex-direction:column}}@media screen and (max-width: 1200px){.page-cheatmd .content-inner section:is(.col-2,.col-3){display:flex;flex-direction:column}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 25%}}@media screen and (max-width: 1000px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 calc(100% / 3)}}@media screen and (max-width: 600px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 50%}.page-cheatmd .content-inner section.width-50{width:100%}}#search{min-height:200px;position:relative}#search .loading{height:64px;width:64px;position:absolute;top:50%;left:calc(50% - 32px)}#search .loading div{box-sizing:border-box;display:block;position:absolute;width:51px;height:51px;margin:6px;border:6px solid var(--coldGray);border-radius:50%;animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:var(--coldGray) transparent transparent transparent}#search .loading div:nth-child(1){animation-delay:-.45s}#search .loading div:nth-child(2){animation-delay:-.3s}#search .loading div:nth-child(3){animation-delay:-.15s}@keyframes loading{0%{transform:rotate(0)}to{transform:rotate(360deg)}}#search .result{margin:2em 0 2.5em}#search .result p{margin:0}#search .result-id{font-size:1.4em;margin:0}#search .result-id a{text-decoration:none;color:var(--textHeaders);transition:var(--transition-colors)}#search .result-id a:is(:visited,:active){color:var(--textHeaders)}#search .result-id a:is(:hover,:focus){color:var(--main)}#search :is(.result-id,.result-elem) em{font-style:normal;color:var(--main)}#search .result-id small{font-weight:400}@keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}.modal{animation-duration:.15s;animation-name:keyboard-shortcuts-show;animation-iteration-count:1;animation-timing-function:ease-in-out;display:none;background-color:#000000bf;position:fixed;inset:0;z-index:300}.modal.shown{display:block}.modal .modal-contents{margin:75px auto 0;max-width:500px;background-color:var(--modalBackground);border-radius:var(--borderRadius-sm);box-shadow:2px 2px 8px #0003;padding:25px 35px 35px}@media screen and (max-width: 768px){.modal .modal-contents{padding:20px}}.modal .modal-header{display:flex;align-items:start}.modal .modal-title{display:inline-block;flex-grow:1;font-size:1.2rem;font-weight:700;margin-bottom:20px}.modal .modal-title button{border:none;background-color:transparent;color:var(--textHeaders);font-weight:700;margin-right:30px;padding-left:0;text-align:left;transition:var(--transition-colors)}.modal .modal-title button:hover{color:var(--main);cursor:pointer}.modal .modal-title button.active{color:var(--main)}.modal .modal-close{cursor:pointer;display:block;font-size:1.5rem;margin:-8px -8px 0 0;padding:8px;opacity:.7;background-color:transparent;color:var(--textHeaders);border:none;transition:var(--transition-opacity)}.modal .modal-close:hover{opacity:1}#keyboard-shortcuts-content dl.shortcut-row{display:flex;align-items:center;justify-content:space-between;margin:0;padding:6px 0 8px;border-bottom:1px solid var(--settingsSectionBorder)}#keyboard-shortcuts-content dl.shortcut-row:last-of-type{border-bottom-style:none}#keyboard-shortcuts-content dl.shortcut-row:first-child{padding-top:0}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){display:inline-block}#keyboard-shortcuts-content kbd>kbd{background-color:var(--settingsInputBorder);color:var(--contrast);border-radius:var(--borderRadius-sm);font-family:inherit;font-weight:700;display:inline-block;line-height:1;padding:4px 7px 6px;min-width:26px;text-align:center;font-size:var(--text-sm)}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){margin:0}#quick-switch-modal-body{width:100%;position:relative}#quick-switch-modal-body .ri-search-2-line{position:absolute;left:0;top:0;padding:4px 10px;color:var(--quickSwitchContour);font-weight:700}#quick-switch-modal-body #quick-switch-input{width:100%;padding:8px 6px 8px 38px;border:none;color:var(--quickSwitchInput);background-color:transparent;border-bottom:1px solid var(--quickSwitchContour);box-sizing:border-box;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-results{margin:0}#quick-switch-modal-body .quick-switch-result{padding:2px 5px;border-bottom:1px dotted var(--quickSwitchContour);transition:all .12s ease-out}#quick-switch-modal-body .quick-switch-result:last-child{border-bottom:none}#quick-switch-modal-body .quick-switch-result:hover{cursor:pointer}#quick-switch-modal-body .quick-switch-result:is(:hover,.selected){border-left:4px solid var(--main);background-color:var(--codeBackground)}.autocomplete{display:none;position:absolute;width:calc(100% - 32px);top:55px}.autocomplete .triangle{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;border-bottom:12px solid var(--autocompleteBackground);position:absolute;top:8px;left:26px;transform:translate(-50%);z-index:100;background-color:transparent}.autocomplete-preview{width:100%;margin:0;height:100%;line-height:20px;background-color:var(--background);font-family:var(--sansFontFamily);border:4px solid var(--autocompleteBorder);padding:12px 16px}.autocomplete-preview div,.autocomplete-preview span{display:none}.autocomplete-preview.loading div{float:left;display:block;border:5px solid var(--autocompleteBorder);border-radius:50%;border-top:5px solid var(--textDetailAccent);width:20px;height:20px;animation:spinner 4s linear infinite}.autocomplete-preview.loading span{color:var(--autocompleteResults);display:inline;margin-left:6px}.autocomplete-preview.loading span:after{color:var(--autocompleteResults);content:"Loading"}@keyframes spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.autocomplete-preview.loading iframe{height:0}.autocomplete-preview iframe{width:100%;height:100%;border:0}.autocomplete-results{list-style:none;margin:0;padding:15px 20px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;color:var(--autocompleteResults);font-family:var(--sansFontFamily);font-weight:300;font-size:.9rem}.autocomplete-results .query{margin-right:auto}.autocomplete-results .bold{color:var(--autocompleteResultsBold);font-weight:400}.autocomplete.shown{display:block}.autocomplete-container{position:absolute;top:15px;width:100%;z-index:200}.autocomplete-suggestions{background-color:var(--autocompleteBackground);border-radius:var(--borderRadius-base);box-shadow:0 15px 99px 0 var(--autocompleteBorder);overflow-y:auto;max-height:450px;white-space:normal;overflow-x:hidden;overscroll-behavior-y:contain;scrollbar-width:thin}.autocomplete-suggestions.previewing:has(.selected){max-height:80vh}.autocomplete-suggestions.previewing:has(.selected) .autocomplete-suggestion:not(.selected){display:none}.autocomplete-suggestions.previewing:not(:has(.selected)) .autocomplete-preview{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview{display:none}.autocomplete-suggestion{color:var(--textHeaders)!important;display:block;padding:12px 20px;text-decoration:none!important;transition:var(--transition-colors);border-top:1px solid var(--suggestionBorder);font-size:.9rem}.autocomplete-suggestion.selected{background-color:var(--autocompleteSelected);box-shadow:inset 2px 0 var(--main)}.autocomplete-suggestion:hover{background-color:var(--autocompleteHover)}.autocomplete-suggestion:not(.selected) .autocomplete-preview-indicator{display:none}.autocomplete-preview-indicator{float:right}.autocomplete-preview-indicator button{color:var(--iconAction);display:flex;align-items:center;text-decoration:none;border:1px solid var(--suggestionBorder);border-radius:var(--borderRadius-base);transition:var(--transition-colors);background-color:var(--autocompletePreview);cursor:pointer;padding:4px 8px;font-size:var(--text-sm)}.autocomplete-preview-indicator button:hover{color:var(--iconActionHover);background-color:var(--autocompleteHover)}.autocomplete-preview-indicator button i{margin-right:4px}.autocomplete-suggestions.previewing .autocomplete-preview-indicator-closed{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview-indicator-open{display:none}.autocomplete-suggestion:hover:not(.selected) .autocomplete-preview-indicator-closed{display:block}.autocomplete-suggestion em{font-style:normal;font-weight:700}.autocomplete-suggestion .description{opacity:.6;padding-top:3px}.autocomplete-suggestion .label{background-color:var(--autocompleteLabelBack);opacity:.6;color:var(--autocompleteLabelFont);padding:4px 8px;border-radius:4px;margin-left:5px;text-transform:uppercase;font-family:var(--sansFontFamily);font-size:.7rem}.autocomplete-suggestion .header{margin-right:5px}.autocomplete-suggestion .title,.autocomplete-suggestion .description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}@media screen and (hover: none){.autocomplete-preview-indicator,.autocomplete-results .press-return{display:none!important}}.tooltip{box-shadow:0 0 10px var(--black-opacity-10);max-height:300px;max-width:500px;padding:0;position:absolute;pointer-events:none;margin:0;z-index:99;top:0;left:0;visibility:hidden;transform:translateY(20px);opacity:0;transition:.2s visibility ease-out,.2s transform ease-out,.2s opacity ease-out}.tooltip.tooltip-shown{visibility:visible;transform:translateY(0);opacity:1}.tooltip .tooltip-body{border:1px solid var(--codeBorder);border-radius:var(--borderRadius-sm);overflow:auto}.tooltip .tooltip-body .signature{min-width:320px;width:100%;line-height:1em}.tooltip .tooltip-body .detail-header{border-left:0;margin-bottom:0;margin-top:0}.tooltip .tooltip-body .docstring{background-color:var(--background);padding:1.2em;margin:0;width:498px}.tooltip .tooltip-body .docstring-plain{max-width:498px;width:auto}.tooltip .tooltip-body .version-info{float:right;font-family:var(--monoFontFamily);font-weight:400;opacity:.3;padding-left:.3em}pre{position:relative}pre:hover .copy-button,pre .copy-button:focus{opacity:1}.copy-button{display:flex;opacity:0;position:absolute;top:7px;right:8px;padding:8px;background-color:transparent;backdrop-filter:blur(8px);border-radius:var(--borderRadius-sm);border:1px solid var(--codeBorder);cursor:pointer;transition:var(--transition-all);font-size:var(--text-sm);line-height:24px;color:currentColor;& svg[aria-live=polite]{display:none}}.copy-button svg{opacity:.5;transition:var(--transition-all)}pre .copy-button:hover svg,pre .copy-button:focus-visible svg{opacity:1}.copy-button svg{width:20px}.copy-button.clicked{opacity:1;color:var(--success);& svg[aria-live=polite]{display:block}}.copy-button.clicked svg{display:none;color:currentColor}#settings-modal-content{margin-top:10px}#settings-modal-content .hidden{display:none}#settings-modal-content .input{box-sizing:border-box;width:80%;padding:8px;font-size:var(--text-sm);background-color:var(--settingsInputBackground);color:var(--settingsInput);border:1px solid var(--settingsInputBorder);border-radius:var(--borderRadius-base);transition:var(--transition-all)}#settings-modal-content .input:focus{border-color:var(--main)}#settings-modal-content .input::placeholder{color:var(--gray400)}#settings-modal-content .switch-button-container{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--settingsSectionBorder);padding:10px 0}#settings-modal-content .switch-button-container:first-of-type{border-top-style:none;padding-top:0}#settings-modal-content .switch-button-container>div>span{font-size:var(--text-md)}#settings-modal-content .switch-button-container>div>p{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--text-sm);line-height:1.4;margin:0;padding-bottom:6px;padding-right:10px}#settings-modal-content .switch-button{position:relative;display:inline-block;flex-shrink:0;width:40px;height:20px;user-select:none;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox{appearance:none;position:absolute;display:block;width:20px;height:20px;border-radius:1000px;background-color:#91a4b7;border:3px solid #e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__bg{display:block;width:100%;height:100%;border-radius:1000px;background-color:#e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox:checked{background-color:#fff;border-color:var(--main);transform:translate(100%)}#settings-modal-content .switch-button__checkbox:checked+.switch-button__bg{background-color:var(--main)}#settings-modal-content .switch-button__checkbox:focus{outline:0}#settings-modal-content .switch-button__checkbox:focus+.switch-button__bg{outline:2px solid var(--main);outline-offset:2px}#settings-modal-content .switch-button__checkbox:focus:not(:focus-visible)+.switch-button__bg{outline:0}#settings-modal-content .settings-select{cursor:pointer;position:relative;border:none;background-color:transparent;color:var(--textBody)}#settings-modal-content .settings-select option{color:initial}#toast{visibility:hidden;opacity:0;position:fixed;z-index:1;left:50%;bottom:1rem;min-width:3rem;margin:0 -1.2rem;padding:.7rem 1.2rem;text-align:center;font-weight:700;border-radius:var(--borderRadius-base);border:1px solid var(--codeBorder);background-color:var(--codeBackground);color:var(--textBody);transition:opacity .4s ease-in-out,transform .3s ease-out;cursor:default}#toast.show{visibility:visible;opacity:1;transform:translateY(-.75rem)}@media (prefers-reduced-motion: reduce){#toast{transition:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;user-select:none}@media print{.body-wrapper{display:block}.sidebar,.sidebar-button,.top-search{display:none}.content{padding-left:0;overflow:visible;left:0;width:100%}.summary-row{break-inside:avoid}#toast{display:none}.content-inner{padding:0}.content-inner .section-heading a.hover-link,.content-inner button.icon-action,.content-inner a.icon-action,.content-inner .bottom-actions{display:none}.footer p:first-of-type{display:none}.content-inner section.admonition{border:2px solid var(--gray400)}.content-inner section.admonition>.admonition-title{color:var(--textHeaders);border-bottom:2px solid var(--gray400)}.content-inner pre code.makeup{border-color:var(--gray400);white-space:break-spaces;break-inside:avoid}.content-inner blockquote code.inline,.content-inner code.inline{border-color:var(--gray400)}}@media print{.page-cheatmd .content-inner *{background-color:transparent!important;border-color:var(--gray400)!important}.page-cheatmd .content-inner{max-width:100%;width:100%;padding:0;font-size:.7em}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:30px}.page-cheatmd .content-inner section.col-2{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:grid}.page-cheatmd .content-inner section.col-3{column-count:3}.page-cheatmd .content-inner h1{margin-top:0;margin-bottom:.5em}.page-cheatmd .content-inner h2.section-heading{font-weight:700;margin-top:1em;column-span:all}.page-cheatmd .content-inner section.h2{break-inside:avoid}.page-cheatmd .content-inner h3{font-weight:700;color:var(--mainDark)}.page-cheatmd .content-inner h3:after{height:2px;background-color:var(--gray400)}.page-cheatmd .content-inner section.h3{min-width:300px;break-inside:avoid}.page-cheatmd .content-inner h4{padding:.5em 0;border:none;font-weight:700;color:#000}.page-cheatmd .content-inner .h2 p{padding-left:0;padding-right:0;border:none!important}.page-cheatmd .content-inner code{line-height:1.5em}.page-cheatmd .content-inner .h2 table{font-variant-numeric:tabular-nums;break-inside:avoid}.page-cheatmd .content-inner .h2 :is(th,td){vertical-align:top;padding-left:0;padding-right:0}.page-cheatmd .content-inner .h2 thead{border-style:solid none;border-width:1px}.page-cheatmd .content-inner .h2 tr{border-bottom:none}.page-cheatmd .content-inner .h2 th{font-weight:700}.page-cheatmd .content-inner .h2 li{padding-left:0;padding-right:0;vertical-align:middle;border-bottom:none}.page-cheatmd .content-inner pre:hover button.copy-button,.page-cheatmd .content-inner div.tooltip{display:none}.page-cheatmd .content-inner footer p:not(.built-using){display:none}}code.makeup .unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.makeup .hll{background-color:#ffc}.makeup .bp{color:#3465a4}.makeup .c,.makeup .c1,.makeup .ch,.makeup .cm,.makeup .cp,.makeup .cpf,.makeup .cs{color:#4d4d4d}.makeup .dl{color:#408200}.makeup .err{color:#a40000;border:#ef2929}.makeup .fm,.makeup .g{color:#4d4d4c}.makeup .gd{color:#a40000}.makeup .ge{color:#4d4d4c;font-style:italic}.makeup .gh{color:navy;font-weight:700}.makeup .gi{color:#00a000}.makeup .go{color:#4d4d4c;font-style:italic}.makeup .gp{color:#4d4d4d}.makeup .gr{color:#ef2929}.makeup .gs{color:#4d4d4c;font-weight:700}.makeup .gt{color:#a40000;font-weight:700}.makeup .gu{color:purple;font-weight:700}.makeup .il{color:#0000cf;font-weight:700}.makeup .k,.makeup .kc,.makeup .kd,.makeup .kn,.makeup .kp,.makeup .kr,.makeup .kt{color:#204a87}.makeup .l{color:#4d4d4c}.makeup .ld{color:#c00}.makeup .m,.makeup .mb,.makeup .mf,.makeup .mh,.makeup .mi,.makeup .mo{color:#2937ab}.makeup .n{color:#4d4d4c}.makeup .na{color:#8a7000}.makeup .nb{color:#204a87}.makeup .nc{color:#0000cf}.makeup .nd{color:#5c35cc;font-weight:700}.makeup .ne{color:#c00;font-weight:700}.makeup .nf{color:#b65800}.makeup .ni{color:#bc5400}.makeup .nl{color:#b65800}.makeup .nn{color:#4d4d4c}.makeup .no{color:#a06600}.makeup .nt{color:#204a87;font-weight:700}.makeup .nv,.makeup .nx{color:#4d4d4c}.makeup .o{color:#bc5400}.makeup .ow{color:#204a87}.makeup .p,.makeup .py{color:#4d4d4c}.makeup .s,.makeup .s1,.makeup .s2,.makeup .sa,.makeup .sb,.makeup .sc{color:#408200}.makeup .sd{color:#8f5902;font-style:italic}.makeup .se{color:#204a87}.makeup .sh{color:#408200}.makeup .si{color:#204a87}.makeup .sr{color:#c00}.makeup .ss{color:#a06600}.makeup .sx{color:#408200}.makeup .vc,.makeup .vg,.makeup .vi,.makeup .vm,.makeup .x{color:#4d4d4c}.dark .makeup{color:#dce1e6}.dark .makeup .hll{background-color:#49483e}.dark .makeup .bp{color:#dce1e6}.dark .makeup .c,.dark .makeup .c1,.dark .makeup .ch,.dark .makeup .cm,.dark .makeup .cp,.dark .makeup .cpf,.dark .makeup .cs{color:#969386}.dark .makeup .dl{color:#e6db74}.dark .makeup .err{color:#960050;background-color:#1e0010}.dark .makeup .fm{color:#a6e22e}.dark .makeup .gd{color:#ff5385}.dark .makeup .ge{font-style:italic}.dark .makeup .gi{color:#a6e22e}.dark .makeup .gp{color:#969386}.dark .makeup .gs{font-weight:700}.dark .makeup .gu{color:#969386}.dark .makeup .gt{color:#ff5385;font-weight:700}.dark .makeup .il{color:#ae81ff}.dark .makeup .k,.dark .makeup .kc,.dark .makeup .kd{color:#66d9ef}.dark .makeup .kn{color:#ff5385}.dark .makeup .kp,.dark .makeup .kr,.dark .makeup .kt{color:#66d9ef}.dark .makeup .l,.dark .makeup .ld,.dark .makeup .m,.dark .makeup .mb,.dark .makeup .mf,.dark .makeup .mh,.dark .makeup .mi,.dark .makeup .mo{color:#ae81ff}.dark .makeup .n{color:#dce1e6}.dark .makeup .na{color:#a6e22e}.dark .makeup .nb{color:#dce1e6}.dark .makeup .nc,.dark .makeup .nd,.dark .makeup .ne,.dark .makeup .nf{color:#a6e22e}.dark .makeup .ni,.dark .makeup .nl,.dark .makeup .nn{color:#dce1e6}.dark .makeup .no{color:#66d9ef}.dark .makeup .nt{color:#ff5385}.dark .makeup .nv{color:#dce1e6}.dark .makeup .nx{color:#a6e22e}.dark .makeup .o,.dark .makeup .ow{color:#ff5385}.dark .makeup .p,.dark .makeup .py{color:#dce1e6}.dark .makeup .s,.dark .makeup .s1,.dark .makeup .s2,.dark .makeup .sa,.dark .makeup .sb,.dark .makeup .sc,.dark .makeup .sd{color:#e6db74}.dark .makeup .se{color:#ae81ff}.dark .makeup .sh,.dark .makeup .si,.dark .makeup .sr,.dark .makeup .ss,.dark .makeup .sx{color:#e6db74}.dark .makeup .vc,.dark .makeup .vg,.dark .makeup .vi,.dark .makeup .vm{color:#dce1e6}.tabset{--borderWidth: 1px;--tabsetPadding: var(--baseLineHeight);margin:var(--baseLineHeight) 0;border:var(--borderWidth) solid var(--tabBorder);padding:0 var(--tabsetPadding);border-radius:var(--borderRadius-lg)}.tabset-tablist{display:flex;overflow:auto;scrollbar-width:thin;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--tabBorderTop)}.tabset-tab{padding:1.1rem var(--tabsetPadding);font-family:var(--sansFontFamily);color:var(--textColor);margin-right:calc(-1 * var(--borderWidth));background-color:transparent;border:0;box-shadow:none;cursor:pointer;border-bottom-width:2px;border-bottom-style:solid;border-bottom-color:transparent;transition:var(--transition-all)}:hover.tabset-tab{border-bottom-color:var(--tabBorderTop);color:var(--textHeaders)}.tabset-tab[aria-selected=true]{border-bottom-color:var(--mainLight);color:var(--textHeaders)}.tabset-tab[aria-selected=true]:focus-visible{background-color:var(--mainLight);border-color:var(--mainLight);color:var(--white)}@media screen and (max-width: 768px){.tabset{--tabsetPadding: calc(var(--baseLineHeight) / 2)}.tabset-panel{padding-top:calc(var(--tabsetPadding) / 2);padding-bottom:calc(var(--tabsetPadding) / 2)}.tabset-panel pre,.tabset-panel blockquote,.tabset-panel section.admonition{margin-left:calc(-1 * var(--tabsetPadding))!important;margin-right:calc(-1 * var(--tabsetPadding))!important}.tabset-panel>pre code{border-left-width:0;border-right-width:0}}@media screen and (max-width: 768px){.tabset-panel>:is(:first-child){&:is(table){margin:.5em 0}}}@media screen and (min-width: 769px){.tabset-panel>:is(:first-child){&:is(blockquote,.admonition){margin-top:1.5em}&:is(p:has(img)){margin-top:1.25em}&:is(table){margin-top:.75em}}.tabset-panel>:is(:last-child){&:is(blockquote,.admonition){margin-bottom:1.5em}&:is(p:not(:has(img)),ul,ol){margin-bottom:1.25em}&:is(table){margin-bottom:.75em}}}body.preview{--sidebarWidth: 0px;overflow:hidden}body.preview .content{height:auto}body.preview .content-inner{padding:0}body.preview .sidebar,body.preview #sidebar-menu,body.preview .hover-link,body.preview .detail-link{display:none}body.preview :is(h1,h2,h3):first-of-type{margin-top:0}body:not(.dark) .content-inner img[src*="#gh-dark-mode-only"],body.dark .content-inner img[src*="#gh-light-mode-only"]{display:none}
-/*! Bundled license information:
-
-modern-normalize/modern-normalize.css:
-  (*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize *)
-*/
diff --git a/formatters/html/dist/html-erlang-ZK43ZOAC.css b/formatters/html/dist/html-erlang-ZK43ZOAC.css
new file mode 100644
index 000000000..4e4d3a929
--- /dev/null
+++ b/formatters/html/dist/html-erlang-ZK43ZOAC.css
@@ -0,0 +1,6 @@
+:root{--main: hsl(0, 100%, 44%);--mainDark: hsl(0, 100%, 34%);--mainDarkest: hsl(0, 100%, 24%);--mainLight: hsl(0, 100%, 64%);--mainLightest: hsl(0, 100%, 74%);--searchBarFocusColor: hsl(0, 100%, 50%);--searchBarBorderColor: rgb(255, 71, 71, .1);--link-color: hsl(212, 96%, 45%);--link-visited-color: hsl(212, 96%, 40%)}body.dark{--link-color: hsl(212, 56%, 72%);--link-visited-color: hsl(212, 56%, 67%)}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-ext-400-normal-N27NCBWW.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:400;src:url(./lato-latin-400-normal-W7754I4D.woff2) format("woff2"),url(./lato-all-400-normal-MNITWADU.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-ext-700-normal-Q2L5DVMW.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0100-024F,U+0259,U+1E00-1EFF,U+2020,U+20A0-20AB,U+20AD-20CF,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Lato;font-style:normal;font-display:swap;font-weight:700;src:url(./lato-latin-700-normal-2XVSBPG4.woff2) format("woff2"),url(./lato-all-700-normal-XMT5XFBS.woff) format("woff");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--content-width: 949px;--content-gutter: 60px;--borderRadius-lg: 14px;--borderRadius-base: 8px;--borderRadius-sm: 3px;--navTabBorderWidth: 2px;--sansFontFamily: "Lato", system-ui, Segoe UI, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";--monoFontFamily: ui-monospace, SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;--baseLineHeight: 1.5em;--gray25: hsl(207, 43%, 98%);--gray50: hsl(207, 43%, 96%);--gray100: hsl(212, 33%, 91%);--gray200: hsl(210, 29%, 88%);--gray300: hsl(210, 26%, 84%);--gray400: hsl(210, 21%, 64%);--gray450: hsl(210, 21%, 49%);--gray500: hsl(210, 21%, 34%);--gray600: hsl(210, 27%, 26%);--gray700: hsl(212, 35%, 17%);--gray750: hsl(214, 46%, 14%);--gray800: hsl(216, 52%, 11%);--gray800-opacity-0: hsla(216, 52%, 11%, 0%);--gray850: hsl(216, 63%, 8%);--gray900: hsl(218, 73%, 4%);--gray900-opacity-50: hsla(218, 73%, 4%, 50%);--gray900-opacity-0: hsla(218, 73%, 4%, 0%);--coldGrayFaint: hsl(240, 5%, 97%);--coldGrayLight: hsl(240, 5%, 88%);--coldGray-lightened-10: hsl(240, 5%, 56%);--coldGray: hsl(240, 5%, 46%);--coldGray-opacity-10: hsla(240, 5%, 46%, 10%);--coldGrayDark: hsl(240, 5%, 28%);--coldGrayDim: hsl(240, 5%, 18%);--yellowLight: hsl(43, 100%, 95%);--yellowDark: hsl(44, 100%, 15%);--yellow: hsl(60, 100%, 43%);--green-lightened-10: hsl(90, 100%, 45%);--green: hsl(90, 100%, 35%);--white: hsl(0, 0%, 100%);--white-opacity-50: hsla(0, 0%, 100%, 50%);--white-opacity-10: hsla(0, 0%, 100%, 10%);--white-opacity-0: hsla(0, 0%, 100%, 0%);--black: hsl(0, 0%, 0%);--black-opacity-10: hsla(0, 0%, 0%, 10%);--black-opacity-50: hsla(0, 0%, 0%, 50%);--orangeDark: hsl(30, 90%, 40%);--orangeLight: hsl(30, 80%, 50%);--text-xs: .75rem;--text-sm: .875rem;--text-md: 1rem;--text-lg: 1.125rem;--text-xl: 1.25rem;--transition-duration: .15s;--transition-timing: cubic-bezier(.4, 0, .2, 1);--transition-all: all var(--transition-duration) var(--transition-timing);--transition-colors: color var(--transition-duration) var(--transition-timing), background-color var(--transition-duration) var(--transition-timing), border-color var(--transition-duration) var(--transition-timing), text-decoration-color var(--transition-duration) var(--transition-timing), fill var(--transition-duration) var(--transition-timing), stroke var(--transition-duration) var(--transition-timing);--transition-opacity: opacity var(--transition-duration) var(--transition-timing)}@media screen and (max-width: 768px){:root{--content-width: 100%;--content-gutter: 20px}}option{background-color:var(--sidebarBackground)}:root{--background: var(--white);--contrast: var(--black);--textBody: var(--gray800);--textHeaders: var(--gray900);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--coldGrayFaint);--iconAction: var(--coldGray);--iconActionHover: var(--gray800);--blockquoteBackground: var(--coldGrayFaint);--blockquoteBorder: var(--coldGrayLight);--tableHeadBorder: var(--gray100);--tableBodyBorder: var(--gray50);--warningBackground: hsl( 33, 100%, 97%);--warningHeadingBackground: hsl( 33, 87%, 64%);--warningHeading: var(--black);--errorBackground: hsl( 7, 81%, 96%);--errorHeadingBackground: hsl( 6, 80%, 60%);--errorHeading: var(--white);--infoBackground: hsl(206, 91%, 96%);--infoHeadingBackground: hsl(213, 92%, 62%);--infoHeading: var(--white);--neutralBackground: hsl(212, 29%, 92%);--neutralHeadingBackground: hsl(220, 43%, 11%);--neutralHeading: var(--white);--tipBackground: hsl(142, 31%, 93%);--tipHeadingBackground: hsl(134, 39%, 36%);--tipHeading: var(--white);--fnSpecAttr: var(--coldGray);--fnDeprecated: var(--yellowLight);--blink: var(--yellowLight);--codeBackground: var(--gray25);--codeBorder: var(--gray100);--codeScrollThumb: var(--gray400);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray25);--admCodeBorder: var(--gray100);--admCodeColor: var(--black);--admInlineCodeColor: var(--black);--admInlineCodeBackground: var(--gray25);--admInlineCodeBorder: var(--gray100);--tabBorder: var(--gray300);--tabBorderTop: var(--gray100);--tabShadow: var(--gray25);--bottomActionsBtnBorder: var(--black-opacity-10);--bottomActionsBtnTitle: var(--mainDark);--modalBackground: var(--white);--settingsInput: var(--gray500);--settingsInputBackground: var(--white);--settingsInputBorder: var(--gray300);--settingsSectionBorder: var(--gray300);--quickSwitchInput: var(--gray500);--quickSwitchContour: var(--coldGray);--success: var(--green);--progressBarColor: var(--gray400);--sidebarAccentMain: var(--black);--sidebarBackground: var(--gray50);--sidebarHeader: var(--gray100);--sidebarMuted: var(--gray800);--sidebarHover: var(--black);--sidebarStaleVersion: var(--orangeDark);--sidebarSubheadings: var(--gray500);--sidebarItem: var(--black);--sidebarInactiveItemBorder: var(--gray500);--sidebarInactiveItemMarker: var(--gray200);--sidebarLanguageAccentBar: var(--mainDark);--sidebarActiveItem: var(--mainDarkest);--searchBarBorder: var(--gray200);--searchAccentMain: var(--gray600);--searchLanguageAccentBar: var(--main);--searchSearch: var(--white);--autocompleteBorder: rgba(3, 9, 19, .1);--autocompletePreview: var(--gray25);--autocompleteSelected: var(--gray25);--autocompleteHover: var(--gray50);--autocompleteBackground: var(--white);--suggestionBorder: var(--gray200);--autocompleteResults: var(--gray600);--autocompleteResultsBold: var(--gray800);--autocompleteLabelBack: var(--gray100);--autocompleteLabelFont: var(--gray600)}body.dark{--background: var(--gray900);--contrast: var(--white);--textBody: var(--gray200);--textHeaders: var(--gray100);--textDetailAccent: var(--mainLight);--textDetailBackground: var(--gray700);--iconAction: var(--coldGray-lightened-10);--iconActionHover: var(--white);--blockquoteBackground: var(--coldGray-opacity-10);--blockquoteBorder: var(--coldGrayDim);--tableHeadBorder: var(--gray600);--tableBodyBorder: var(--gray700);--warningBackground: hsla( 33, 30%, 60%, 10%);--warningHeadingBackground: hsla( 33, 66%, 35%, 80%);--warningHeading: var(--white);--errorBackground: hsla( 7, 30%, 60%, 10%);--errorHeadingBackground: hsla( 6, 70%, 40%, 80%);--errorHeading: var(--white);--infoBackground: hsla(206, 30%, 60%, 10%);--infoHeadingBackground: hsla(213, 55%, 35%, 80%);--infoHeading: var(--white);--neutralBackground: hsl(210, 30%, 60%, 10%);--neutralHeadingBackground: var(--gray600);--neutralHeading: var(--white);--tipBackground: hsla(142, 30%, 60%, 10%);--tipHeadingBackground: hsla(134, 45%, 30%, 80%);--tipHeading: var(--white);--fnSpecAttr: var(--gray400);--fnDeprecated: var(--yellowDark);--blink: var(--gray600);--codeBackground: var(--gray750);--codeBorder: var(--gray600);--codeScrollThumb: var(--gray500);--codeScrollBackground: var(--codeBorder);--admCodeBackground: var(--gray750);--admCodeBorder: var(--gray600);--admCodeColor: var(--gray100);--admInlineCodeColor: var(--gray100);--admInlineCodeBackground: var(--gray750);--admInlineCodeBorder: var(--gray600);--tabBorder: var(--gray700);--tabBorderTop: var(--gray700);--tabShadow: var(--black);--bottomActionsBtnBorder: var(--white-opacity-10);--bottomActionsBtnTitle: var(--mainLightest);--modalBackground: var(--gray800);--settingsInput: var(--white);--settingsInputBackground: var(--gray700);--settingsInputBorder: var(--gray700);--settingsSectionBorder: var(--gray700);--quickSwitchInput: var(--gray300);--quickSwitchContour: var(--gray500);--success: var(--green-lightened-10);--progressBarColor: var(--gray300);--sidebarAccentMain: var(--gray50);--sidebarBackground: var(--gray800);--sidebarHeader: var(--gray700);--sidebarMuted: var(--gray300);--sidebarHover: var(--white);--sidebarStaleVersion: var(--orangeLight);--sidebarSubheadings: var(--gray400);--sidebarItem: var(--gray200);--sidebarInactiveItemBorder: var(--gray400);--sidebarInactiveItemMarker: var(--gray600);--sidebarLanguageAccentBar: var(--mainLight);--sidebarActiveItem: var(--mainLightest);--searchBarBorder: var(--gray500);--searchAccentMain: var(--gray300);--searchSearch: var(--gray900);--autocompleteBorder: rgba(28,42,60,.75);--autocompletePreview: var(--gray750);--autocompleteSelected: var(--gray750);--autocompleteHover: var(--gray700);--autocompleteBackground: var(--gray800);--suggestionBorder: var(--gray600);--autocompleteResults: var(--gray200);--autocompleteResultsBold: var(--gray100);--autocompleteLabelBack: var(--gray600);--autocompleteLabelFont: rgba(255, 255, 255, .8)}:root:has(body.dark){color-scheme:dark}*,:before,:after{box-sizing:border-box}html{font-family:system-ui,Segoe UI,Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";line-height:1.15;-webkit-text-size-adjust:100%;tab-size:4}body{margin:0}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-color:currentcolor}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}legend{padding:0}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}@font-face{font-family:remixicon;src:url(./remixicon-QPNJX265.woff2) format("woff2");font-display:swap}[class^=ri-],[class*=" ri-"],.remix-icon{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:root{--icon-arrow-up-s: "\ea78";--icon-arrow-down-s: "\ea4e";--icon-arrow-right-s: "\ea6e";--icon-add: "\ea13";--icon-subtract: "\f1af";--icon-error-warning: "\eca1";--icon-external-link-line: "\ecaf";--icon-information: "\ee59";--icon-alert: "\ea21";--icon-double-quotes-l: "\ec51";--icon-link-m: "\eeaf";--icon-close-line: "\eb99";--icon-code-s-slash-line: "\ebad";--icon-menu-line: "\ef3e";--icon-search-2-line: "\f0cd";--icon-settings-3-line: "\f0e6";--icon-printer-line: "\f029"}.ri-lg{font-size:1.3333em;line-height:.75em;vertical-align:-.0667em}.ri-settings-3-line:before{content:var(--icon-settings-3-line)}.ri-add-line:before{content:var(--icon-add)}.ri-subtract-line:before{content:var(--icon-subtract)}.ri-arrow-up-s-line:before{content:var(--icon-arrow-up-s)}.ri-arrow-down-s-line:before{content:var(--icon-arrow-down-s)}.ri-arrow-right-s-line:before{content:var(--icon-arrow-right-s)}.ri-external-link-line:before{content:var(--icon-external-link-line)}.ri-search-2-line:before{content:var(--icon-search-2-line)}.ri-menu-line:before{content:var(--icon-menu-line)}.ri-close-line:before{content:var(--icon-close-line)}.ri-link-m:before{content:var(--icon-link-m)}.ri-code-s-slash-line:before{content:var(--icon-code-s-slash-line)}.ri-error-warning-line:before{content:var(--icon-error-warning)}.ri-information-line:before{content:var(--icon-information)}.ri-alert-line:before{content:var(--icon-alert)}.ri-double-quotes-l:before{content:var(--icon-double-quotes-l)}.ri-printer-line:before{content:var(--icon-printer-line)}html,body{box-sizing:border-box;height:100%;width:100%}body{--sidebarWidth: 300px;--sidebarMinWidth: 300px;--sidebarTransitionDuration: .3s;background-color:var(--background);color:var(--textBody);font-size:var(--text-md);line-height:1.6875em;outline:none!important}*,*:before,*:after{box-sizing:inherit}.body-wrapper{display:flex;height:100%}.sidebar{display:none;flex-direction:column;width:var(--sidebarWidth);min-width:var(--sidebarMinWidth);max-width:50vw;height:100%;position:fixed;top:0;left:calc(-1 * var(--sidebarWidth));z-index:100;resize:horizontal}.sidebar-button{padding:26px 12px 18px 19px;position:fixed;z-index:200;top:0;left:0;will-change:transform;transform:translate(0)}.content{left:0;width:100%;height:100%;position:absolute}.content .content-inner{container:content / inline-size;max-width:var(--content-width);min-height:100%;margin:0 auto;padding:0 var(--content-gutter) 10px}.content-inner:focus{outline:none}.sidebar-transition .sidebar,.sidebar-transition .sidebar-button,.sidebar-transition .content{transition:all var(--sidebarTransitionDuration) ease-in-out allow-discrete}.sidebar-open .sidebar,.sidebar-transition .sidebar{display:flex}.sidebar-open .sidebar{left:0}.sidebar-open .sidebar-button{transform:translate(calc(var(--sidebarWidth) - 100%))}.sidebar-open .content{width:calc(100% - var(--sidebarWidth));left:var(--sidebarWidth)}@media screen and (max-width: 768px){.sidebar-open .content{left:0;width:100%}.sidebar{max-width:90vw}body:not(.sidebar-open) .sidebar-button{position:absolute}}.swup-progress-bar{height:2px;background-color:var(--progressBarColor)}.sidebar{--sidebarFontSize: 16px;--sidebarLineHeight: 20px;font-family:var(--sansFontFamily);font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);background-color:var(--sidebarBackground);color:var(--sidebarAccentMain);overflow:hidden;& .sidebar-tabpanel{scrollbar-width:thin}}.apple-os .sidebar{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sidebar ul{list-style:none}.sidebar ul li{margin:0;padding:0 10px}.sidebar a{color:var(--sidebarAccentMain);text-decoration:none;transition:var(--transition-colors)}.sidebar a:hover{color:var(--sidebarHover)}.sidebar .external-link{margin:0 2.5px 0 0}.sidebar .sidebar-header{background-color:var(--sidebarHeader);width:100%}.sidebar .sidebar-projectInfo{display:flex;justify-content:start;align-items:center;gap:8px;margin:12px 34px 12px 14px}.sidebar .sidebar-projectInfo>div{flex:1}.sidebar .sidebar-projectImage{align-self:flex-end}.sidebar .sidebar-projectImage img{display:block;max-width:48px;max-height:48px}.sidebar .sidebar-projectName{font-weight:700;font-size:var(--text-xl);line-height:24px;color:var(--sidebarAccentMain);margin:0;padding:0;word-wrap:break-word;display:block;width:calc(100% - 12px)}.sidebar .sidebar-projectVersion{display:block;position:relative;margin:0;padding:0;font-size:var(--sidebarFontSize);line-height:var(--sidebarLineHeight);color:var(--sidebarMuted);width:calc(100% - 12px)}.sidebar .sidebar-projectVersion form{display:flex}.sidebar .sidebar-projectVersion select{cursor:pointer;position:relative;margin:0;padding:0 0 0 10px;border:none;-webkit-appearance:none;appearance:none;background-color:transparent;color:var(--sidebarMuted);z-index:2}.sidebar .sidebar-projectVersion option{color:initial}.sidebar .sidebar-projectVersionsCaret{position:absolute;left:0;top:2px;z-index:1;font-size:8px;color:var(--sidebarMuted)}.sidebar .sidebar-projectVersion select::-ms-expand{display:none}.sidebar .sidebar-staleVersion{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--sidebarStaleVersion)}.sidebar .sidebar-staleVersion>a{color:var(--sidebarStaleVersion);font-weight:400}.sidebar .sidebar-staleIcon{font-size:var(--text-lg);position:relative;top:3px;line-height:0}.sidebar .sidebar-list-nav{display:flex;margin:0;padding:0;overflow:auto;scrollbar-width:thin}.sidebar .sidebar-list-nav :is(li,li button){text-transform:uppercase;letter-spacing:.02em;font-size:var(--text-sm);color:var(--sidebarSubheadings);white-space:nowrap}.sidebar .sidebar-list-nav li{display:inline-block;padding:0}.sidebar .sidebar-list-nav button{background:none;border:0;border-radius:0;-webkit-appearance:none;text-align:inherit;color:inherit;font-weight:inherit;cursor:pointer;display:inline-block;line-height:27px;padding:4px 14px;transition:var(--transition-all)}.sidebar .sidebar-list-nav button{border-bottom:var(--navTabBorderWidth) solid transparent}.sidebar .sidebar-list-nav button:not([aria-selected]):hover{border-bottom:var(--navTabBorderWidth) solid var(--sidebarInactiveItemBorder);color:var(--sidebarAccentMain);transition:var(--transition-all)}.sidebar .sidebar-list-nav button[aria-selected]{border-bottom:var(--navTabBorderWidth) solid var(--sidebarLanguageAccentBar);color:var(--sidebarAccentMain)}.sidebar .sidebar-tabpanel{flex:1 1 .01%;overflow-y:auto;overscroll-behavior:contain;position:relative;-webkit-overflow-scrolling:touch;padding-top:12px;scroll-padding-top:40px}.sidebar .full-list{margin:0;padding:0 0 20px;position:relative}.sidebar .full-list :is(li,a){display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.sidebar .full-list li{padding:0;line-height:27px}.sidebar .full-list li.group{text-transform:uppercase;font-weight:700;font-size:.8em;margin:1.5em 0 0;line-height:1.8em;color:var(--sidebarSubheadings);padding-left:15px}.sidebar .full-list li.nesting-context{font-weight:700;font-size:.9em;line-height:1.8em;color:var(--sidebarSubheadings);margin-top:10px;padding-left:15px}.sidebar .full-list a{margin-right:30px;padding:3px 0 3px 12px;border-left:var(--navTabBorderWidth) solid transparent;color:var(--sidebarItem)}.sidebar .full-list a[aria-selected]{color:var(--sidebarActiveItem)}.sidebar .full-list button{appearance:none;background-color:transparent;border:0;padding:0;cursor:pointer;color:inherit;width:20px;text-align:center;font-size:calc(1.2 * var(--sidebarFontSize));line-height:var(--sidebarLineHeight);position:absolute;display:block;right:10px;transform:translateY(-100%)}.sidebar .full-list a[aria-selected]+button{color:var(--sidebarActiveItem)}.sidebar .full-list button:after{font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;content:var(--icon-arrow-down-s)}.sidebar .full-list button[aria-expanded=true]:after{content:var(--icon-arrow-up-s)}.sidebar .full-list ul{display:none;margin:10px 0 10px 10px;padding:0}.sidebar .full-list button[aria-expanded=true]+ul{display:block}.sidebar .full-list>li>a{height:27px;line-height:var(--sidebarLineHeight)}.sidebar .full-list>li>a:hover{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li>a[aria-selected]{border-left-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list>li:last-child{margin-bottom:30px}.sidebar .full-list>li.group:first-child{margin-top:0}.sidebar .full-list>li>ul>li:not(:has(li a[aria-selected=true]))>a[aria-selected=true]:before,.sidebar .full-list>li>ul>li>a:hover:before{content:"\2022";position:absolute;margin-left:-15px;color:var(--sidebarActiveItem)}.sidebar .full-list ul li{line-height:var(--sidebarFontSize);padding:0 8px}.sidebar .full-list ul a{padding-left:15px;height:24px}.sidebar .full-list ul button{font-size:var(--sidebarFontSize)}.sidebar .full-list ul button:after{content:var(--icon-add)}.sidebar .full-list ul button[aria-expanded=true]:after{content:var(--icon-subtract)}.sidebar .full-list ul ul{margin:9px 0 9px 10px}.sidebar .full-list ul ul li{height:20px;color:var(--sidebarAccentMain)}.sidebar .full-list ul ul a{border-left:1px solid var(--sidebarInactiveItemMarker);padding:0 10px;height:20px}.sidebar .full-list ul ul a:hover{border-color:var(--sidebarLanguageAccentBar)}.sidebar .full-list ul ul a[aria-selected]{color:var(--sidebarActiveItem);border-color:var(--sidebarLanguageAccentBar)}.sidebar-button{cursor:pointer;background-color:transparent;border:none;font-size:var(--sidebarFontSize);color:var(--sidebarAccentMain)}.sidebar-button:hover{color:var(--sidebarHover)}body:not(.sidebar-open) .sidebar-button{color:var(--contrast)}@media screen and (max-height: 500px){.sidebar{overflow-y:auto}.sidebar .full-list{overflow:visible}}.top-search{background-color:var(--background);top:0;z-index:99;position:relative;width:100%;padding:10px 0}.search-settings{display:flex;column-gap:12px;align-items:center;width:100%;position:relative}.search-bar{border:1px solid var(--searchBarBorder);border-radius:var(--borderRadius-base);height:48px;position:relative;width:100%}.top-search .search-bar .search-input{background-color:var(--searchSearch);border:1px solid transparent;border-radius:var(--borderRadius-base);color:var(--searchAccentMain);position:relative;height:46px;padding:8px 35px 8px 43px;width:100%;transition:var(--transition-all)}.top-search .search-bar .search-input::placeholder{color:var(--searchAccentMain);opacity:.5}.top-search .search-bar .search-input:focus{border:1px solid var(--searchBarFocusColor);border-radius:calc(var(--borderRadius-base) - 1px);position:relative;box-shadow:0 4px 20px 0 var(--searchBarBorderColor) inset}.top-search .search-bar .search-label{position:relative}.top-search .search-bar .search-button{font-size:var(--text-sm);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;left:11px;opacity:.5;padding:5px 1px 5px 5px;position:absolute;top:60%;transform:translateY(-60%);z-index:99;transition:var(--transition-all)}.top-search .search-bar.selected .search-button,.top-search .search-bar .search-button:hover,.top-search .search-bar .search-button:focus{color:var(--top-searchLanguageAccentBar);opacity:1}.top-search .search-bar .search-close-button{font-size:var(--text-md);color:var(--searchAccentMain);background-color:transparent;border:none;cursor:pointer;right:11px;margin:0;opacity:.5;padding:5px 1px 5px 0;position:absolute;transform:scaleY(0);top:calc(50% - 13px);transition:var(--transition-all);z-index:99}.top-search .search-bar .search-close-button:hover{opacity:.7}.top-search .search-settings button.icon-settings{display:flex;align-items:center;justify-content:flex-end}.top-search .search-settings .icon-settings{font-size:var(--text-xl);float:right;color:var(--iconAction);text-decoration:none;border:none;transition:color .3s ease-in-out;background-color:transparent;cursor:pointer;padding:0}.top-search .search-settings .icon-settings:hover{color:var(--iconActionHover)}.top-search .search-settings .icon-settings:visited{color:var(--iconAction)}@media screen and (max-width: 768px){.top-search{padding-left:calc(var(--content-gutter) + 36px);padding-right:var(--content-gutter);margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));width:calc(2 * var(--content-gutter) + 100%)}.search-settings{width:100%;box-sizing:border-box}}body.search-focused .search-bar .search-close-button{transform:scaleY(1);transition:var(--transition-all)}@media screen and (hover: hover){body.search-focused .top-search{position:sticky!important}body.search-focused .sidebar-button{position:fixed!important}}@media screen and (hover: none){body.scroll-sticky .top-search{position:sticky!important}body.scroll-sticky .sidebar-button{position:fixed!important}}*:focus,button:focus,[type=button]:focus,[type=reset]:focus,[type=submit]:focus{outline:2px solid var(--main);outline-offset:-2px}*:focus:not(:focus-visible),button:focus:not(:focus-visible),[type=button]:focus:not(:focus-visible),[type=reset]:focus:not(:focus-visible),[type=submit]:focus:not(:focus-visible){outline:0}input[type=text],input[type=number],input[type=date],input[type=datetime],input[type=datetime-local],input[type=email],input[type=month],input[type=number],input[type=password],input[type=search],input[type=tel],input[type=time],input[type=url],input[type=week],textarea{outline:0}.content-inner{font-size:1em;line-height:1.6875em;position:relative;background-color:var(--background);color:var(--textBody)}.content-inner .heading-with-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px}.content-inner .heading-with-actions>*:not(h1){flex-shrink:0}.content-inner .heading-with-actions h1{flex-grow:1;justify-self:flex-start;max-width:100%;margin:0;overflow-wrap:break-word}.content-inner .heading-with-actions .icon-action{width:20px;height:20px;display:flex;justify-content:center;align-items:center;font-weight:400}.content-inner .heading-with-actions.top-heading .icon-action{font-size:1.2rem}@container content (width > 600px){.content-inner .heading-with-actions.top-heading{flex-wrap:nowrap;align-items:flex-start;& h1{padding-right:32px}& .icon-action{padding-top:1.7rem}}}.content-inner .top-heading{padding-top:1rem}.content-inner :is(h1,h2,h3,h4,h5,h6){font-family:var(--sansFontFamily);font-weight:700;line-height:1.5em;word-wrap:break-word;color:var(--textHeaders)}.content-inner h1{font-size:2em;margin:.5em 0}.content-inner h1.section-heading{margin:1.5em 0 .5em}.content-inner h1 small{font-weight:400}.content-inner h2{font-size:1.6em;padding-top:1em;margin-bottom:.5em}.content-inner h3{font-size:1.375em;margin:1em 0 .5em}.content-inner li+li{margin-top:.25em}.content-inner :is(a,.a-main){color:var(--link-color);text-decoration:underline;text-decoration-skip-ink:auto}.content-inner :is(a:visited,.a-main:visited){color:var(--link-visited-color)}.content-inner .icon-action{color:var(--iconAction);text-decoration:none;border:none;transition:var(--transition-colors);background-color:transparent;cursor:pointer}.content-inner .icon-action:hover{color:var(--iconActionHover)}.content-inner .icon-action:visited{color:var(--iconAction)}.content-inner .livebook-badge-container{display:flex}.content-inner a.livebook-badge{display:inline-flex}.content-inner .note{color:var(--iconAction);font-size:var(--text-xs);font-weight:400}.content-inner blockquote,.content-inner section.admonition{border-left:3px solid var(--blockquoteBorder);position:relative;margin:1.5625em 0;padding:0 1.2rem;overflow:auto;background-color:var(--blockquoteBackground);border-radius:var(--borderRadius-base)}.content-inner blockquote p:last-child,.content-inner section.admonition p:last-child{padding-bottom:1em;margin-bottom:0}.content-inner table{margin:2em 0;border-collapse:collapse;display:block;overflow:auto}.content-inner th{text-align:left;font-family:var(--sansFontFamily);font-weight:700;padding-bottom:.5em;white-space:nowrap}.content-inner thead tr{border-bottom:1px solid var(--tableHeadBorder)}.content-inner tbody tr{border-bottom:1px solid var(--tableBodyBorder)}.content-inner tbody tr:last-child{border-bottom:none}.content-inner tr{vertical-align:bottom;height:2.5em}.content-inner :is(td,th){padding:.25em .25em .25em 1em;line-height:2em;vertical-align:top}.content-inner .section-heading{--icon-size: 16px;--icon-spacing: 5px;display:grid;grid-template:1fr / 1fr}@media screen and (max-width: 768px){.content-inner .section-heading{--icon-spacing: 2px}}.content-inner .section-heading>:is(.hover-link,.text){grid-row:1;grid-column:1}.content-inner .section-heading .hover-link{text-decoration:none}.content-inner .section-heading i{font-size:var(--icon-size);color:var(--mainLight);top:-2px;margin-left:calc(-1 * (var(--icon-size) + var(--icon-spacing)));padding-right:var(--icon-spacing);position:relative;opacity:0}.content-inner :is(blockquote,section.admonition) .section-heading i{display:none}.content-inner .section-heading:is(:hover,:focus,:target) i{opacity:1}.content-inner .app-vsn{display:none!important;font-size:.6em;line-height:1.5em}@media screen and (max-width: 768px){.content-inner .app-vsn{display:block!important}}.content-inner img{max-width:100%}.content-inner strong>code{font-weight:700}.content-inner code{font-family:var(--monoFontFamily);font-style:normal;line-height:24px;font-weight:400;font-size:var(--text-sm)}@media screen and (max-width: 768px){.content-inner :is(ol,ul){padding-left:calc(1.5 * var(--content-gutter))}}.content-inner section.admonition{border-radius:var(--borderRadius-base);border-left:0}.content-inner section.admonition.warning{background-color:var(--warningBackground)}.content-inner section.admonition.error{background-color:var(--errorBackground)}.content-inner section.admonition.info{background-color:var(--infoBackground)}.content-inner section.admonition.neutral{background-color:var(--neutralBackground)}.content-inner section.admonition.tip{background-color:var(--tipBackground)}.content-inner section.admonition>.admonition-title{color:var(--contrast);margin:0 -1.2rem;padding:.7rem 1.2rem .7rem 3.3rem;font-weight:700;font-style:normal}.content-inner section.admonition>.admonition-title:before{color:var(--contrast);position:absolute;left:1rem;font-size:1.8rem;font-family:remixicon;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.content-inner section.admonition>.admonition-title.warning{background-color:var(--warningHeadingBackground);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.warning:before{content:var(--icon-error-warning);color:var(--warningHeading)}.content-inner section.admonition>.admonition-title.error{background-color:var(--errorHeadingBackground);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.error:before{content:var(--icon-error-warning);color:var(--errorHeading)}.content-inner section.admonition>.admonition-title.info{background-color:var(--infoHeadingBackground);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.info:before{content:var(--icon-information);color:var(--infoHeading)}.content-inner section.admonition>.admonition-title.neutral{background-color:var(--neutralHeadingBackground);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.neutral:before{content:var(--icon-double-quotes-l);color:var(--neutralHeading)}.content-inner section.admonition>.admonition-title.tip{background-color:var(--tipHeadingBackground);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title.tip:before{content:var(--icon-information);color:var(--tipHeading)}.content-inner section.admonition>.admonition-title code{margin:0 .5ch}.content-inner section.admonition code{background-color:var(--admInlineCodeBackground);border:1px solid var(--admInlineCodeBorder);color:var(--admInlineCodeColor)}.content-inner section.admonition pre code{background-color:var(--admCodeBackground);border:1px solid var(--admCodeBorder);color:var(--admCodeColor)}.content-inner section.admonition>.admonition-title :is(a,a:visited){color:inherit;text-decoration-color:currentColor}@media screen and (max-width: 768px){.content-inner section.admonition{margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter));padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0}.content-inner section.admonition>.admonition-title{margin:0 calc(-1 * var(--content-gutter))}}.content-inner .summary h2 a{text-decoration:none;border:none;color:var(--textHeaders)!important}.content-inner .summary span.deprecated{color:var(--darkDeprecated);font-weight:400}.content-inner .summary .summary-row .summary-signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700}.content-inner .summary .summary-row .summary-signature a{text-decoration:none;border:none}.content-inner .summary .summary-row .summary-synopsis{padding:0 1.2em;margin:0 0 .5em}.content-inner .summary .summary-row .summary-synopsis p{margin:0;padding:0}@font-face{font-family:Consolas;src:local("Consolas");size-adjust:110%}.content-inner.content-inner :is(a:has(code,img),pre a){color:var(--link-color);text-shadow:none;text-decoration:none;background-image:none}.content-inner.content-inner :is(a:has(code,img),pre a):is(:visited,:active,:focus,:hover){color:var(--link-visited-color)}.content-inner code{background-color:var(--codeBackground);vertical-align:baseline;border-radius:var(--borderRadius-sm);padding:.1em .2em;border:1px solid var(--codeBorder);text-transform:none}.content-inner code.inline{border-radius:var(--borderRadius-sm);word-wrap:break-word}.content-inner pre{margin:var(--baseLineHeight) 0}.content-inner pre code{display:block;overflow-x:auto;white-space:inherit;padding:1em;scrollbar-width:thin}.content-inner pre code.output{margin:0 12px;max-height:400px;overflow:auto}.content-inner pre code.output+.copy-button{margin-right:12px}.content-inner pre code.output:before{content:"Output";display:block;position:absolute;top:-16px;left:12px;padding:2px 4px;font-size:var(--text-xs);font-family:var(--monoFontFamily);line-height:1;color:var(--textHeaders);background-color:var(--codeBackground);border:1px solid var(--codeBorder);border-bottom:0;border-radius:2px}@media screen and (max-width: 768px){.content-inner>pre:has(code),.content-inner section>pre:has(code){margin-left:calc(-1 * var(--content-gutter));margin-right:calc(-1 * var(--content-gutter))}.content-inner>pre code,.content-inner section>pre code{padding-left:var(--content-gutter);padding-right:var(--content-gutter);border-radius:0;border-left-width:0;border-right-width:0}}@keyframes blink-background{0%,to{background-color:var(--textDetailBackground)}50%{background-color:var(--blink)}}.content-inner .detail:target .detail-header{animation-duration:.55s;animation-name:blink-background;animation-iteration-count:1;animation-timing-function:ease-in-out}.content-inner .detail-header{margin:1em 0;padding:.5em .85em .5em 1em;background-color:var(--textDetailBackground);border-left:3px solid var(--textDetailAccent);font-size:1em;font-family:var(--monoFontFamily);position:relative}.content-inner .detail-header .signature{font-family:var(--monoFontFamily);font-size:13px;font-weight:700;line-height:2em}.content-inner .detail-header:hover a.detail-link,.content-inner .detail-header a.detail-link:focus{opacity:1;text-decoration:none}.content-inner .detail-header a.detail-link{transition:var(--transition-opacity);position:absolute;top:0;left:0;display:block;opacity:0;padding:.6em;line-height:1.5em;margin-left:-2.5em;text-decoration:none;border:none}@media screen and (max-width: 768px){.content-inner .detail-header a.detail-link{margin-left:-30px}}.content-inner .specs pre{font-family:var(--monoFontFamily);font-size:var(--text-xs);font-style:normal;line-height:24px;white-space:pre-wrap;margin:0;padding:0}.content-inner .specs .attribute{color:var(--fnSpecAttr)}.content-inner .docstring{margin:1.2em 0 3em 1.2em}@media screen and (max-width: 768px){.content-inner .docstring{margin-left:0}}.content-inner .docstring:is(h2,h3,h4,h5){font-weight:700}.content-inner .docstring h2{font-size:1.1em}.content-inner .docstring h3{font-size:1em}.content-inner .docstring h4{font-size:.95em}.content-inner .docstring h5{font-size:.9em}.content-inner div.deprecated{display:block;padding:1em;background-color:var(--fnDeprecated);border-radius:var(--borderRadius-sm);margin:var(--baseLineHeight) 0}.content-inner .footer{margin:4em auto 1em;text-align:center;font-size:var(--text-sm)}.content-inner .footer .line{display:inline-block}.content-inner .footer .footer-button{background-color:transparent;border:0;cursor:pointer;padding:0 4px}.content-inner .footer .footer-hex-package{margin-right:4px}.content-inner .bottom-actions{display:flex;justify-content:space-between;margin-top:4em;gap:12px}.bottom-actions-item{flex:1 1 0%}.content-inner .bottom-actions .bottom-actions-button{display:flex;text-decoration:none;flex-direction:column;border-radius:var(--borderRadius-sm);border:1px solid var(--bottomActionsBtnBorder);padding:12px 16px;min-width:150px;transition:var(--transition-all)}.content-inner .bottom-actions .bottom-actions-button:hover{border-color:var(--mainLight)}.content-inner .bottom-actions .bottom-actions-button .subheader{font-size:.8em;color:var(--textHeaders);white-space:nowrap}.content-inner .bottom-actions .bottom-actions-button .title{color:var(--bottomActionsBtnTitle)}.content-inner .bottom-actions .bottom-actions-button[rel=prev]{text-align:start}.content-inner .bottom-actions .bottom-actions-button[rel=next]{text-align:end}@media screen and (max-width: 768px){.content-inner .bottom-actions{flex-direction:column-reverse}}.page-cheatmd .content-inner{--horizontal-space: 1.5em;--vertical-space: 1em}@media (max-width: 600px){.page-cheatmd .content-inner{--horizontal-space: 1em;--vertical-space: .75em}}.page-cheatmd .content-inner{max-width:1200px}.page-cheatmd .content-inner h1{margin-bottom:var(--vertical-space)}.page-cheatmd .content-inner h2{margin:var(--vertical-space) 0;column-span:all;color:var(--gray700);font-weight:500}.dark .page-cheatmd .content-inner h2{color:var(--gray200)}.page-cheatmd .content-inner h3{margin:0 0 1em;font-weight:400}.page-cheatmd .content-inner section.h3{min-width:300px;margin:0;padding:0 0 calc(var(--vertical-space) * 2) 0;break-inside:avoid}.page-cheatmd .content-inner h3 .text{overflow:hidden}.page-cheatmd .content-inner h3 .text:after{content:"";margin-left:calc(var(--horizontal-space) / 2);vertical-align:baseline;display:inline-block;width:100%;height:1px;margin-right:-100%;margin-bottom:5px;background-color:var(--codeBorder)}.page-cheatmd .content-inner h4{display:block;margin:0;padding:.25em var(--horizontal-space);font-weight:400;background:var(--gray100);color:#567;border:solid 1px 1px 0 1px var(--gray100)}.dark .page-cheatmd .content-inner h4{background:#192f50;color:var(--textBody);border:1px solid #192f50;border-bottom:0}.page-cheatmd .content-inner .h2 p{margin:0;display:block;background:var(--gray50);padding:var(--vertical-space) var(--horizontal-space)}.dark .page-cheatmd .content-inner .h2 p{background:var(--gray700)}.page-cheatmd .content-inner .h2 p>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner pre code{padding:var(--vertical-space) var(--horizontal-space)}.page-cheatmd .content-inner .h2 pre{margin:0}.page-cheatmd .content-inner .h2 pre+pre{margin-top:-1px}.page-cheatmd .content-inner pre.wrap{white-space:break-spaces}@media screen and (max-width: 768px){.page-cheatmd .content-inner pre code{border-left-width:1px!important;border-right-width:1px!important}}.page-cheatmd .content-inner .h2 table{display:table;box-sizing:border-box;width:100%;border-collapse:collapse;margin:0}.page-cheatmd .content-inner .h2 th{padding:var(--vertical-space) var(--horizontal-space);line-height:inherit;margin-bottom:-1px;vertical-align:middle;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td{padding:var(--vertical-space) var(--horizontal-space);border:0;border-bottom:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 tr:first-child{border-top:1px solid var(--codeBorder)}.page-cheatmd .content-inner .h2 td code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner .h2 thead{background-color:var(--gray50)}.dark .page-cheatmd .content-inner .h2 thead{background-color:var(--gray700)}.page-cheatmd .content-inner .h2 tbody{background-color:var(--codeBackground)}.page-cheatmd .content-inner .h2 :is(ul,ol){margin:0;padding:0}.page-cheatmd .content-inner .h2 li{list-style-position:inside;padding:.5em var(--horizontal-space);line-height:2em;vertical-align:middle;background-color:var(--codeBackground);border-bottom:1px solid var(--codeBorder);margin-top:0}.page-cheatmd .content-inner .h2 :is(ul,ol)+pre code{border-top:0}.page-cheatmd .content-inner .h2 li>code{color:#eb5757;border-radius:var(--borderRadius-sm);padding:.2em .4em}.page-cheatmd .content-inner section.width-50{display:block;width:50%;margin:0}.page-cheatmd .content-inner section.width-50>section>table{width:100%}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:40px}.page-cheatmd .content-inner section.col-2{column-count:2;height:auto}.page-cheatmd .content-inner section.col-2-left{display:grid;grid-template-columns:calc(100% / 3) auto}.page-cheatmd .content-inner section.col-2-left>h2{grid-column-end:span 2}.page-cheatmd .content-inner section.col-3{column-count:3;height:auto}.page-cheatmd .content-inner section.list-4>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-4>ul>li{flex:0 0 25%}.page-cheatmd .content-inner section.list-6>ul{display:flex;flex-wrap:wrap}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 calc(100% / 6)}@media screen and (max-width: 1400px){.page-cheatmd .content-inner section.col-3{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:flex;flex-direction:column}}@media screen and (max-width: 1200px){.page-cheatmd .content-inner section:is(.col-2,.col-3){display:flex;flex-direction:column}.page-cheatmd .content-inner section.list-6>ul>li{flex:0 0 25%}}@media screen and (max-width: 1000px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 calc(100% / 3)}}@media screen and (max-width: 600px){.page-cheatmd .content-inner section:is(.list-4,.list-6)>ul>li{flex:0 0 50%}.page-cheatmd .content-inner section.width-50{width:100%}}#search{min-height:200px;position:relative}#search .loading{height:64px;width:64px;position:absolute;top:50%;left:calc(50% - 32px)}#search .loading div{box-sizing:border-box;display:block;position:absolute;width:51px;height:51px;margin:6px;border:6px solid var(--coldGray);border-radius:50%;animation:loading 1.2s cubic-bezier(.5,0,.5,1) infinite;border-color:var(--coldGray) transparent transparent transparent}#search .loading div:nth-child(1){animation-delay:-.45s}#search .loading div:nth-child(2){animation-delay:-.3s}#search .loading div:nth-child(3){animation-delay:-.15s}@keyframes loading{0%{transform:rotate(0)}to{transform:rotate(360deg)}}#search .result{margin:2em 0 2.5em}#search .result p{margin:0}#search .result-id{font-size:1.4em;margin:0}#search .result-id a{text-decoration:none;color:var(--textHeaders);transition:var(--transition-colors)}#search .result-id a:is(:visited,:active){color:var(--textHeaders)}#search .result-id a:is(:hover,:focus){color:var(--main)}#search :is(.result-id,.result-elem) em{font-style:normal;color:var(--main)}#search .result-id small{font-weight:400}@keyframes keyboard-shortcuts-show{0%{opacity:0}to{opacity:1}}.modal{animation-duration:.15s;animation-name:keyboard-shortcuts-show;animation-iteration-count:1;animation-timing-function:ease-in-out;display:none;background-color:#000000bf;position:fixed;inset:0;z-index:300}.modal.shown{display:block}.modal .modal-contents{margin:75px auto 0;max-width:500px;background-color:var(--modalBackground);border-radius:var(--borderRadius-sm);box-shadow:2px 2px 8px #0003;padding:25px 35px 35px}@media screen and (max-width: 768px){.modal .modal-contents{padding:20px}}.modal .modal-header{display:flex;align-items:start}.modal .modal-title{display:inline-block;flex-grow:1;font-size:1.2rem;font-weight:700;margin-bottom:20px}.modal .modal-title button{border:none;background-color:transparent;color:var(--textHeaders);font-weight:700;margin-right:30px;padding-left:0;text-align:left;transition:var(--transition-colors)}.modal .modal-title button:hover{color:var(--main);cursor:pointer}.modal .modal-title button.active{color:var(--main)}.modal .modal-close{cursor:pointer;display:block;font-size:1.5rem;margin:-8px -8px 0 0;padding:8px;opacity:.7;background-color:transparent;color:var(--textHeaders);border:none;transition:var(--transition-opacity)}.modal .modal-close:hover{opacity:1}#keyboard-shortcuts-content dl.shortcut-row{display:flex;align-items:center;justify-content:space-between;margin:0;padding:6px 0 8px;border-bottom:1px solid var(--settingsSectionBorder)}#keyboard-shortcuts-content dl.shortcut-row:last-of-type{border-bottom-style:none}#keyboard-shortcuts-content dl.shortcut-row:first-child{padding-top:0}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){display:inline-block}#keyboard-shortcuts-content kbd>kbd{background-color:var(--settingsInputBorder);color:var(--contrast);border-radius:var(--borderRadius-sm);font-family:inherit;font-weight:700;display:inline-block;line-height:1;padding:4px 7px 6px;min-width:26px;text-align:center;font-size:var(--text-sm)}#keyboard-shortcuts-content :is(.shortcut-keys,.shortcut-description){margin:0}#quick-switch-modal-body{width:100%;position:relative}#quick-switch-modal-body .ri-search-2-line{position:absolute;left:0;top:0;padding:4px 10px;color:var(--quickSwitchContour);font-weight:700}#quick-switch-modal-body #quick-switch-input{width:100%;padding:8px 6px 8px 38px;border:none;color:var(--quickSwitchInput);background-color:transparent;border-bottom:1px solid var(--quickSwitchContour);box-sizing:border-box;transition:all .12s ease-out}#quick-switch-modal-body #quick-switch-results{margin:0}#quick-switch-modal-body .quick-switch-result{padding:2px 5px;border-bottom:1px dotted var(--quickSwitchContour);transition:all .12s ease-out}#quick-switch-modal-body .quick-switch-result:last-child{border-bottom:none}#quick-switch-modal-body .quick-switch-result:hover{cursor:pointer}#quick-switch-modal-body .quick-switch-result:is(:hover,.selected){border-left:4px solid var(--main);background-color:var(--codeBackground)}.autocomplete{display:none;position:absolute;width:calc(100% - 32px);top:55px}.autocomplete .triangle{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;border-bottom:12px solid var(--autocompleteBackground);position:absolute;top:8px;left:26px;transform:translate(-50%);z-index:100;background-color:transparent}.autocomplete-preview{width:100%;margin:0;height:100%;line-height:20px;background-color:var(--background);font-family:var(--sansFontFamily);border:4px solid var(--autocompleteBorder);padding:12px 16px}.autocomplete-preview div,.autocomplete-preview span{display:none}.autocomplete-preview.loading div{float:left;display:block;border:5px solid var(--autocompleteBorder);border-radius:50%;border-top:5px solid var(--textDetailAccent);width:20px;height:20px;animation:spinner 4s linear infinite}.autocomplete-preview.loading span{color:var(--autocompleteResults);display:inline;margin-left:6px}.autocomplete-preview.loading span:after{color:var(--autocompleteResults);content:"Loading"}@keyframes spinner{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.autocomplete-preview.loading iframe{height:0}.autocomplete-preview iframe{width:100%;height:100%;border:0}.autocomplete-results{list-style:none;margin:0;padding:15px 20px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;color:var(--autocompleteResults);font-family:var(--sansFontFamily);font-weight:300;font-size:.9rem}.autocomplete-results .query{margin-right:auto}.autocomplete-results .bold{color:var(--autocompleteResultsBold);font-weight:400}.autocomplete.shown{display:block}.autocomplete-container{position:absolute;top:15px;width:100%;z-index:200}.autocomplete-suggestions{background-color:var(--autocompleteBackground);border-radius:var(--borderRadius-base);box-shadow:0 15px 99px 0 var(--autocompleteBorder);overflow-y:auto;max-height:450px;white-space:normal;overflow-x:hidden;overscroll-behavior-y:contain;scrollbar-width:thin}.autocomplete-suggestions.previewing:has(.selected){max-height:80vh}.autocomplete-suggestions.previewing:has(.selected) .autocomplete-suggestion:not(.selected){display:none}.autocomplete-suggestions.previewing:not(:has(.selected)) .autocomplete-preview{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview{display:none}.autocomplete-suggestion{color:var(--textHeaders)!important;display:block;padding:12px 20px;text-decoration:none!important;transition:var(--transition-colors);border-top:1px solid var(--suggestionBorder);font-size:.9rem}.autocomplete-suggestion.selected{background-color:var(--autocompleteSelected);box-shadow:inset 2px 0 var(--main)}.autocomplete-suggestion:hover{background-color:var(--autocompleteHover)}.autocomplete-suggestion:not(.selected) .autocomplete-preview-indicator{display:none}.autocomplete-preview-indicator{float:right}.autocomplete-preview-indicator button{color:var(--iconAction);display:flex;align-items:center;text-decoration:none;border:1px solid var(--suggestionBorder);border-radius:var(--borderRadius-base);transition:var(--transition-colors);background-color:var(--autocompletePreview);cursor:pointer;padding:4px 8px;font-size:var(--text-sm)}.autocomplete-preview-indicator button:hover{color:var(--iconActionHover);background-color:var(--autocompleteHover)}.autocomplete-preview-indicator button i{margin-right:4px}.autocomplete-suggestions.previewing .autocomplete-preview-indicator-closed{display:none}.autocomplete-suggestions:not(.previewing) .autocomplete-preview-indicator-open{display:none}.autocomplete-suggestion:hover:not(.selected) .autocomplete-preview-indicator-closed{display:block}.autocomplete-suggestion em{font-style:normal;font-weight:700}.autocomplete-suggestion .description{opacity:.6;padding-top:3px}.autocomplete-suggestion .label{background-color:var(--autocompleteLabelBack);opacity:.6;color:var(--autocompleteLabelFont);padding:4px 8px;border-radius:4px;margin-left:5px;text-transform:uppercase;font-family:var(--sansFontFamily);font-size:.7rem}.autocomplete-suggestion .header{margin-right:5px}.autocomplete-suggestion .title,.autocomplete-suggestion .description{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:100%}@media screen and (hover: none){.autocomplete-preview-indicator,.autocomplete-results .press-return{display:none!important}}.tooltip{box-shadow:0 0 10px var(--black-opacity-10);max-height:300px;max-width:500px;padding:0;position:absolute;pointer-events:none;margin:0;z-index:99;top:0;left:0;visibility:hidden;transform:translateY(20px);opacity:0;transition:.2s visibility ease-out,.2s transform ease-out,.2s opacity ease-out}.tooltip.tooltip-shown{visibility:visible;transform:translateY(0);opacity:1}.tooltip .tooltip-body{border:1px solid var(--codeBorder);border-radius:var(--borderRadius-sm);overflow:auto}.tooltip .tooltip-body .signature{min-width:320px;width:100%;line-height:1em}.tooltip .tooltip-body .detail-header{border-left:0;margin-bottom:0;margin-top:0}.tooltip .tooltip-body .docstring{background-color:var(--background);padding:1.2em;margin:0;width:498px}.tooltip .tooltip-body .docstring-plain{max-width:498px;width:auto}.tooltip .tooltip-body .version-info{float:right;font-family:var(--monoFontFamily);font-weight:400;opacity:.3;padding-left:.3em}pre{position:relative}pre:hover .copy-button,pre .copy-button:focus{opacity:1}.copy-button{display:flex;opacity:0;position:absolute;top:7px;right:8px;padding:8px;background-color:transparent;backdrop-filter:blur(8px);border-radius:var(--borderRadius-sm);border:1px solid var(--codeBorder);cursor:pointer;transition:var(--transition-all);font-size:var(--text-sm);line-height:24px;color:currentColor;& svg[aria-live=polite]{display:none}}.copy-button svg{opacity:.5;transition:var(--transition-all)}pre .copy-button:hover svg,pre .copy-button:focus-visible svg{opacity:1}.copy-button svg{width:20px}.copy-button.clicked{opacity:1;color:var(--success);& svg[aria-live=polite]{display:block}}.copy-button.clicked svg{display:none;color:currentColor}#settings-modal-content{margin-top:10px}#settings-modal-content .hidden{display:none}#settings-modal-content .input{box-sizing:border-box;width:80%;padding:8px;font-size:var(--text-sm);background-color:var(--settingsInputBackground);color:var(--settingsInput);border:1px solid var(--settingsInputBorder);border-radius:var(--borderRadius-base);transition:var(--transition-all)}#settings-modal-content .input:focus{border-color:var(--main)}#settings-modal-content .input::placeholder{color:var(--gray400)}#settings-modal-content .switch-button-container{display:flex;align-items:center;justify-content:space-between;border-top:1px solid var(--settingsSectionBorder);padding:10px 0}#settings-modal-content .switch-button-container:first-of-type{border-top-style:none;padding-top:0}#settings-modal-content .switch-button-container>div>span{font-size:var(--text-md)}#settings-modal-content .switch-button-container>div>p{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:var(--text-sm);line-height:1.4;margin:0;padding-bottom:6px;padding-right:10px}#settings-modal-content .switch-button{position:relative;display:inline-block;flex-shrink:0;width:40px;height:20px;user-select:none;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox{appearance:none;position:absolute;display:block;width:20px;height:20px;border-radius:1000px;background-color:#91a4b7;border:3px solid #e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__bg{display:block;width:100%;height:100%;border-radius:1000px;background-color:#e5edf5;cursor:pointer;transition:var(--transition-all)}#settings-modal-content .switch-button__checkbox:checked{background-color:#fff;border-color:var(--main);transform:translate(100%)}#settings-modal-content .switch-button__checkbox:checked+.switch-button__bg{background-color:var(--main)}#settings-modal-content .switch-button__checkbox:focus{outline:0}#settings-modal-content .switch-button__checkbox:focus+.switch-button__bg{outline:2px solid var(--main);outline-offset:2px}#settings-modal-content .switch-button__checkbox:focus:not(:focus-visible)+.switch-button__bg{outline:0}#settings-modal-content .settings-select{cursor:pointer;position:relative;border:none;background-color:transparent;color:var(--textBody)}#settings-modal-content .settings-select option{color:initial}#toast{visibility:hidden;opacity:0;position:fixed;z-index:1;left:50%;bottom:1rem;min-width:3rem;margin:0 -1.2rem;padding:.7rem 1.2rem;text-align:center;font-weight:700;border-radius:var(--borderRadius-base);border:1px solid var(--codeBorder);background-color:var(--codeBackground);color:var(--textBody);transition:opacity .4s ease-in-out,transform .3s ease-out;cursor:default}#toast.show{visibility:visible;opacity:1;transform:translateY(-.75rem)}@media (prefers-reduced-motion: reduce){#toast{transition:none}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0;user-select:none}@media print{.body-wrapper{display:block}.sidebar,.sidebar-button,.top-search{display:none}.content{padding-left:0;overflow:visible;left:0;width:100%}.summary-row{break-inside:avoid}#toast{display:none}.content-inner{padding:0}.content-inner .section-heading a.hover-link,.content-inner button.icon-action,.content-inner a.icon-action,.content-inner .bottom-actions{display:none}.footer p:first-of-type{display:none}.content-inner section.admonition{border:2px solid var(--gray400)}.content-inner section.admonition>.admonition-title{color:var(--textHeaders);border-bottom:2px solid var(--gray400)}.content-inner pre code.makeup{border-color:var(--gray400);white-space:break-spaces;break-inside:avoid}.content-inner blockquote code.inline,.content-inner code.inline{border-color:var(--gray400)}}@media print{.page-cheatmd .content-inner *{background-color:transparent!important;border-color:var(--gray400)!important}.page-cheatmd .content-inner{max-width:100%;width:100%;padding:0;font-size:.7em}.page-cheatmd .content-inner section:is(.col-2,.col-2-left,.col-3){column-gap:30px}.page-cheatmd .content-inner section.col-2{column-count:2}.page-cheatmd .content-inner section.col-2-left{display:grid}.page-cheatmd .content-inner section.col-3{column-count:3}.page-cheatmd .content-inner h1{margin-top:0;margin-bottom:.5em}.page-cheatmd .content-inner h2.section-heading{font-weight:700;margin-top:1em;column-span:all}.page-cheatmd .content-inner section.h2{break-inside:avoid}.page-cheatmd .content-inner h3{font-weight:700;color:var(--mainDark)}.page-cheatmd .content-inner h3:after{height:2px;background-color:var(--gray400)}.page-cheatmd .content-inner section.h3{min-width:300px;break-inside:avoid}.page-cheatmd .content-inner h4{padding:.5em 0;border:none;font-weight:700;color:#000}.page-cheatmd .content-inner .h2 p{padding-left:0;padding-right:0;border:none!important}.page-cheatmd .content-inner code{line-height:1.5em}.page-cheatmd .content-inner .h2 table{font-variant-numeric:tabular-nums;break-inside:avoid}.page-cheatmd .content-inner .h2 :is(th,td){vertical-align:top;padding-left:0;padding-right:0}.page-cheatmd .content-inner .h2 thead{border-style:solid none;border-width:1px}.page-cheatmd .content-inner .h2 tr{border-bottom:none}.page-cheatmd .content-inner .h2 th{font-weight:700}.page-cheatmd .content-inner .h2 li{padding-left:0;padding-right:0;vertical-align:middle;border-bottom:none}.page-cheatmd .content-inner pre:hover button.copy-button,.page-cheatmd .content-inner div.tooltip{display:none}.page-cheatmd .content-inner footer p:not(.built-using){display:none}}code.makeup .unselectable{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.makeup .hll{background-color:#ffc}.makeup .bp{color:#3465a4}.makeup .c,.makeup .c1,.makeup .ch,.makeup .cm,.makeup .cp,.makeup .cpf,.makeup .cs{color:#4d4d4d}.makeup .dl{color:#408200}.makeup .err{color:#a40000;border:#ef2929}.makeup .fm,.makeup .g{color:#4d4d4c}.makeup .gd{color:#a40000}.makeup .ge{color:#4d4d4c;font-style:italic}.makeup .gh{color:navy;font-weight:700}.makeup .gi{color:#00a000}.makeup .go{color:#4d4d4c;font-style:italic}.makeup .gp{color:#4d4d4d}.makeup .gr{color:#ef2929}.makeup .gs{color:#4d4d4c;font-weight:700}.makeup .gt{color:#a40000;font-weight:700}.makeup .gu{color:purple;font-weight:700}.makeup .il{color:#0000cf;font-weight:700}.makeup .k,.makeup .kc,.makeup .kd,.makeup .kn,.makeup .kp,.makeup .kr,.makeup .kt{color:#204a87}.makeup .l{color:#4d4d4c}.makeup .ld{color:#c00}.makeup .m,.makeup .mb,.makeup .mf,.makeup .mh,.makeup .mi,.makeup .mo{color:#2937ab}.makeup .n{color:#4d4d4c}.makeup .na{color:#8a7000}.makeup .nb{color:#204a87}.makeup .nc{color:#0000cf}.makeup .nd{color:#5c35cc;font-weight:700}.makeup .ne{color:#c00;font-weight:700}.makeup .nf{color:#b65800}.makeup .ni{color:#bc5400}.makeup .nl{color:#b65800}.makeup .nn{color:#4d4d4c}.makeup .no{color:#a06600}.makeup .nt{color:#204a87;font-weight:700}.makeup .nv,.makeup .nx{color:#4d4d4c}.makeup .o{color:#bc5400}.makeup .ow{color:#204a87}.makeup .p,.makeup .py{color:#4d4d4c}.makeup .s,.makeup .s1,.makeup .s2,.makeup .sa,.makeup .sb,.makeup .sc{color:#408200}.makeup .sd{color:#8f5902;font-style:italic}.makeup .se{color:#204a87}.makeup .sh{color:#408200}.makeup .si{color:#204a87}.makeup .sr{color:#c00}.makeup .ss{color:#a06600}.makeup .sx{color:#408200}.makeup .vc,.makeup .vg,.makeup .vi,.makeup .vm,.makeup .x{color:#4d4d4c}.dark .makeup{color:#dce1e6}.dark .makeup .hll{background-color:#49483e}.dark .makeup .bp{color:#dce1e6}.dark .makeup .c,.dark .makeup .c1,.dark .makeup .ch,.dark .makeup .cm,.dark .makeup .cp,.dark .makeup .cpf,.dark .makeup .cs{color:#969386}.dark .makeup .dl{color:#e6db74}.dark .makeup .err{color:#960050;background-color:#1e0010}.dark .makeup .fm{color:#a6e22e}.dark .makeup .gd{color:#ff5385}.dark .makeup .ge{font-style:italic}.dark .makeup .gi{color:#a6e22e}.dark .makeup .gp{color:#969386}.dark .makeup .gs{font-weight:700}.dark .makeup .gu{color:#969386}.dark .makeup .gt{color:#ff5385;font-weight:700}.dark .makeup .il{color:#ae81ff}.dark .makeup .k,.dark .makeup .kc,.dark .makeup .kd{color:#66d9ef}.dark .makeup .kn{color:#ff5385}.dark .makeup .kp,.dark .makeup .kr,.dark .makeup .kt{color:#66d9ef}.dark .makeup .l,.dark .makeup .ld,.dark .makeup .m,.dark .makeup .mb,.dark .makeup .mf,.dark .makeup .mh,.dark .makeup .mi,.dark .makeup .mo{color:#ae81ff}.dark .makeup .n{color:#dce1e6}.dark .makeup .na{color:#a6e22e}.dark .makeup .nb{color:#dce1e6}.dark .makeup .nc,.dark .makeup .nd,.dark .makeup .ne,.dark .makeup .nf{color:#a6e22e}.dark .makeup .ni,.dark .makeup .nl,.dark .makeup .nn{color:#dce1e6}.dark .makeup .no{color:#66d9ef}.dark .makeup .nt{color:#ff5385}.dark .makeup .nv{color:#dce1e6}.dark .makeup .nx{color:#a6e22e}.dark .makeup .o,.dark .makeup .ow{color:#ff5385}.dark .makeup .p,.dark .makeup .py{color:#dce1e6}.dark .makeup .s,.dark .makeup .s1,.dark .makeup .s2,.dark .makeup .sa,.dark .makeup .sb,.dark .makeup .sc,.dark .makeup .sd{color:#e6db74}.dark .makeup .se{color:#ae81ff}.dark .makeup .sh,.dark .makeup .si,.dark .makeup .sr,.dark .makeup .ss,.dark .makeup .sx{color:#e6db74}.dark .makeup .vc,.dark .makeup .vg,.dark .makeup .vi,.dark .makeup .vm{color:#dce1e6}.tabset{--borderWidth: 1px;--tabsetPadding: var(--baseLineHeight);margin:var(--baseLineHeight) 0;border:var(--borderWidth) solid var(--tabBorder);padding:0 var(--tabsetPadding);border-radius:var(--borderRadius-lg)}.tabset-tablist{display:flex;overflow:auto;scrollbar-width:thin;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:var(--tabBorderTop)}.tabset-tab{padding:1.1rem var(--tabsetPadding);font-family:var(--sansFontFamily);color:var(--textColor);margin-right:calc(-1 * var(--borderWidth));background-color:transparent;border:0;box-shadow:none;cursor:pointer;border-bottom-width:2px;border-bottom-style:solid;border-bottom-color:transparent;transition:var(--transition-all)}:hover.tabset-tab{border-bottom-color:var(--tabBorderTop);color:var(--textHeaders)}.tabset-tab[aria-selected=true]{border-bottom-color:var(--mainLight);color:var(--textHeaders)}.tabset-tab[aria-selected=true]:focus-visible{background-color:var(--mainLight);border-color:var(--mainLight);color:var(--white)}@media screen and (max-width: 768px){.tabset{--tabsetPadding: calc(var(--baseLineHeight) / 2)}.tabset-panel{padding-top:calc(var(--tabsetPadding) / 2);padding-bottom:calc(var(--tabsetPadding) / 2)}.tabset-panel pre,.tabset-panel blockquote,.tabset-panel section.admonition{margin-left:calc(-1 * var(--tabsetPadding))!important;margin-right:calc(-1 * var(--tabsetPadding))!important}.tabset-panel>pre code{border-left-width:0;border-right-width:0}}@media screen and (max-width: 768px){.tabset-panel>:is(:first-child){&:is(table){margin:.5em 0}}}@media screen and (min-width: 769px){.tabset-panel>:is(:first-child){&:is(blockquote,.admonition){margin-top:1.5em}&:is(p:has(img)){margin-top:1.25em}&:is(table){margin-top:.75em}}.tabset-panel>:is(:last-child){&:is(blockquote,.admonition){margin-bottom:1.5em}&:is(p:not(:has(img)),ul,ol){margin-bottom:1.25em}&:is(table){margin-bottom:.75em}}}body.preview{--sidebarWidth: 0px;overflow:hidden}body.preview .content{height:auto}body.preview .content-inner{padding:0}body.preview .sidebar,body.preview #sidebar-menu,body.preview .hover-link,body.preview .detail-link{display:none}body.preview :is(h1,h2,h3):first-of-type{margin-top:0}body:not(.dark) .content-inner img[src*="#gh-dark-mode-only"],body.dark .content-inner img[src*="#gh-light-mode-only"]{display:none}
+/*! Bundled license information:
+
+modern-normalize/modern-normalize.css:
+  (*! modern-normalize v3.0.1 | MIT License | https://github.com/sindresorhus/modern-normalize *)
+*/
diff --git a/lib/ex_doc/formatter/epub.ex b/lib/ex_doc/formatter/epub.ex
index 66f642994..84d89e0b3 100644
--- a/lib/ex_doc/formatter/epub.ex
+++ b/lib/ex_doc/formatter/epub.ex
@@ -62,12 +62,10 @@ defmodule ExDoc.Formatter.EPUB do
 
   defp generate_extras(config) do
     for {_title, extras} <- config.extras,
-        extra_config <- extras,
-        not is_map_key(extra_config, :url) do
-      %{id: id, title: title, title_content: title_content, content: content} = extra_config
-
-      output = "#{config.output}/OEBPS/#{id}.xhtml"
-      html = Templates.extra_template(config, title, title_content, content)
+        node <- extras,
+        not is_map_key(node, :url) do
+      output = "#{config.output}/OEBPS/#{node.id}.xhtml"
+      html = Templates.extra_template(config, node)
 
       if File.regular?(output) do
         Utils.warn("file #{Path.relative_to_cwd(output)} already exists", [])
diff --git a/lib/ex_doc/formatter/epub/templates.ex b/lib/ex_doc/formatter/epub/templates.ex
index 9e4e72f3b..e59a660bc 100644
--- a/lib/ex_doc/formatter/epub/templates.ex
+++ b/lib/ex_doc/formatter/epub/templates.ex
@@ -9,6 +9,9 @@ defmodule ExDoc.Formatter.EPUB.Templates do
   alias ExDoc.Formatter.HTML.Templates, as: H
   alias ExDoc.Formatter.EPUB.Assets
 
+  # The actual rendering happens here
+  defp render_doc(ast), do: ast && ExDoc.DocAST.to_string(ast)
+
   @doc """
   Generate content from the module template for a given `node`
   """
@@ -76,7 +79,7 @@ defmodule ExDoc.Formatter.EPUB.Templates do
     :def,
     :extra_template,
     Path.expand("templates/extra_template.eex", __DIR__),
-    [:config, :title, :title_content, :content],
+    [:config, :node],
     trim: true
   )
 
diff --git a/lib/ex_doc/formatter/epub/templates/extra_template.eex b/lib/ex_doc/formatter/epub/templates/extra_template.eex
index c73cb60ce..0ad9b52f2 100644
--- a/lib/ex_doc/formatter/epub/templates/extra_template.eex
+++ b/lib/ex_doc/formatter/epub/templates/extra_template.eex
@@ -1,8 +1,8 @@
-<%= head_template(config, title) %>
+<%= head_template(config, node.title) %>
     

- <%=h title_content %> + <%=h node.title_content %>

- <%= H.link_headings(content) %> + <%= render_doc(node.doc) %> <%= before_closing_body_tag(config, :epub) %> diff --git a/lib/ex_doc/formatter/epub/templates/module_template.eex b/lib/ex_doc/formatter/epub/templates/module_template.eex index 2639baddd..d73158afa 100644 --- a/lib/ex_doc/formatter/epub/templates/module_template.eex +++ b/lib/ex_doc/formatter/epub/templates/module_template.eex @@ -9,9 +9,9 @@ <% end %> - <%= if doc = module.rendered_doc do %> + <%= if doc = module.doc do %>
- <%= H.link_moduledoc_headings(doc) %> + <%= render_doc(doc) %>
<% end %> diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index a5700b789..d9a75f932 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -32,6 +32,7 @@ defmodule ExDoc.Formatter.HTML do tasks: filter_list(:task, project_nodes) } + # TODO: api reference should not be treated as an extra extras = if config.api_reference do [build_api_reference(nodes_map, config) | extras] @@ -125,8 +126,8 @@ defmodule ExDoc.Formatter.HTML do do: node defp render_doc(%{doc: doc} = node, language, autolink_opts, opts) do - rendered = autolink_and_render(doc, language, autolink_opts, opts) - %{node | rendered_doc: rendered} + doc = autolink_and_highlight(doc, language, autolink_opts, opts) + %{node | doc: doc, rendered_doc: ExDoc.DocAST.to_string(doc)} end defp id(%{id: mod_id}, %{id: "c:" <> id}) do @@ -141,11 +142,10 @@ defmodule ExDoc.Formatter.HTML do mod_id <> "." <> id end - defp autolink_and_render(doc, language, autolink_opts, opts) do + defp autolink_and_highlight(doc, language, autolink_opts, opts) do doc |> language.autolink_doc(autolink_opts) |> ExDoc.DocAST.highlight(language, opts) - |> ExDoc.DocAST.to_string() end defp output_setup(build, config) do @@ -314,13 +314,13 @@ defmodule ExDoc.Formatter.HTML do ~s{API Reference #{config.project} v#{config.version}} %{ - content: api_reference, group: nil, id: "api-reference", source_path: nil, source_url: config.source_url, title: "API Reference", title_content: title_content, + content: api_reference, headers: if(nodes_map.modules != [], do: [{:h2, "Modules", "modules"}], else: []) ++ if(nodes_map.tasks != [], do: [{:h2, "Mix Tasks", "mix-tasks"}], else: []) @@ -425,6 +425,7 @@ defmodule ExDoc.Formatter.HTML do |> Markdown.to_ast(opts) |> ExDoc.DocAST.add_ids_to_headers([:h2, :h3]) |> sectionize(extension) + |> autolink_and_highlight(language, [file: input] ++ autolink_opts, opts) {source, ast} @@ -441,7 +442,6 @@ defmodule ExDoc.Formatter.HTML do title_text = title_ast && ExDoc.DocAST.text(title_ast) title_html = title_ast && ExDoc.DocAST.to_string(title_ast) - content_html = autolink_and_render(ast, language, [file: input] ++ autolink_opts, opts) group = GroupMatcher.match_extra(groups, input) title = input_options[:title] || title_text || filename_to_title(input) @@ -454,13 +454,13 @@ defmodule ExDoc.Formatter.HTML do source: source, group: group, id: id, + doc: ast, source_path: source_path, source_url: source_url, search_data: search_data, title: title, title_content: title_html || title, - # TODO: Remove these fields but first we would need to make API reference return DocAST - content: content_html, + # Remove this field when API reference is no longer treated as an extra headers: ExDoc.DocAST.extract_headers_with_ids(ast, [:h2]) } end diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index 8d4d146a5..e8bd2183d 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -172,94 +172,49 @@ defmodule ExDoc.Formatter.HTML.Templates do defp sidebar_type(:livemd), do: "extras" defp sidebar_type(:extra), do: "extras" - # TODO: Adding the link headings must be done via DocAST instead of using regexes. + @section_header_class_name "section-heading" @doc """ - Add link headings for the given `content`. + Renders the document in the page. - IDs are prefixed with `prefix`. - - We only link `h2` and `h3` headers. This is kept consistent in ExDoc.SearchData. + For now it enriches the document by adding fancy anchors + around h2 and h3 tags with IDs. """ - @spec link_headings(String.t() | nil, String.t()) :: String.t() | nil - def link_headings(content, prefix \\ "") - def link_headings(nil, _), do: nil - - def link_headings(content, prefix) do - ~r/<(h[23]).*?>(.*?)<\/\1>/m - |> Regex.scan(content) - |> Enum.reduce({content, %{}}, fn [match, tag, title], {content, occurrences} -> - possible_id = title |> ExDoc.Utils.strip_tags() |> text_to_id() - id_occurred = Map.get(occurrences, possible_id, 0) - - anchor_id = if id_occurred >= 1, do: "#{possible_id}-#{id_occurred}", else: possible_id - replacement = link_heading(match, tag, title, anchor_id, prefix) - linked_content = String.replace(content, match, replacement, global: false) - incremented_occs = Map.put(occurrences, possible_id, id_occurred + 1) - {linked_content, incremented_occs} - end) - |> elem(0) - end - - @class_separator " " - defp link_heading(match, _tag, _title, "", _prefix), do: match - - defp link_heading(match, tag, title, id, prefix) do - section_header_class_name = "section-heading" - - # NOTE: This addition is mainly to preserve the previous `class` attributes - # from the headers, in case there is one. Now with the _admonition_ text - # block, we inject CSS classes. So far, the supported classes are: - # `warning`, `info`, `error`, and `neutral`. - # - # The Markdown syntax that we support for the admonition text - # blocks is something like this: - # - # > ### Never open this door! {: .warning} - # > - # > ... - # - # That should produce the following HTML: - # - #
- #

Never open this door!

- #

...

- #
- # - # The original implementation discarded the previous CSS classes. Instead, - # it was setting `#{section_header_class_name}` as the only CSS class - # associated with the given header. - class_attribute = - case Regex.named_captures(~r/[^"]+)")?.*?>/, match) do - %{"class" => ""} -> - section_header_class_name - - %{"class" => previous_classes} -> - # Let's make sure that the `section_header_class_name` is not already - # included in the previous classes for the header - previous_classes - |> String.split(@class_separator) - |> Enum.reject(&(&1 == section_header_class_name)) - |> Enum.join(@class_separator) - |> Kernel.<>(" #{section_header_class_name}") - end - - """ - <#{tag} id="#{prefix}#{id}" class="#{class_attribute}"> - - - - #{title} - - """ - end + def render_doc(nil), do: "" - def link_moduledoc_headings(content) do - link_headings(content, "module-") + def render_doc(ast) do + ast + |> add_fancy_anchors() + |> ExDoc.DocAST.to_string() end - def link_detail_headings(content, prefix) do - link_headings(content, prefix <> "-") + defp add_fancy_anchors(ast) do + ExDoc.DocAST.map_tags(ast, fn + {tag, attrs, inner, meta} = ast when tag in [:h2, :h3] -> + if id = Keyword.get(attrs, :id) do + attrs = + Keyword.update( + attrs, + :class, + @section_header_class_name, + &(&1 <> " " <> @section_header_class_name) + ) + + {tag, attrs, + [ + {:a, [href: "##{id}", class: "hover-link"], + [ + {:i, [class: "ri-link-m", "aria-hidden": "true"], [], %{}} + ], %{}}, + {:span, [class: "text"], inner, %{}} + ], meta} + else + ast + end + + ast -> + ast + end) end templates = [ diff --git a/lib/ex_doc/formatter/html/templates/detail_template.eex b/lib/ex_doc/formatter/html/templates/detail_template.eex index 3b5ec916e..8e76a962d 100644 --- a/lib/ex_doc/formatter/html/templates/detail_template.eex +++ b/lib/ex_doc/formatter/html/templates/detail_template.eex @@ -33,6 +33,6 @@ <% end %> - <%= link_detail_headings(node.rendered_doc, enc(node.id)) %> + <%= render_doc(node.doc) %>
diff --git a/lib/ex_doc/formatter/html/templates/extra_template.eex b/lib/ex_doc/formatter/html/templates/extra_template.eex index 43f9a287c..5c227876b 100644 --- a/lib/ex_doc/formatter/html/templates/extra_template.eex +++ b/lib/ex_doc/formatter/html/templates/extra_template.eex @@ -26,7 +26,7 @@ <% end %> - <%= link_headings(node.content) %> + <%= node[:content] || render_doc(node.doc) %>
diff --git a/lib/ex_doc/formatter/html/templates/module_template.eex b/lib/ex_doc/formatter/html/templates/module_template.eex index e14af45bf..d25a932d4 100644 --- a/lib/ex_doc/formatter/html/templates/module_template.eex +++ b/lib/ex_doc/formatter/html/templates/module_template.eex @@ -24,9 +24,9 @@
<% end %> - <%= if doc = module.rendered_doc do %> + <%= if doc = module.doc do %>
- <%= link_moduledoc_headings(doc) %> + <%= render_doc(doc) %>
<% end %> diff --git a/lib/ex_doc/retriever.ex b/lib/ex_doc/retriever.ex index 5c11ca385..35861f79d 100644 --- a/lib/ex_doc/retriever.ex +++ b/lib/ex_doc/retriever.ex @@ -177,7 +177,7 @@ defmodule ExDoc.Retriever do nil end - # TODO: Consider perhaps moving auto-linking here. + # TODO: Consider moving auto-linking here. defp normalize_doc_ast(doc_ast, prefix) do doc_ast |> DocAST.add_ids_to_headers([:h2, :h3], prefix) diff --git a/test/ex_doc/formatter/epub/templates_test.exs b/test/ex_doc/formatter/epub/templates_test.exs index 724ea3400..e3937269a 100644 --- a/test/ex_doc/formatter/epub/templates_test.exs +++ b/test/ex_doc/formatter/epub/templates_test.exs @@ -108,10 +108,10 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do assert content =~ ~s{

Summary

} assert content =~ - ~r{

.*Example.*

}ms + ~r{

.*Example.*

}ms assert content =~ - ~r{

.*Example H3 heading.*

}ms + ~r{

.*Example H3 heading.*

}ms assert content =~ ~r{moduledoc.*Example.*CompiledWithDocs\.example.*}ms diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index dabfed5f7..419b2e3c9 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -41,123 +41,31 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do :ok end - describe "link_headings" do - test "generates headers with hovers" do - assert Templates.link_headings("

Foo

Bar

") == """ -

- - - - Foo -

-

- - - - Bar -

- """ - - assert Templates.link_headings("

Foo

\n

Bar

") == """ -

- - - - Foo -

- -

- - - - Bar -

- """ + describe "render_doc" do + test "adds fancy anchors around ids" do + assert """ + ## Foo - assert Templates.link_headings("

Bar

") == """ -

- - - - Bar -

+ ### Bar {:class=wrap} """ - - assert Templates.link_headings("

\n

Bar

") == """ -

-

- - - - Bar -

- """ - - assert Templates.link_headings("

Foo

") == - String.trim_trailing(""" + |> ExDoc.DocAST.parse!("text/markdown") + |> ExDoc.DocAST.add_ids_to_headers([:h2, :h3]) + |> Templates.render_doc() == + """

Foo

-

- """) - - assert Templates.link_headings("

Foo

\n

") == - String.trim_trailing(""" -

- +

+ - Foo -

- -

- """) - - assert Templates.link_headings("

Foo

") == """ -

- - - - Foo -

- """ - end - - test "generates headers with unique id's" do - assert Templates.link_headings("

Foo

\n

Foo

") == """ -

- - - - Foo -

- -

- - - - Foo -

- """ - end - - test "generates headers for admonition support" do - admonition_block = """ -

Foo

- """ - - assert Templates.link_headings(admonition_block) == """ -

- - - - Foo -

-
- """ + Bar + + """ + |> String.replace(~r/\n\s*/, "") end end From 3aa792ba783df194165a041fcea254348ce7153b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 14:07:57 +0200 Subject: [PATCH 10/17] Remove unused extract_headers --- lib/ex_doc/doc_ast.ex | 13 ------------- test/ex_doc/doc_ast_test.exs | 25 ------------------------- 2 files changed, 38 deletions(-) diff --git a/lib/ex_doc/doc_ast.ex b/lib/ex_doc/doc_ast.ex index 81586ded7..be7c67af3 100644 --- a/lib/ex_doc/doc_ast.ex +++ b/lib/ex_doc/doc_ast.ex @@ -109,19 +109,6 @@ defmodule ExDoc.DocAST do def extract_title([{:h1, _attrs, inner, _meta} | ast]), do: {:ok, inner, ast} def extract_title(_ast), do: :error - @doc """ - Extracts headers (h2) from the given AST. - - Returns the header text. - """ - def extract_headers(doc_ast, headers) do - for {tag, _, _, _} = node <- doc_ast, - tag in headers, - text = ExDoc.DocAST.text(node), - text != "", - do: text - end - @doc """ Extracts the headers which have anchors (aka ids) in them. """ diff --git a/test/ex_doc/doc_ast_test.exs b/test/ex_doc/doc_ast_test.exs index a892e871f..abbf54d0c 100644 --- a/test/ex_doc/doc_ast_test.exs +++ b/test/ex_doc/doc_ast_test.exs @@ -131,31 +131,6 @@ defmodule ExDoc.DocASTTest do end end - describe "extract_headers" do - test "extracts h2 headers" do - assert extract_headers(""" - # h1 - ## h2-a - ### h3 - ## h2-b - ## - """) == ["h2-a", "h2-b"] - end - - test "trims whitespace and preserve HTML entities" do - assert extract_headers(""" - # h1 - ##\s\s\s**h2**\s<&>\s`h2`\s\s\s - """) == ["h2 <&> h2"] - end - - defp extract_headers(markdown) do - markdown - |> DocAST.parse!("text/markdown") - |> DocAST.extract_headers([:h2]) - end - end - describe "headers" do test "adds and extracts anchored headers" do assert """ From f65d2fff9b6950e996540aae510f8b4813691285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 14:18:29 +0200 Subject: [PATCH 11/17] Remove cheatsheets from epub, perform sectionize later --- lib/ex_doc/formatter/epub.ex | 2 +- lib/ex_doc/formatter/html.ex | 14 ++++---------- .../formatter/html/templates/extra_template.eex | 6 +++++- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/ex_doc/formatter/epub.ex b/lib/ex_doc/formatter/epub.ex index 84d89e0b3..6d0a6b9b4 100644 --- a/lib/ex_doc/formatter/epub.ex +++ b/lib/ex_doc/formatter/epub.ex @@ -63,7 +63,7 @@ defmodule ExDoc.Formatter.EPUB do defp generate_extras(config) do for {_title, extras} <- config.extras, node <- extras, - not is_map_key(node, :url) do + not is_map_key(node, :url) and node.extension != ".cheatmd" do output = "#{config.output}/OEBPS/#{node.id}.xhtml" html = Templates.extra_template(config, node) diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index d9a75f932..91934354b 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -410,12 +410,12 @@ defmodule ExDoc.Formatter.HTML do source_file = input_options[:source] || input opts = [file: source_file, line: 1] - {source, ast} = + {extension, source, ast} = case extension_name(input) do extension when extension in ["", ".txt"] -> source = File.read!(input) ast = [{:pre, [], ["\n" <> source], %{}}] - {source, ast} + {extension, source, ast} extension when extension in [".md", ".livemd", ".cheatmd"] -> source = File.read!(input) @@ -424,10 +424,9 @@ defmodule ExDoc.Formatter.HTML do source |> Markdown.to_ast(opts) |> ExDoc.DocAST.add_ids_to_headers([:h2, :h3]) - |> sectionize(extension) |> autolink_and_highlight(language, [file: input] ++ autolink_opts, opts) - {source, ast} + {extension, source, ast} _ -> raise ArgumentError, @@ -451,6 +450,7 @@ defmodule ExDoc.Formatter.HTML do search_data = normalize_search_data!(input_options[:search_data]) %{ + extension: extension, source: source, group: group, id: id, @@ -491,12 +491,6 @@ defmodule ExDoc.Formatter.HTML do |> String.downcase() end - defp sectionize(ast, ".cheatmd") do - ExDoc.DocAST.sectionize(ast, [:h2, :h3]) - end - - defp sectionize(ast, _), do: ast - defp filename_to_title(input) do input |> Path.basename() |> Path.rootname() end diff --git a/lib/ex_doc/formatter/html/templates/extra_template.eex b/lib/ex_doc/formatter/html/templates/extra_template.eex index 5c227876b..805a44307 100644 --- a/lib/ex_doc/formatter/html/templates/extra_template.eex +++ b/lib/ex_doc/formatter/html/templates/extra_template.eex @@ -26,7 +26,11 @@ <% end %> - <%= node[:content] || render_doc(node.doc) %> + <%= if type == :cheatmd do %> + <%= node.doc |> ExDoc.DocAST.sectionize([:h2, :h3]) |> render_doc() %> + <% else %> + <%= node[:content] || render_doc(node.doc) %> + <% end %>
From 81b55edceb77924e49e67466e9a105c2aa1154ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 15:08:39 +0200 Subject: [PATCH 12/17] Decouple api reference from extras --- lib/ex_doc/formatter/epub.ex | 2 +- lib/ex_doc/formatter/html.ex | 54 +++++++----------- lib/ex_doc/formatter/html/templates.ex | 53 +++++++++-------- .../html/templates/api_reference_template.eex | 57 ++++++++++++------- .../html/templates/extra_template.eex | 10 ++-- .../html/templates/footer_template.eex | 2 +- .../html/templates/module_template.eex | 2 +- test/ex_doc/formatter/html/templates_test.exs | 38 +++++++++---- test/ex_doc/formatter/html_test.exs | 7 ++- 9 files changed, 126 insertions(+), 99 deletions(-) diff --git a/lib/ex_doc/formatter/epub.ex b/lib/ex_doc/formatter/epub.ex index 6d0a6b9b4..1c8f0f1e8 100644 --- a/lib/ex_doc/formatter/epub.ex +++ b/lib/ex_doc/formatter/epub.ex @@ -63,7 +63,7 @@ defmodule ExDoc.Formatter.EPUB do defp generate_extras(config) do for {_title, extras} <- config.extras, node <- extras, - not is_map_key(node, :url) and node.extension != ".cheatmd" do + not is_map_key(node, :url) and node.type != :cheatmd do output = "#{config.output}/OEBPS/#{node.id}.xhtml" html = Templates.extra_template(config, node) diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 91934354b..78f38a108 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -32,18 +32,11 @@ defmodule ExDoc.Formatter.HTML do tasks: filter_list(:task, project_nodes) } - # TODO: api reference should not be treated as an extra - extras = - if config.api_reference do - [build_api_reference(nodes_map, config) | extras] - else - extras - end - all_files = search_data ++ static_files ++ generate_sidebar_items(nodes_map, extras, config) ++ + generate_api_reference(nodes_map, config) ++ generate_extras(extras, config) ++ generate_favicon(@assets_dir, config) ++ generate_logo(@assets_dir, config) ++ @@ -185,7 +178,7 @@ defmodule ExDoc.Formatter.HTML do end defp generate_sidebar_items(nodes_map, extras, config) do - content = Templates.create_sidebar_items(nodes_map, extras) + content = Templates.create_sidebar_items(config, nodes_map, extras) path = "dist/sidebar_items-#{digest(content)}.js" File.write!(Path.join(config.output, path), content) @@ -221,8 +214,7 @@ defmodule ExDoc.Formatter.HTML do next: next && %{path: "#{next.id}.html", title: next.title} } - extension = node.source_path && Path.extname(node.source_path) - html = Templates.extra_template(config, node, extra_type(extension), refs) + html = Templates.extra_template(config, node, refs) if File.regular?(output) do Utils.warn("file #{Path.relative_to_cwd(output)} already exists", []) @@ -307,24 +299,23 @@ defmodule ExDoc.Formatter.HTML do ] end - defp build_api_reference(nodes_map, config) do - api_reference = Templates.api_reference_template(nodes_map) + defp generate_api_reference(_nodes_map, %{api_reference: false}) do + [] + end - title_content = - ~s{API Reference #{config.project} v#{config.version}} + defp generate_api_reference(nodes_map, config) do + filename = "api-reference.html" + output = "#{config.output}/#{filename}" + config = set_canonical_url(config, filename) - %{ - group: nil, - id: "api-reference", - source_path: nil, - source_url: config.source_url, - title: "API Reference", - title_content: title_content, - content: api_reference, - headers: - if(nodes_map.modules != [], do: [{:h2, "Modules", "modules"}], else: []) ++ - if(nodes_map.tasks != [], do: [{:h2, "Mix Tasks", "mix-tasks"}], else: []) - } + html = Templates.api_reference_template(config, nodes_map) + + if File.regular?(output) do + Utils.warn("file #{Path.relative_to_cwd(output)} already exists", []) + end + + File.write!(output, html) + [filename] end @doc """ @@ -441,16 +432,15 @@ defmodule ExDoc.Formatter.HTML do title_text = title_ast && ExDoc.DocAST.text(title_ast) title_html = title_ast && ExDoc.DocAST.to_string(title_ast) - - group = GroupMatcher.match_extra(groups, input) title = input_options[:title] || title_text || filename_to_title(input) + group = GroupMatcher.match_extra(groups, input) source_path = source_file |> Path.relative_to(File.cwd!()) |> String.replace_leading("./", "") source_url = source_url_pattern.(source_path, 1) search_data = normalize_search_data!(input_options[:search_data]) %{ - extension: extension, + type: extra_type(extension), source: source, group: group, id: id, @@ -459,9 +449,7 @@ defmodule ExDoc.Formatter.HTML do source_url: source_url, search_data: search_data, title: title, - title_content: title_html || title, - # Remove this field when API reference is no longer treated as an extra - headers: ExDoc.DocAST.extract_headers_with_ids(ast, [:h2]) + title_content: title_html || title } end diff --git a/lib/ex_doc/formatter/html/templates.ex b/lib/ex_doc/formatter/html/templates.ex index e8bd2183d..73609f982 100644 --- a/lib/ex_doc/formatter/html/templates.ex +++ b/lib/ex_doc/formatter/html/templates.ex @@ -46,16 +46,26 @@ defmodule ExDoc.Formatter.HTML.Templates do @doc """ Create a JS object which holds all the items displayed in the sidebar area """ - def create_sidebar_items(nodes_map, extras) do + def create_sidebar_items(config, nodes_map, extras) do nodes = nodes_map |> Enum.map(&sidebar_module/1) |> Map.new() - |> Map.put(:extras, sidebar_extras(extras)) + |> Map.put(:extras, api_reference(config, nodes_map) ++ sidebar_extras(extras)) ["sidebarNodes=" | ExDoc.Utils.to_json(nodes)] end + defp api_reference(%{api_reference: false}, _nodes_map), do: [] + + defp api_reference(_config, nodes_map) do + headers = + if(nodes_map.modules != [], do: [%{id: "Modules", anchor: "modules"}], else: []) ++ + if(nodes_map.tasks != [], do: [%{id: "Mix Tasks", anchor: "mix-tasks"}], else: []) + + [%{id: "api-reference", title: "API Reference", group: "", headers: headers}] + end + defp sidebar_extras(extras) do for extra <- extras do %{id: id, title: title, group: group} = extra @@ -73,14 +83,14 @@ defmodule ExDoc.Formatter.HTML.Templates do end) item - |> Map.put(:headers, headers_to_id_and_anchors(extra.headers)) + |> Map.put(:headers, headers(extra.doc)) |> Map.put(:searchData, search_data) %{url: url} when is_binary(url) -> Map.put(item, :url, url) _ -> - Map.put(item, :headers, headers_to_id_and_anchors(extra.headers)) + Map.put(item, :headers, headers(extra.doc)) end end end @@ -88,7 +98,7 @@ defmodule ExDoc.Formatter.HTML.Templates do defp sidebar_module({id, modules}) do modules = for module <- modules do - extra = + groups = module |> module_summary() |> case do @@ -96,18 +106,18 @@ defmodule ExDoc.Formatter.HTML.Templates do entries -> [nodeGroups: Enum.map(entries, &sidebar_entries/1)] end - sections = module_sections(module) - - deprecated? = not is_nil(module.deprecated) - pairs = for key <- [:id, :title, :nested_title, :nested_context], value = Map.get(module, key), do: {key, value} - pairs = [{:deprecated, deprecated?} | pairs] + others = [ + deprecated: not is_nil(module.deprecated), + sections: headers(module.doc || []), + group: to_string(module.group) + ] - Map.new([group: to_string(module.group)] ++ extra ++ pairs ++ sections) + Map.new(groups ++ pairs ++ others) end {id, modules} @@ -135,17 +145,10 @@ defmodule ExDoc.Formatter.HTML.Templates do %{key: text_to_id(group), name: group, nodes: nodes} end - defp module_sections(module) do - sections = - (module.doc || []) - |> ExDoc.DocAST.extract_headers_with_ids([:h2]) - |> headers_to_id_and_anchors() - - [sections: sections] - end - - defp headers_to_id_and_anchors(headers) do - Enum.map(headers, fn {:h2, text, anchor} -> + defp headers(doc) do + doc + |> ExDoc.DocAST.extract_headers_with_ids([:h2]) + |> Enum.map(fn {:h2, text, anchor} -> %{id: text, anchor: anchor} end) end @@ -219,13 +222,13 @@ defmodule ExDoc.Formatter.HTML.Templates do templates = [ detail_template: [:node, :module], - footer_template: [:config, :node], + footer_template: [:config, :source_path], head_template: [:config, :title, :noindex], module_template: [:config, :module, :summary], not_found_template: [:config], api_reference_entry_template: [:module_node], - api_reference_template: [:nodes_map], - extra_template: [:config, :node, :type, :refs], + api_reference_template: [:config, :nodes_map], + extra_template: [:config, :node, :refs], search_template: [:config], sidebar_template: [:config, :type], summary_template: [:name, :nodes], diff --git a/lib/ex_doc/formatter/html/templates/api_reference_template.eex b/lib/ex_doc/formatter/html/templates/api_reference_template.eex index 523a28964..90b6b049f 100644 --- a/lib/ex_doc/formatter/html/templates/api_reference_template.eex +++ b/lib/ex_doc/formatter/html/templates/api_reference_template.eex @@ -1,21 +1,38 @@ -<%= if nodes_map.modules != [] do %> -
-

Modules

-
- <%= for module_node <- Enum.sort_by(nodes_map.modules, & &1.id) do - api_reference_entry_template(module_node) - end %> -
-
-<% end %> +<%= head_template(config, "API Reference", false) %> +<%= sidebar_template(config, :extra) %> -<%= if nodes_map.tasks != [] do %> -
-

Mix Tasks

-
- <%= for task_node <- nodes_map.tasks do - api_reference_entry_template(task_node) - end %> -
-
-<% end %> +
+
+

API Reference <%= config.project %> v#<%= config.version %>

+ <%= if config.source_url do %> + + + View Source + + <% end %> +
+ + <%= if nodes_map.modules != [] do %> +
+

Modules

+
+ <%= for module_node <- Enum.sort_by(nodes_map.modules, & &1.id) do + api_reference_entry_template(module_node) + end %> +
+
+ <% end %> + + <%= if nodes_map.tasks != [] do %> +
+

Mix Tasks

+
+ <%= for task_node <- nodes_map.tasks do + api_reference_entry_template(task_node) + end %> +
+
+ <% end %> +
+ +<%= footer_template(config, nil) %> \ No newline at end of file diff --git a/lib/ex_doc/formatter/html/templates/extra_template.eex b/lib/ex_doc/formatter/html/templates/extra_template.eex index 805a44307..4d32afbe1 100644 --- a/lib/ex_doc/formatter/html/templates/extra_template.eex +++ b/lib/ex_doc/formatter/html/templates/extra_template.eex @@ -1,10 +1,10 @@ <%= head_template(config, node.title, false) %> -<%= sidebar_template(config, type) %> +<%= sidebar_template(config, node.type) %>

<%= node.title_content %>

- <%= if type == :cheatmd do %> + <%= if node.type == :cheatmd do %>
- <%= if type == :livemd do %> + <%= if node.type == :livemd do %> <% end %> - <%= if type == :cheatmd do %> + <%= if node.type == :cheatmd do %> <%= node.doc |> ExDoc.DocAST.sectionize([:h2, :h3]) |> render_doc() %> <% else %> <%= node[:content] || render_doc(node.doc) %> @@ -60,4 +60,4 @@
-<%= footer_template(config, node) %> +<%= footer_template(config, node.source_path) %> diff --git a/lib/ex_doc/formatter/html/templates/footer_template.eex b/lib/ex_doc/formatter/html/templates/footer_template.eex index 5488a0212..8d6d1b4e5 100644 --- a/lib/ex_doc/formatter/html/templates/footer_template.eex +++ b/lib/ex_doc/formatter/html/templates/footer_template.eex @@ -6,7 +6,7 @@ Hex Preview - <%= source_path = node && Map.get(node, :source_path); if source_path do %> + <%= if source_path do %> (current file) <% end %> diff --git a/lib/ex_doc/formatter/html/templates/module_template.eex b/lib/ex_doc/formatter/html/templates/module_template.eex index d25a932d4..6990304ec 100644 --- a/lib/ex_doc/formatter/html/templates/module_template.eex +++ b/lib/ex_doc/formatter/html/templates/module_template.eex @@ -57,4 +57,4 @@ <% end %> -<%= footer_template(config, module) %> +<%= footer_template(config, module.source_path) %> diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index 419b2e3c9..4beff1e48 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -117,6 +117,23 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do Templates.footer_template(doc_config(context), nil) end + test "includes api reference", context do + names = [CompiledWithDocs] + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) + all = %{modules: nodes, tasks: []} + + assert [ + %{ + "group" => "", + "headers" => [%{"anchor" => "modules", "id" => "Modules"}], + "id" => "api-reference", + "title" => "API Reference" + } + ] = create_sidebar_items(%{api_reference: true}, all, [])["extras"] + + assert [] = create_sidebar_items(%{api_reference: false}, all, [])["extras"] + end + test "outputs listing for the given nodes", context do names = [CompiledWithDocs, CompiledWithDocs.Nested] {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) @@ -143,7 +160,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do ] }, %{"id" => "CompiledWithDocs.Nested"} - ] = create_sidebar_items(%{modules: nodes}, [])["modules"] + ] = create_sidebar_items(%{}, %{modules: nodes, tasks: []}, [])["modules"] end test "outputs deprecated: true if node is deprecated", context do @@ -151,7 +168,9 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) path = ["modules", Access.at!(0), "nodeGroups", Access.at!(0), "nodes"] - sidebar_functions = get_in(create_sidebar_items(%{modules: nodes}, []), path) + + sidebar_functions = + get_in(create_sidebar_items(%{}, %{modules: nodes, tasks: []}, []), path) assert Enum.any?( sidebar_functions, @@ -164,7 +183,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) assert Enum.any?( - create_sidebar_items(%{modules: nodes}, [])["modules"], + create_sidebar_items(%{}, %{modules: nodes, tasks: []}, [])["modules"], &match?(%{"title" => "Warnings", "deprecated" => true}, &1) ) end @@ -214,7 +233,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do ] }, %{"id" => "CompiledWithDocs.Nested"} - ] = create_sidebar_items(%{modules: nodes}, [])["modules"] + ] = create_sidebar_items(%{}, %{modules: nodes, tasks: []}, [])["modules"] end test "outputs module groups for the given nodes", context do @@ -229,17 +248,16 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do "id" => "CompiledWithDocs", "title" => "CompiledWithDocs" } - ] = create_sidebar_items(%{modules: nodes}, [])["modules"] + ] = create_sidebar_items(%{}, %{modules: nodes, tasks: []}, [])["modules"] end test "builds sections out of moduledocs", context do names = [CompiledWithDocs, CompiledWithoutDocs, DuplicateHeadings] config = doc_config(context) {nodes, []} = ExDoc.Retriever.docs_from_modules(names, config) - nodes = HTML.render_all(nodes, [], ".html", config, []) [compiled_with_docs, compiled_without_docs, duplicate_headings] = - create_sidebar_items(%{modules: nodes}, [])["modules"] + create_sidebar_items(%{}, %{modules: nodes, tasks: []}, [])["modules"] assert compiled_with_docs["sections"] == [ %{ @@ -260,10 +278,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do ] end - defp create_sidebar_items(nodes_map, extras) do + defp create_sidebar_items(config, nodes_map, extras) do "sidebarNodes=" <> content = - nodes_map - |> Templates.create_sidebar_items(extras) + config + |> Templates.create_sidebar_items(nodes_map, extras) |> IO.iodata_to_binary() Jason.decode!(content) diff --git a/test/ex_doc/formatter/html_test.exs b/test/ex_doc/formatter/html_test.exs index 15e928ab9..0f3e7b05c 100644 --- a/test/ex_doc/formatter/html_test.exs +++ b/test/ex_doc/formatter/html_test.exs @@ -854,15 +854,16 @@ defmodule ExDoc.Formatter.HTMLTest do generate_docs( doc_config(context, extras: [ + "test/fixtures/ExtraPage.md", "test/fixtures/LICENSE", "test/fixtures/README.md" ] ) ) - # We have three extras: API Reference, LICENSE and README + # We have three extras: Extra Page, LICENSE and README - content_first = File.read!(tmp_dir <> "/html/api-reference.html") + content_first = File.read!(tmp_dir <> "/html/extrapage.html") refute content_first =~ ~r{Previous Page} @@ -872,7 +873,7 @@ defmodule ExDoc.Formatter.HTMLTest do content_middle = File.read!(tmp_dir <> "/html/license.html") assert content_middle =~ - ~r{} + ~r{} assert content_middle =~ ~r{} From 62246912310deb38d497c28d5de045b8342bef76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 8 May 2025 15:11:37 +0200 Subject: [PATCH 13/17] Renaming --- .../formatter/epub/templates/extra_template.eex | 4 +--- lib/ex_doc/formatter/html.ex | 11 ++++------- .../formatter/html/templates/extra_template.eex | 2 +- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/ex_doc/formatter/epub/templates/extra_template.eex b/lib/ex_doc/formatter/epub/templates/extra_template.eex index 0ad9b52f2..87f63cc58 100644 --- a/lib/ex_doc/formatter/epub/templates/extra_template.eex +++ b/lib/ex_doc/formatter/epub/templates/extra_template.eex @@ -1,7 +1,5 @@ <%= head_template(config, node.title) %> -

- <%=h node.title_content %> -

+

<%= ExDoc.DocAST.to_string(node.title_doc) %>

<%= render_doc(node.doc) %> <%= before_closing_body_tag(config, :epub) %> diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 78f38a108..2ec435bd5 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -424,16 +424,13 @@ defmodule ExDoc.Formatter.HTML do "file extension not recognized, allowed extension is either .cheatmd, .livemd, .md, .txt or no extension" end - {title_ast, ast} = + {title_doc, title_text, ast} = case ExDoc.DocAST.extract_title(ast) do - {:ok, title_ast, ast} -> {title_ast, ast} - :error -> {nil, ast} + {:ok, title_doc, ast} -> {title_doc, ExDoc.DocAST.text(title_doc), ast} + :error -> {nil, nil, ast} end - title_text = title_ast && ExDoc.DocAST.text(title_ast) - title_html = title_ast && ExDoc.DocAST.to_string(title_ast) title = input_options[:title] || title_text || filename_to_title(input) - group = GroupMatcher.match_extra(groups, input) source_path = source_file |> Path.relative_to(File.cwd!()) |> String.replace_leading("./", "") source_url = source_url_pattern.(source_path, 1) @@ -449,7 +446,7 @@ defmodule ExDoc.Formatter.HTML do source_url: source_url, search_data: search_data, title: title, - title_content: title_html || title + title_doc: title_doc || title } end diff --git a/lib/ex_doc/formatter/html/templates/extra_template.eex b/lib/ex_doc/formatter/html/templates/extra_template.eex index 4d32afbe1..8ea894ca1 100644 --- a/lib/ex_doc/formatter/html/templates/extra_template.eex +++ b/lib/ex_doc/formatter/html/templates/extra_template.eex @@ -3,7 +3,7 @@
-

<%= node.title_content %>

+

<%= ExDoc.DocAST.to_string(node.title_doc) %>

<%= if node.type == :cheatmd do %>