diff --git a/html2pdf4doc/main_fuzzer.py b/html2pdf4doc/main_fuzzer.py
index eac8b07..972627b 100644
--- a/html2pdf4doc/main_fuzzer.py
+++ b/html2pdf4doc/main_fuzzer.py
@@ -5,6 +5,7 @@
import random
import shutil
import sys
+from enum import Enum
from pathlib import Path
from subprocess import CalledProcessError, CompletedProcess, TimeoutExpired, run
from time import time
@@ -12,6 +13,7 @@
from faker import Faker
from lxml import etree, html
+from lxml.html import HtmlElement
@contextlib.contextmanager
@@ -26,37 +28,77 @@ def measure_performance(title: str) -> Iterator[None]:
print(f"{padded_name}{padded_time}s", flush=True) # noqa: T201
+def rewrite_js_path_to_local(html_text: str) -> str:
+ tree = html.fromstring(html_text)
+ for script in tree.xpath("//script[@src]"):
+ src = script.get("src")
+ if src.endswith("html2pdf4doc.min.js"):
+ script.set("src", "html2pdf4doc.min.js")
+ return str(html.tostring(tree, encoding="unicode"))
+
+
+class MutationType(str, Enum):
+ RANDOM = "random"
+ INCREMENTAL = "incremental"
+
+ @classmethod
+ def all_as_str(cls) -> List[str]:
+ return [t.value for t in cls]
+
+
+def mutate_html_content(
+ tree: HtmlElement, mutation_type: MutationType, mutation_cycle: int
+) -> None:
+ if mutation_type == MutationType.RANDOM:
+ # Pick a random element.
+ elems = tree.xpath("//p | //td")
+ if elems:
+ for _i in range(25):
+ node = random.choice(elems)
+
+ print("Mutating node:", node.tag, flush=True) # noqa: T201
+
+ n_sentences = random.randint(1, 100)
+
+ fake = Faker()
+ extra_text = fake.text(max_nb_chars=10 * n_sentences)
+
+ node.text = extra_text
+ elif mutation_type == MutationType.INCREMENTAL:
+ elems = tree.xpath('//*[@id="html2pdf4doc_mutate_this"]')
+ assert len(elems) == 1, (
+ 'Expected element with id="html2pdf4doc_mutate_this" to be found.'
+ )
+
+ filler_element = elems[0]
+ filler_element.attrib["style"] = f"height: {mutation_cycle}px;"
+ else:
+ raise AssertionError("Must not reach here.")
+
+
def mutate_and_print(
*,
path_to_input_file: str,
path_to_root: str,
path_to_failed_mutants_dir: str,
+ cycle: int,
+ mutation_type: MutationType,
strict_mode_2: bool = False,
) -> bool:
assert os.path.isfile(path_to_input_file), path_to_input_file
assert os.path.isdir(path_to_root), path_to_root
+ assert 0 <= cycle <= 1000, cycle
+
if not os.path.abspath(path_to_root):
path_to_root = os.path.abspath(path_to_root)
- text = open(path_to_input_file, encoding="utf-8").read()
+ with open(path_to_input_file, encoding="utf-8") as input_file_:
+ text = input_file_.read()
# Parse HTML into DOM
tree = html.fromstring(text)
- # Pick a random element
- elems = tree.xpath("//p | //td")
- if elems:
- for _i in range(25):
- node = random.choice(elems)
-
- print("Mutating node:", node.tag, flush=True) # noqa: T201
-
- n_sentences = random.randint(1, 100)
-
- fake = Faker()
- extra_text = fake.text(max_nb_chars=10 * n_sentences)
-
- node.text = extra_text
+ mutate_html_content(tree, mutation_type, cycle)
# Serialize back to HTML
mutated_html = etree.tostring(
@@ -87,7 +129,8 @@ def mutate_and_print(
cmd.append(path_to_print_[0])
cmd.append(path_to_print_[1])
- relative_path_to_mut_html = Path(path_to_mut_html).relative_to(path_to_root)
+ path_to_mut_dir = os.path.dirname(path_to_mut_html)
+ relative_path_to_mut_html = Path(path_to_mut_dir).relative_to(path_to_root)
path_to_mut_output = os.path.join(
path_to_failed_mutants_dir, relative_path_to_mut_html
)
@@ -165,6 +208,7 @@ def fuzz_test(
path_to_root: str,
path_to_failed_mutants_dir: str,
total_mutations: int = 20,
+ mutation_type: MutationType = MutationType.RANDOM,
strict_mode_2: bool = False,
) -> None:
success_count, failure_count = 0, 0
@@ -178,6 +222,8 @@ def fuzz_test(
path_to_input_file=path_to_input_file,
path_to_root=path_to_root,
path_to_failed_mutants_dir=path_to_failed_mutants_dir,
+ cycle=i,
+ mutation_type=mutation_type,
strict_mode_2=strict_mode_2,
)
if success:
@@ -213,6 +259,12 @@ def main() -> None:
required=True,
help="An integer between 1 and 1000",
)
+ parser.add_argument(
+ "--mutations",
+ type=str,
+ choices=MutationType.all_as_str(),
+ help="Algorithm to use for mutations.",
+ )
parser.add_argument(
"--strict",
action="store_true",
@@ -231,6 +283,8 @@ def main() -> None:
total_mutations = args.total_mutations
assert 1 <= total_mutations <= 1000, total_mutations
+ mutation_type = MutationType(args.mutations)
+
strict_mode_2 = args.strict2
fuzz_test(
@@ -238,6 +292,7 @@ def main() -> None:
path_to_root=path_to_root,
path_to_failed_mutants_dir=path_to_failed_mutants_dir,
total_mutations=total_mutations,
+ mutation_type=mutation_type,
strict_mode_2=strict_mode_2,
)
diff --git a/tests/fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html b/tests/fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html
index 317c8a2..0d22e25 100644
--- a/tests/fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html
+++ b/tests/fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html
@@ -1963,6 +1963,15 @@
html2pdf
class="content"
>
+
+
+
+
+
Table of contents
diff --git a/tests/fuzz/_incremental/30_pusher_example/case_001.html b/tests/fuzz/_incremental/30_pusher_example/case_001.html
new file mode 100644
index 0000000..95cba97
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/case_001.html
@@ -0,0 +1,513 @@
+
+
+
+
+
+
+
+
StrictDoc
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Workflow
+ Description
+
+
+
+
+ Requirements analysis and prototyping
+ Early phases of the project. Requirements are drafted out quickly. The higher-level picture and coverage of
+ all
+ topics may be more important than specific details.
+
+
+ Requirements compliance, traceability and justification
+ Demonstrating the correctness of specification, also for contractual purposes. Every aspect shall be
+ traceable.
+
+
+
+ Requirements implementation
+ Assisting software engineers in implementing requirements in source code. Making links between requirements
+ and
+ source code implementation units, e.g., files, functions, code fragments. Linking source code implementation
+ units
+ to requirements using special markers left in source code.
+
+
+ Requirements validation/verification workflow (RAIT)
+ Verifying the correctness of requirements themselves and the validity of the information they communicate.
+
+
+
+ Configuration management, change management
+ Time machine and Diff functions. Maintaining requirements baselines (v1, v1.1, v2, etc.).
+
+
+ Reporting
+ Progress reports, statistics, metrication.
+
+
+ Collaboration on requirements
+ Supporting multiple users to collaborate on a documentation tree.
+
+
+ Requirements exchange
+ Integration between distinct projects requirements trees. Example: An embedded software project has its own
+ requirements. The developers want to integrate a requirements subtree of another product that is integrated to
+ the
+ parent project as an off-the-shelf solution.
+
+
+ Formal reviews
+ Formal review of documentation. Walkthroughs, inspections. Version control of delivered documentation
+ packages.
+ Assessment of progress reports achieved.
+
+
+ Interoperability with industry standards.
+ Supporting seamless integration between a project documentation tree and applicable standards.
+ third safety line (the end of the Table)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/autogen.css b/tests/fuzz/_incremental/30_pusher_example/css/autogen.css
new file mode 100644
index 0000000..b42148e
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/autogen.css
@@ -0,0 +1,256 @@
+/* A wrapper for styling the markup generated by MarkupRenderer. */
+
+sdoc-autogen {
+ /*
+ TODO: 'display: contents;'
+ Turn this back on when the bug is fixed:
+ Selenium cannot detect text inside a container
+ with the 'display: contents;' directive
+ */
+ /* display: contents; */
+
+ /* hyphens: auto; */
+
+ --autogen-v-rhythm: calc(var(--base-rhythm, 8px) * 2);
+}
+
+sdoc-autogen a,
+sdoc-autogen a:link,
+sdoc-autogen a:visited {
+ text-decoration: underline;
+}
+
+/* Table */
+
+sdoc-autogen table {
+ border-collapse: collapse;
+ margin: var(--base-padding) 0;
+ font-size: 1rem;
+
+ /*** add scroll for wide tables */
+ /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* border: 1px solid #ccc; */
+ border: none;
+ display: block;
+ overflow-x: auto;
+ white-space: nowrap;
+}
+
+sdoc-autogen table caption {
+ font-weight: bold;
+ padding-bottom: 1rem;
+}
+
+sdoc-autogen table th {
+ background-color: var(--color-bg-main);
+}
+
+sdoc-autogen table th,
+sdoc-autogen table td {
+ padding: var(--base-rhythm) calc(var(--base-rhythm) * 1.5);
+ vertical-align: top;
+ text-align: left;
+ border: 1px solid #ccc;
+
+ /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /*** add scroll for wide tables (unset) */
+ white-space: initial;
+}
+
+/* Typography */
+
+sdoc-autogen p {
+ margin: var(--autogen-v-rhythm) 0;
+}
+
+/* blockquote */
+
+sdoc-autogen blockquote {
+ color: #666;
+ padding: .25em 0 0.25em 1rem;
+ border-left: 4px solid #ccc;
+ margin: var(--autogen-v-rhythm) 0;
+}
+
+/* pre.code */
+
+sdoc-autogen pre.code {
+ font-family: var(--code-font-family);
+
+ font-size: var(--code-font-size);
+ line-height: 2;
+ margin: var(--code-font-size) 0;
+ padding: calc(var(--code-font-size)*1)
+ calc(var(--code-font-size)*1)
+ calc(var(--code-font-size)*1)
+ calc(var(--code-font-size)*2);
+
+ overflow: auto;
+ background-color: var(--color-bg-main);
+ border: 1px solid var(--color-border);
+}
+
+/* We have to override this for the print version because the printer
+ interprets scroll-bars differently in different environments,
+ which breaks HTML2PDF.
+ Also, we need to show the whole code in its entirety.
+ */
+[html2pdf] sdoc-autogen pre.code {
+ overflow: unset;
+ white-space: pre-wrap;
+ overflow-wrap: break-word;
+}
+
+/* ``some text`` is generated into:
by docutils. */
+sdoc-autogen tt.literal {
+ position: relative;
+ padding: 0 4px;
+ font-style: normal;
+ font-family: var(--code-font-family);
+ font-size: var(--code-font-size);
+ background-color: var(--color-bg-main);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ -webkit-box-decoration-break: clone;
+ box-decoration-break: clone;
+}
+
+/* ul */
+
+sdoc-autogen ul,
+sdoc-autogen ol {
+ padding-left: 1.6em;
+ margin: var(--autogen-v-rhythm) 0;
+}
+
+/* list in table */
+sdoc-autogen td ul,
+sdoc-autogen dt ol {
+ margin: 0;
+ padding-left: 1em;
+}
+
+/* object */
+
+sdoc-autogen img,
+sdoc-autogen object {
+ width: 100%;
+ padding: 1em;
+ background: var(--color-bg-contrast);
+}
+
+/*
+ **************************
+ automatically added by RST
+ **************************
+*/
+
+div.document {
+ /* alarm style for detecting unwrapped blocks */
+ border: 1px dashed red;
+}
+
+sdoc-autogen div.document {
+ display: contents;
+ border: none;
+}
+
+/* block margins */
+
+sdoc-autogen .document > *:first-child, /* RST */
+sdoc-autogen > *:first-child {
+ margin-top: 0 !important;
+}
+
+sdoc-autogen .document > *:last-child, /* RST */
+sdoc-autogen > *:last-child {
+ margin-bottom: 0 !important;
+}
+
+/* admonition by RST */
+/* "attention", "caution", "danger", "error", "hint", "important", "note", "tip", "warning" */
+
+sdoc-autogen .admonition {
+ display: block;
+ overflow: hidden;
+ padding: 0 var(--autogen-v-rhythm);
+ border: var(--requirement-border-width, 1px) solid;
+ border-radius: var(--requirement-border-radius);
+ margin: var(--autogen-v-rhythm) 0;
+ color: var(--color-fg-main);
+}
+
+sdoc-autogen .admonition .admonition-title {
+ margin: 0;
+ padding-top: calc(0.5 * var(--base-rhythm));
+ padding-bottom: calc(0.5 * var(--base-rhythm));
+ color: currentColor;
+ font-weight: 600;
+ position: relative;
+}
+
+sdoc-autogen .admonition .admonition-title::after {
+ content: '';
+ position: absolute;
+ top: 0; bottom: 0;
+ left: calc(-1 * var(--autogen-v-rhythm));
+ right: calc(-1 * var(--autogen-v-rhythm));
+ /* background:repeating-linear-gradient(
+ -45deg,
+ rgba(255, 255, 255, .25),
+ rgba(255, 255, 255, .25) 10px,
+ rgba(255, 255, 255, .0) 10px,
+ rgba(255, 255, 255, .0) 20px
+ ); */
+ background-color: currentColor;
+ opacity: 0.1;
+}
+
+sdoc-autogen .admonition > *:not(.admonition-title) {
+ color: var(--color-fg-main);
+}
+
+sdoc-autogen .admonition.attention {
+ color: Crimson;
+}
+
+sdoc-autogen .admonition.caution {
+ color: Crimson;
+}
+
+sdoc-autogen .admonition.important {
+ color: OrangeRed;
+}
+
+sdoc-autogen .admonition.danger {
+ color: red;
+}
+
+sdoc-autogen .admonition.error {
+ color: Red;
+}
+
+sdoc-autogen .admonition.warning {
+ color: DarkOrange;
+}
+
+sdoc-autogen .admonition.warning .admonition-title::before {
+ /* content: '⚠️'; */
+ margin-right: var(--base-rhythm);
+}
+
+sdoc-autogen .admonition.note {
+ /* color: CornflowerBlue; */
+ color: SteelBlue;
+}
+
+sdoc-autogen .admonition.hint {
+ color: DarkSlateBlue;
+}
+
+sdoc-autogen .admonition.tip {
+ color: MediumSlateBlue;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/base.css b/tests/fuzz/_incremental/30_pusher_example/css/base.css
new file mode 100644
index 0000000..e8444f2
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/base.css
@@ -0,0 +1,127 @@
+/* @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+Mono:wght@400;500;600;700&family=Noto+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap'); */
+
+/* .test-content {} */
+
+:root {
+
+ --color-bg-main: #F2F5F9;
+ --color-fg-main: #444;
+
+ --color-bg-contrast: #fff;
+ --color-fg-contrast: #000;
+
+ --color-fg-accent: rgb(242, 100, 42);
+ --color-bg-accent: rgb(242 100 42 / 10%);
+
+ --color-accent: #274466;
+ --color-highlight: rgb(255, 255, 200);
+ --color-highlight-secondary: rgb(230, 236, 242);
+
+ --color-fg-secondary: rgba(0, 0, 0, .5);
+ --color-bg-secondary: rgba(0, 0, 0, .025);
+
+ --color-fg-secondary-invert: rgb(255 255 255 / 50%);
+ --color-bg-secondary-invert: rgb(0 0 0 / 10%);
+
+ --color-bg-ui: #282c42;
+
+ --color-red: rgb(200, 0, 0);
+ --color-blue: rgb(50, 100, 200);
+ --color-green: rgb(0, 100, 100);
+
+ --color-danger: var(--color-red);
+ --color-cancel: var(--color-fg-secondary);
+ --color-submit: var(--color-action);
+
+ --color-link: var(--color-fg-secondary);
+ --color-action: var(--color-fg-accent);
+ --color-hover: var(--color-fg-contrast);
+
+ --color-border: rgba(0,0,0,.1);
+ --color-placeholder: rgba(0,0,0,.25);
+
+ --base-border: 1px solid var(--color-border);
+ --code-border-color: var(--color-border);
+
+ --scrollbarBG: transparent;
+ --thumbBG: rgba(0,0,0,.05);
+
+ --base-rhythm: 8px;
+
+ --base-font-size: calc(var(--base-rhythm)*2);
+ --base-line-height: 1.6;
+
+ --font-size: var(--base-font-size);
+
+ --font-size-l: 1.25rem;
+ --font-size-sm: 0.8125rem;
+ --font-size-xsm: 0.75rem;
+ --font-size-xxsm: 11px;
+ --code-font-size: .85em;
+
+ /* --base-font-family: 'Noto Sans', sans-serif; */
+ /* --code-font-family: 'Noto Sans Mono', consolas, monaco, monospace; */
+ /*
+ DEV NOTE: To use system fonts,
+ uncomment the following two variables, replacing the previous two:
+ */
+ --base-font-family: ui-sans-serif, system-ui, -apple-system, "system-ui", "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ --code-font-family: monospace;
+
+ --base-gap: calc(var(--base-rhythm)*6);
+ --tree-gap: calc(var(--base-rhythm)*4);
+ --base-padding: calc(var(--base-rhythm)*2);
+
+ --base-elevation-0: 0 0 0 rgba(0,0,0,0);
+ --base-elevation-node: 0 0 16px rgba(0,0,0,.1);
+ --base-elevation-modal: 0 0 32px rgba(0,0,0,.32);
+
+ --main-elevation-shadow: inset 8px 8px 16px rgba(0,0,0,.2);
+ --base-elevation: 0 0 16px rgba(0,0,0,.2);
+
+ --traceability-arrow: 1.25rem;
+
+ --card-width: 300px;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+
+ font-family: var(--base-font-family);
+ font-size: var(--base-font-size);
+ line-height: var(--base-line-height);
+ color: var(--color-fg-main);
+ background-color: var(--color-bg-main);
+}
+
+* { box-sizing: border-box; }
+
+sdoc-scope {
+ display: contents;
+}
+
+/* scrollbar */
+
+* {
+ scrollbar-color: var(--thumbBG) var(--scrollbarBG);
+}
+::-webkit-scrollbar:horizontal,
+::-webkit-scrollbar:vertical,
+::-webkit-scrollbar,
+::-webkit-scrollbar-track:horizontal,
+::-webkit-scrollbar-track:vertical,
+::-webkit-scrollbar-track,
+::-webkit-scrollbar-corner {
+ background-color: var(--scrollbarBG);
+}
+::-webkit-scrollbar-thumb:horizontal,
+::-webkit-scrollbar-thumb:vertical,
+::-webkit-scrollbar-thumb {
+ background-color: var(--thumbBG)
+ /*
+ background-color: var(--scrollbarBG);
+ border: 3px solid var(--thumbBG);
+ border-radius: 6px;
+ */
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/content.css b/tests/fuzz/_incremental/30_pusher_example/css/content.css
new file mode 100644
index 0000000..596cf49
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/content.css
@@ -0,0 +1,203 @@
+/* .main */
+
+.main {
+ position: relative;
+ overflow: auto;
+ scroll-behavior: smooth;
+ scrollbar-gutter: stable both-edges;
+ padding: var(--base-gap) /* == calc(var(--base-rhythm)*6) */
+ calc(var(--base-rhythm)*6); /* compensate both-edges scrollbar-gutter */
+
+ height: 100%;
+ background-color: var(--color-bg-main);
+
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: stretch;
+ gap: var(--base-rhythm);
+}
+
+/* redefine main layout grid */
+
+[data-viewtype="diff"] .main {
+ padding-bottom: 0;
+}
+
+[data-viewtype="source-file"] .main {
+ padding: 0;
+ scrollbar-gutter: unset;
+}
+
+.main_sticky_header {
+ position: sticky;
+ top: 0;
+ left: 0;
+ z-index: 11;
+
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-rhythm);
+
+ /* margin-bottom: calc(var(--base-rhythm)*4); */
+ background-color: var(--color-bg-main);
+ border: none;
+}
+
+.main_sticky_header > * {
+ position: relative;
+}
+
+.main_sticky_header::before {
+ content: '';
+ position: absolute;
+ bottom: 0;
+ top: -60px;
+ left: calc(-1 * var(--base-gap));
+ right: calc(-1 * var(--base-gap));
+ background-color: var(--color-bg-main);
+ z-index: 0;
+}
+
+/* .content */
+
+.content {
+ width: 100%;
+ min-width: calc(var(--card-width) + calc(var(--base-padding)*4));
+}
+
+[data-viewtype="document"] .content {
+ display: block;
+ max-width: 900px;
+ margin-bottom: 300px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+[data-viewtype="traceability"] .content {
+ display: grid;
+ place-items: stretch stretch;
+ grid-template-columns: minmax(min-content, max-content)
+ minmax(var(--card-width), calc(2*var(--card-width)))
+ minmax(min-content, max-content);
+ gap: var(--requirement-tree-margin) 0;
+ width: -moz-fit-content;
+ width: fit-content;
+ /* overflow: hidden; */
+}
+
+[data-viewtype="requirements-coverage"] .content,
+[data-viewtype="deep_traceability"] .content {
+ display: grid;
+ place-items: stretch stretch;
+ grid-template-columns: minmax(min-content, max-content)
+ max-content
+ minmax(min-content, max-content);
+ gap: var(--requirement-tree-margin) 0;
+ width: -moz-fit-content;
+ width: fit-content;
+
+ /* fon node-controls: */
+ /* overflow: hidden; */
+}
+
+[data-viewtype="table"] .content {
+ background-color: var(--color-bg-contrast);
+ display: block;
+ /* aligns the width of the white box of the content and the table: */
+ width: fit-content;
+}
+
+[data-viewtype="table"] sdoc-node .free_text{
+ max-width: 900px;
+}
+
+[data-viewtype="search"] .content {
+ display: grid;
+ place-items: stretch stretch;
+ grid-template-columns: 1fr;
+ gap: var(--tree-gap) 0;
+ width: -moz-fit-content;
+ width: fit-content;
+}
+
+/* TODO */
+/* used in TR, DTR, requirements_coverage: */
+.content_section {
+ display: contents;
+}
+/* TODO */
+.content_item {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ align-content: stretch;
+ align-items: stretch;
+}
+
+/* traceability */
+
+.content_item[data-role="parents"] {
+ grid-column: 1 / 2;
+}
+
+.content_item[data-role="current"] {
+ grid-column: 2 / 3;
+}
+
+[data-viewtype="deep_traceability"] .content_item[data-role="current"] {
+ /* central column */
+ width: var(--card-width);
+}
+
+[data-viewtype="requirements-coverage"] .content_item[data-role="current"] {
+ /* central column */
+ width: calc(var(--card-width)*0.75);
+}
+
+.content_item[data-role="children"] {
+ grid-column: 3 / 4;
+}
+
+[data-viewtype="deep_traceability"] .content_item[data-role="current"]::before,
+[data-viewtype="traceability"] .content_item[data-role="current"]::before {
+ /* for vertical line in 'current' column */
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: calc(var(--requirement-tree-margin)*(-1));
+ left: 50%;
+ border-left: 1px dotted #000;
+}
+
+[data-viewtype="deep_traceability"] section:last-child .content_item[data-role="current"]::before,
+[data-viewtype="traceability"] section:last-child .content_item[data-role="current"]::before {
+ /* the last section doesn't need a vertical connector under the middle node */
+ content: none;
+}
+
+/* placeholder */
+
+sdoc-main-placeholder {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ color: var(--color-placeholder);
+ font-weight: 700;
+ font-family: var(--code-font-family);
+ width: 100%;
+ height: 100%;
+}
+
+sdoc-main-legend {
+ display: block;
+ color: var(--color-placeholder);
+ font-weight: 700;
+ font-family: var(--code-font-family);
+ max-width: 1024px;
+ padding: var(--base-gap);
+ font-weight: 500;
+ margin-bottom: auto; /* To align the element at the top of the container that uses 'display:flex' */
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/diff.css b/tests/fuzz/_incremental/30_pusher_example/css/diff.css
new file mode 100644
index 0000000..35ab06f
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/diff.css
@@ -0,0 +1,531 @@
+/* diff */
+:root {
+ --pre-stripe: 20px;
+ --pre-stripe-color: rgba(0,0,0,0.02);
+ --pre-block-bg-color: rgba(0,0,0,0.01);
+
+ --diff-block-color-left: rgba(255, 55, 55, .05);
+ --diff-word-color-left: rgba(255, 55, 55, .2);
+ --diff-icon-color-left: rgba(255, 55, 55, .75);
+ --diff-document-color-left: rgba(255, 55, 55, 1);
+
+ --diff-block-color-right: rgba(20, 120, 20, .05);
+ --diff-word-color-right: rgba(20, 120, 20, .2);
+ --diff-icon-color-right: rgba(20, 120, 20, .75);
+ --diff-document-color-right: rgba(20, 120, 20, 1);
+}
+
+/*
+ *** diff ***
+ */
+
+.diff {
+ scroll-behavior: smooth;
+ background-color: var(--color-bg-main);
+
+ display: grid;
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ grid-template-columns: minmax(0, 1fr) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ minmax(0, 1fr);
+ grid-template-rows: minmax(0, max-content)
+ minmax(0, 1fr);
+
+ gap: var(--base-rhythm);
+
+ min-height: 0; /* to prevent from overflowing the parent flex container */
+}
+
+/* controls */
+
+.diff_controls {
+ display: flex;
+ justify-content: flex-end;
+ gap: calc(var(--base-rhythm)/2);
+}
+
+#diff_left_open {
+ color: var(--diff-document-color-left);
+}
+
+#diff_right_open {
+ color: var(--diff-document-color-right);
+}
+
+#diff_left_close,
+#diff_right_close {
+ color: var(--color-link);
+}
+
+#diff_left_open:hover,
+#diff_right_open:hover {
+ color: var(--color-hover);
+}
+
+/* columns */
+.diff_column {
+ overflow: auto;
+ overflow-y: scroll;
+
+ overflow-wrap: break-word;
+
+ border-radius: 4px;
+ border: 1px solid var(--color-border);
+
+ position: relative; /* for position:sticky */
+}
+
+.diff_column[left] {
+ direction:rtl;
+}
+
+.diff_column[right] {
+ direction:ltr;
+}
+
+.diff_inner {
+ direction: initial;
+ padding-bottom: 100%; /* to balance the scrolling freely */
+}
+
+.diff_content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-rhythm);
+ padding: var(--base-rhythm);
+}
+
+/* details with summary */
+
+.diff details {
+ width: 100%;
+}
+
+.diff summary {
+ list-style: none;
+ display: flex;
+ gap: var(--base-rhythm);
+ cursor: pointer;
+ color: var(--color-link);
+}
+
+.diff details[modified] > summary {
+ color: var(--color-fg-accent);
+}
+
+.diff details[modified="left"] > summary {
+ color: var(--diff-document-color-left);
+}
+
+.diff details[modified="right"] > summary {
+ color: var(--diff-document-color-right);
+}
+
+.diff summary:hover,
+.diff details[modified] > summary:hover {
+ color: var(--color-hover);
+}
+
+.diff summary::-webkit-details-marker {
+ display: none;
+}
+
+.diff details > summary::before {
+ content:"+";
+}
+
+.diff details[open] > summary::before {
+ content:"–";
+}
+
+/* document / details */
+
+.diff_document {
+ background-color: var(--color-bg-contrast);
+ border: 1px solid transparent;
+ border-radius: 4px;
+ padding: 0 var(--base-rhythm);
+}
+
+.diff_document[modified] {
+ border-color: var(--color-fg-accent);
+}
+
+.diff_document[modified="left"] {
+ border-color: var(--diff-document-color-left, rgba(255, 55, 55, 1));
+}
+
+.diff_document[modified="right"] {
+ border-color: var(--diff-document-color-right, rgba(20, 120, 20, 1));
+}
+
+.diff_document > summary {
+ line-height: 1.2;
+ padding: var(--base-rhythm) 0;
+ font-size: var(--font-size-sm);
+ font-weight: 700;
+ justify-content: space-between; /* '+' to right */
+}
+
+.diff_document[open] > summary {
+ /*
+ When the details are closed up, the summary sometimes covers the bottom border.
+ That's why we only add the background for cases where the card is open
+ and sticking makes sense.
+ */
+ background: var(--color-bg-contrast);
+ position: sticky;
+ top: 0;
+}
+
+.diff_document > summary .document_title {
+ flex-grow: 1;
+}
+
+.diff_document[open] > summary {
+ border-bottom: 1px dotted;
+}
+
+.diff_document > summary::before,
+.diff_document[open] > summary::before {
+ content: none !important;
+}
+
+.diff_document > summary::after {
+ content:"+";
+}
+
+.diff_document[open] > summary::after {
+ content:"–";
+}
+
+/* folder */
+
+.diff_folder {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ column-gap: calc(var(--base-rhythm)/2);
+ font-size: var(--font-size-sm);
+ min-width: 0;
+ line-height: 1.5;
+ padding-top: var(--base-rhythm);
+}
+
+/* node content */
+
+.diff_node {
+ margin: var(--base-rhythm) 0;
+}
+
+.diff_node_fields {
+ display: flex;
+ flex-direction: column;
+ margin: var(--base-rhythm) 0;
+ row-gap: calc(var(--base-rhythm) / 2);
+}
+
+.diff_node > .diff_node_fields {
+ padding-left: calc(var(--base-rhythm)*2);
+}
+
+.diff_node_field {
+ display: flex;
+ flex-wrap: wrap;
+ align-items: baseline;
+ column-gap: calc(var(--base-rhythm) / 2);
+}
+
+.diff_node_field > .badge {
+ line-height: var(--pre-stripe);
+}
+
+/*
+ *** changelog ***
+ */
+
+.changelog {
+ display: flex;
+ flex-direction: column;
+}
+
+.changelog .sdoc-table_key_value {
+ width: auto;
+}
+
+.changelog .diff_column {
+ margin-right: -16px;
+ border-radius: 0;
+ border: none;
+ border-right: 1px solid var(--color-border);
+}
+
+.changelog_summary {
+ padding: calc(2 * var(--base-rhythm));
+}
+
+.changelog_content {
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-rhythm);
+ margin-bottom: calc(4 * var(--base-rhythm));
+}
+
+.changelog_changes {
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-rhythm);
+}
+
+.changelog_change {
+ background-color: var(--color-bg-contrast);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+}
+
+.changelog_change_meta {
+ background-color: var(--color-bg-main);
+ width: 100%;
+ font-size: var(--font-size-xsm);
+ font-weight: 700;
+ display: flex;
+ gap: var(--base-rhythm);
+ padding: var(--base-rhythm);
+}
+
+.changelog_change_type {
+ font-size: var(--font-size-xsm);
+}
+
+.changelog_change_type.removed {
+ color: red;
+}
+
+.changelog_change_type.modified {
+ color: orange;
+}
+
+.changelog_change_type.added {
+ color: green;
+}
+
+.changelog_change_node {
+ width: 100%;
+ padding: var(--base-rhythm);
+}
+
+@media (min-width: 768px) {
+ .changelog_change_node {
+ /* width: calc(50% - var(--base-rhythm)); */
+ width: 50%;
+ }
+}
+
+.changelog_node_null {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: var(--color-placeholder);
+
+ height: 100%;
+ min-height: 32px;
+ background:repeating-linear-gradient(
+ -45deg,
+ rgba(234, 234, 234, 0.1),
+ rgba(234, 234, 234, .1) 10px,
+ rgba(234, 234, 234, .15) 10px,
+ rgba(234, 234, 234, .15) 20px
+ );
+
+}
+
+/*
+ *** MISC ***
+ */
+
+/* badge */
+
+.badge {
+ white-space: nowrap;
+}
+
+.badge::before {
+ content: attr(text);
+ padding: 0 calc(var(--base-rhythm)/2);
+ border: 1px solid;
+ border-radius: calc(var(--base-rhythm)/2);
+ font-size: var(--font-size-xxsm);
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+/* in summary: */
+[modified="left"] > summary .badge::before,
+/* in field: */
+[modified="left"] > .badge::before {
+ color: white;
+ background-color: var(--diff-icon-color-left);
+ border-color: var(--diff-icon-color-left);
+}
+
+/* in summary: */
+[modified="right"] > summary .badge::before,
+/* in field: */
+[modified="right"] > .badge::before {
+ color: white;
+ background-color: var(--diff-icon-color-right);
+ border-color: var(--diff-icon-color-right);
+}
+
+/* pre */
+
+.sdoc_pre_content {
+ flex-grow: 1;
+ white-space: pre-wrap;
+ overflow-x: clip;
+ font-family: monospace;
+ font-size: 0.85em;
+ line-height: var(--pre-stripe);
+ background-image: repeating-linear-gradient(
+ to bottom,
+ var(--pre-stripe-color),
+ var(--pre-stripe-color) var(--pre-stripe),
+ transparent var(--pre-stripe),
+ transparent calc(var(--pre-stripe)*2)
+ );
+ background-color: var(--pre-block-bg-color);
+}
+
+[multiline] .sdoc_pre_content {
+ flex-basis: 100%;
+}
+
+[modified="left"] > .sdoc_pre_content {
+ background-color: var(--diff-block-color-left);
+}
+.lambda_red {background-color: var(--diff-word-color-left);}
+
+[modified="right"] > .sdoc_pre_content {
+ background-color: var(--diff-block-color-right);
+}
+.lambda_green {background-color: var(--diff-word-color-right);}
+
+/* preloaded */
+/*
+ The element has been pre-loaded
+ and a smooth appearance effect is added to it.
+ The element will retain the computed values set by the last keyframe.
+ */
+.preloaded {
+ position: relative;
+ animation: fadeInPreloaded 1s ease-in-out;
+ animation-fill-mode: forwards;
+}
+
+@keyframes fadeInPreloaded {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+/* skeleton */
+
+.skeleton_spinner_container {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ min-height: 333px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ grid-column: 1/3;
+ grid-row: 2/3;
+ z-index: 11;
+}
+
+@keyframes change-color {
+ from {background-color: rgba(255,255,255,0.8);}
+ to {background-color: rgba(255,255,255,0.3);}
+}
+
+@keyframes pulse {
+ 0%, 100% {
+ opacity: .5;
+ }
+ 50% {
+ opacity: 1;
+ }
+}
+
+.skeleton_spinner {
+ position: relative;
+ text-indent: -9999em;
+ animation: mulShdSpin 1.3s infinite linear;
+ transform: translateZ(0);
+ /* size */
+ font-size: 8px;
+ margin: 36px;
+ /* dot */
+ color: var(--color-fg-accent);
+ width: 1em;
+ height: 1em;
+ border-radius: 50%;
+}
+
+@keyframes mulShdSpin {
+ 0%,
+ 100% {
+ box-shadow: 0 -3em 0 0.2em,
+ 2em -2em 0 0em, 3em 0 0 -1em,
+ 2em 2em 0 -1em, 0 3em 0 -1em,
+ -2em 2em 0 -1em, -3em 0 0 -1em,
+ -2em -2em 0 0;
+ }
+ 12.5% {
+ box-shadow: 0 -3em 0 0, 2em -2em 0 0.2em,
+ 3em 0 0 0, 2em 2em 0 -1em, 0 3em 0 -1em,
+ -2em 2em 0 -1em, -3em 0 0 -1em,
+ -2em -2em 0 -1em;
+ }
+ 25% {
+ box-shadow: 0 -3em 0 -0.5em,
+ 2em -2em 0 0, 3em 0 0 0.2em,
+ 2em 2em 0 0, 0 3em 0 -1em,
+ -2em 2em 0 -1em, -3em 0 0 -1em,
+ -2em -2em 0 -1em;
+ }
+ 37.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
+ 3em 0em 0 0, 2em 2em 0 0.2em, 0 3em 0 0em,
+ -2em 2em 0 -1em, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 50% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
+ 3em 0 0 -1em, 2em 2em 0 0em, 0 3em 0 0.2em,
+ -2em 2em 0 0, -3em 0em 0 -1em, -2em -2em 0 -1em;
+ }
+ 62.5% {
+ box-shadow: 0 -3em 0 -1em, 2em -2em 0 -1em,
+ 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 0,
+ -2em 2em 0 0.2em, -3em 0 0 0, -2em -2em 0 -1em;
+ }
+ 75% {
+ box-shadow: 0em -3em 0 -1em, 2em -2em 0 -1em,
+ 3em 0em 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,
+ -2em 2em 0 0, -3em 0em 0 0.2em, -2em -2em 0 0;
+ }
+ 87.5% {
+ box-shadow: 0em -3em 0 0, 2em -2em 0 -1em,
+ 3em 0 0 -1em, 2em 2em 0 -1em, 0 3em 0 -1em,
+ -2em 2em 0 0, -3em 0em 0 0, -2em -2em 0 0.2em;
+ }
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/element.css b/tests/fuzz/_incremental/30_pusher_example/css/element.css
new file mode 100644
index 0000000..5a3a0df
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/element.css
@@ -0,0 +1,1647 @@
+
+
+[data-viewtype="source-file"] .requirement__link:hover {
+ text-decoration: none;
+}
+
+svg {
+ /* Disable shrinking of icons in flex strings */
+ flex-shrink: 0;
+}
+
+/* typography */
+
+h1 { font-size: 2em; }
+h2 { font-size: 1.6em; }
+h3 { font-size: 1.4em; }
+h4 { font-size: 1.2em; }
+h5 { font-size: 1em; }
+h6 { font-size: 1em; }
+
+h1:first-child,
+h2:first-child,
+h3:first-child,
+h4:first-child,
+h5:first-child,
+h6:first-child {
+ margin-top: 0;
+}
+
+/* a */
+
+a {
+ /* Disabled link styles */
+ text-decoration: none;
+ color: gray;
+ transition: color .2s ease;
+}
+
+a:link,
+a:visited,
+a[href] { /* or a[href] */
+ /* Enabled link styles */
+ text-decoration: none;
+ color: var(--color-link);
+}
+
+a:hover {
+ /* color: blueviolet; */
+ color: var(--color-hover);
+}
+
+a[aria-disabled="true"] {
+ /* color: currentColor; */
+ cursor: not-allowed;
+ opacity: 0.5;
+ text-decoration: none;
+ pointer-events: none;
+}
+
+/* misc */
+
+code {
+ position: relative;
+ padding: 0 4px;
+ font-style: normal;
+ font-family: var(--code-font-family);
+ font-size: var(--code-font-size);
+ background-color: var(--color-bg-main);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+
+ overflow-wrap: break-word;
+ word-wrap: break-word;
+ -webkit-box-decoration-break: clone;
+ box-decoration-break: clone;
+}
+
+/* action_button */
+
+.actions_group {
+ display: flex;
+ /* header context: */
+ column-gap: calc(var(--base-rhythm)/2);
+ margin-left: auto;
+}
+
+.action_button,
+a.action_button,
+a.action_button:link,
+a.action_button:visited {
+ font-size:var(--font-size-xsm);
+ font-weight: 600;
+ text-align: left;
+ text-decoration: none;
+ white-space: nowrap;
+ position: relative;
+ display: inline-flex;
+
+ align-items: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
+ border-radius: 6px;
+ border: 1px solid transparent;
+ backface-visibility: hidden;
+ user-select: none;
+ cursor: pointer;
+ appearance: none;
+
+ /* 1.5 column-gap is compensated by SVG negative margin */
+ column-gap: calc(var(--base-rhythm)*1.5);
+ padding-left: calc(var(--base-rhythm)*1.5);
+ padding-right: calc(var(--base-rhythm)*1.5);
+ min-height: calc(var(--base-rhythm)*4);
+ max-width: 100%;
+
+ /* box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; */
+ color: var(--color-action);
+ background-color: rgb(255, 255, 255);
+ border-color: rgba(0, 0, 0, 0.05);
+ background-clip: padding-box;
+
+ transition: 0.2s;
+}
+
+.action_button:hover,
+a.action_button:hover {
+ box-shadow: rgb(0 0 0 / 10%) 0px 2px var(--base-rhythm) 0px;
+ color: var(--color-hover);
+ z-index: 6;
+}
+
+.action_button:disabled,
+.action_button:disabled:hover,
+.action_button[aria-disabled="true"],
+.action_button[aria-disabled="true"]:hover {
+ color: var(--color-action);
+ opacity: .4;
+ cursor: default;
+}
+
+.action_button svg {
+ /*
+ action_button 1.5 column-gap
+ is compensated by SVG negative margin
+ */
+ margin-left: calc(var(--base-rhythm)*(-.5));
+ margin-right: calc(var(--base-rhythm)*(-.5));
+}
+
+[data-action-type="submit"],
+.action_button[type=submit] {
+ color: var(--color-submit);
+}
+
+[data-action-type="action"],
+[data-action-type="confirm_delete"] {
+ color: var(--color-action) !important;
+ border-color: var(--color-action) !important;
+}
+
+[data-action-type="delete"],
+[data-action-type="confirm_delete"] {
+ color: var(--color-danger) !important;
+ border-color: var(--color-danger) !important;
+}
+
+[data-action-type="confirm_delete"]:hover {
+ color: var(--color-bg-contrast) !important;
+ background: var(--color-danger) !important;
+}
+
+[data-action-type="cancel"],
+.action_button[href*="cancel"] {
+ color: var(--color-cancel) !important;
+}
+
+.action_icon,
+a.action_icon,
+a.action_icon:link,
+a.action_icon:visited {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
+ backface-visibility: hidden;
+ user-select: none;
+ cursor: pointer;
+ appearance: none;
+ border: none;
+ border-color: transparent;
+ background-color: rgba(0,0,0,0);
+ background: rgba(0,0,0,0);
+ box-shadow: none;
+ background-clip: padding-box;
+
+ color: var(--color-action);
+ transition: 0.2s;
+ padding: calc(var(--base-rhythm)*.5);
+ z-index: 2;
+}
+
+.action_icon.secondary,
+a.action_icon.secondary,
+a.action_icon.secondary:link,
+a.action_icon.secondary:visited {
+ color: var(--color-link);
+}
+
+.action_icon.secondary:hover,
+a.action_icon.secondary:hover,
+.action_icon:hover,
+a.action_icon:hover {
+ color: var(--color-hover);
+ z-index: 6;
+}
+
+.action_button.compact {
+ column-gap: 0;
+ padding-left: calc(var(--base-rhythm)* 0.75);
+ padding-right: calc(var(--base-rhythm)* 0.75);
+ min-height: calc(var(--base-rhythm)*3);
+}
+
+.action_button.compact .action_button_compact__arising {
+ overflow: hidden;
+
+ max-width: 0;
+ margin-left: 0;
+
+ transition-property: max-width, margin;
+ transition-duration: .5s;
+ transition-timing-function: ease-in-out;
+ transition-delay: 1s;
+}
+
+.action_button.compact:hover > .action_button_compact__arising {
+ max-width: 200px;
+ margin-left: var(--base-rhythm);
+
+ transition-property: max-width, margin;
+ transition-duration: .5s;
+ transition-timing-function: ease-in-out;
+ transition-delay: 0;
+}
+
+/* TODO */
+sdoc-node-controls .action_button {
+ /* depends on sdoc-node-controls: */
+ /*
+ width: calc(var(--base-rhythm)*4);
+ height: calc(var(--base-rhythm)*4);
+ */
+ padding: 0 !important;
+ width: unset;
+ height: unset;
+ min-height: calc(var(--base-rhythm)*3) !important;
+ max-width: 100%;
+ max-height: 100%;
+ aspect-ratio: 1;
+ border-radius: 20% !important;
+
+ vertical-align: top;
+}
+
+/* field_action */
+/* TODO: optimize code with .action_icon & .action_button */
+
+.field_action { /* button */
+ font-size:var(--font-size-xsm);
+ font-weight: 600;
+ text-align: left;
+ text-decoration: none;
+ white-space: nowrap;
+
+ position: static;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
+ backface-visibility: hidden;
+ user-select: none;
+ cursor: pointer;
+ appearance: none;
+ border: none;
+ border-color: transparent;
+ background-color: rgba(0,0,0,0);
+ background: rgba(0,0,0,0);
+ box-shadow: none;
+ background-clip: padding-box;
+
+ color: var(--color-action);
+ transition: 0.2s;
+ padding: calc(var(--base-rhythm)*.5);
+ z-index: 2;
+}
+
+.field_action:hover,
+a.field_action:hover {
+ color: var(--color-hover);
+ z-index: 6;
+}
+
+.field_action::before {
+ content: '';
+ position: absolute;
+ /* The element is expected to be placed in a context
+ that defines the top and bottom boundaries.
+
+ The width of the element must be enough
+ to cover the entire available context,
+ and will be cut off by the parent element via overflow.
+ */
+ top: calc(var(--base-rhythm)*(-3)); /* -2 */
+ bottom: calc(var(--base-rhythm)*(-1)); /* -2 */
+ left: -100vw;
+ right: -100vw;
+ z-index: 0;
+ pointer-events: none;
+ /* Determines the shade of the color through the opacity of the element.
+ The color is passed from the parent.
+ */
+ transition: background-color 0.3s;
+ background-color: transparent;
+ opacity: .1; /* Defines the color shade. */
+}
+
+.field_action:hover::before {
+ background: currentcolor;
+}
+
+/* ***
+ USED BY copy_to_clipboard controller
+ */
+
+sdoc-field {
+ display: flex;
+ /* it is assumed that it will automatically stretch, as a block element,
+ to the entire field space, and the elements in the service area will be
+ positioned relative to it:
+ */
+ position: relative;
+ flex-grow: 1;
+ width: 100%; /* holds within the width of the parent */
+}
+
+sdoc-field-content {
+ flex-grow: 1;
+ width: 100%; /* holds within the width of the parent */
+}
+
+.copy_to_clipboard-cover {
+ position: absolute;
+ z-index: 98;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ pointer-events: none;
+
+ border-top-right-radius: 6px; /* TODO 4 + in button*/
+ background-color: rgba(242, 100, 42, 0);
+ transition: .5s ease-out;
+}
+
+.copy_to_clipboard-cover:hover {
+ background-color: rgba(242, 100, 42, 0.05);
+ transition: .5s ease-out;
+}
+
+/* Fix: Prevent .copy_to_clipboard-button from receiving hover when covered by dropdown menu */
+sdoc-field > sdoc-field-service .copy_to_clipboard-button {
+ visibility: hidden;
+}
+
+sdoc-field:hover > sdoc-field-service .copy_to_clipboard-button {
+ visibility: visible;
+}
+
+/* button overrides */
+.copy_to_clipboard-button.action_button {
+ height: calc(var(--base-rhythm)*3);
+ width: calc(var(--base-rhythm)*3);
+ min-height: unset;
+ padding: var(--base-rhythm);
+ position: absolute;
+ right: 0;
+ pointer-events: auto;
+
+ max-height: 100%; /* for meta row: to keep the copy button from expanding out of the content line */
+}
+
+/* button behavior */
+sdoc-field .copy_to_clipboard-button {
+ transition: .5s ease-out;
+ opacity: 0;
+}
+
+sdoc-field:hover .copy_to_clipboard-button {
+ opacity: 1;
+}
+
+/* ***
+ USED BY copy_stable_link controller
+ inside sdoc-node
+ */
+
+.copy_stable_link-button {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: var(--base-rhythm);
+
+ position: absolute;
+ left: 0;
+ top: 0;
+
+ cursor: pointer;
+ transition: .5s ease-out;
+ opacity: 0;
+}
+
+.copy_stable_link-button:hover {
+ color: var(--color-action);
+}
+
+sdoc-node:hover .copy_stable_link-button {
+ opacity: 1;
+}
+
+/* ANCHOR */
+
+sdoc-anchor {
+ /* for Fixed Headers + Section Anchors */
+ /* calc(var(--base-gap) + var(--base-padding)); */
+ scroll-snap-margin-top: var(--base-gap);
+ scroll-margin-top: var(--base-gap);
+}
+
+sdoc-node > sdoc-anchor {
+ scroll-snap-margin-top: unset; /** top: 0; */
+ scroll-margin-top: unset; /** top: 0; */
+
+ display: block;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: 0;
+}
+
+sdoc-anchor:target + sdoc-node-content sdoc-node-title,
+sdoc-anchor:target + sdoc-section sdoc-section-title,
+sdoc-anchor:target + .requirement__title {
+ background-color: var(--color-highlight);
+}
+
+/*
+ This code is triggered when
+ export/html/_static/controllers/anchor_controller.js adds
+ the [visible] attribute to the sdoc-anchor:
+*/
+sdoc-anchor[visible] {
+ position: absolute;
+ z-index: 2;
+ left: 0;
+
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: flex-start;
+
+ transition: opacity 0.5s;
+ opacity: 0;
+}
+
+sdoc-node:hover sdoc-anchor[visible] {
+ opacity: 1;
+}
+
+sdoc-anchor[visible].anchor_has_links {
+ opacity: 1;
+}
+
+sdoc-anchor[visible]:hover {
+ z-index: 10;
+}
+
+sdoc-anchor[visible] .anchor_block {
+ position: absolute;
+ top: 0;
+ left: calc(-4 * var(--base-rhythm) - 3px);
+
+ border-radius: 6px;
+ transition: opacity 0.2s;
+ opacity: .6;
+}
+
+sdoc-anchor[visible]:hover .anchor_block {
+ background-color: rgb(255, 255, 255);
+ border-color: rgba(0, 0, 0, 0.05);
+ box-shadow: rgb(0 0 0 / 10%) 0px 2px var(--base-rhythm) 0px;
+ opacity: 1;
+}
+
+sdoc-anchor[visible] .anchor_button {
+ cursor: pointer;
+ font-size:var(--font-size-sm);
+ font-weight: 600;
+ text-align: left;
+ white-space: nowrap;
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ border-radius: 6px;
+ border: 1px solid transparent;
+ background-clip: padding-box;
+
+ /* 1.5 column-gap is compensated by SVG negative margin */
+ column-gap: calc(var(--base-rhythm)*1.5);
+ padding-left: calc(var(--base-rhythm)*1.5);
+ padding-right: calc(var(--base-rhythm)*1.5);
+ min-height: calc(var(--base-rhythm)*4);
+ min-width: calc(var(--base-rhythm)*4);
+
+ /* box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; */
+ /* color: var(--color-action); */
+
+ overflow: hidden;
+
+ transition: opacity 0.2s;
+ opacity: .6;
+}
+
+sdoc-anchor[visible] .anchor_button:hover {
+ color: var(--color-hover);
+ z-index: 6;
+
+ opacity: 1;
+}
+
+sdoc-anchor[visible] .anchor_button svg {
+ color: var(--color-fg-secondary);
+ margin-left: calc(var(--base-rhythm)*(-.5));
+ margin-right: calc(var(--base-rhythm)*(-.5));
+}
+
+sdoc-anchor[visible].anchor_has_links .anchor_button svg {
+ color: black;
+ opacity: 1;
+}
+
+sdoc-anchor[visible] .anchor_button:hover svg {
+ color: var(--color-action) !important;
+}
+
+sdoc-anchor[visible] .anchor_button_text {
+ font-size: var(--font-size-sm);
+ font-weight: bolder;
+
+ display: none;
+}
+
+sdoc-anchor[visible]:hover .anchor_button_text {
+ display: block;
+}
+
+sdoc-anchor[visible] .anchor_back_links {
+ min-width: 300px;
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: var(--base-rhythm);
+ padding-top: var(--base-rhythm);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ display: none;
+}
+
+sdoc-anchor[visible]:hover .anchor_back_links {
+ display: block;
+}
+
+sdoc-anchor[visible] .anchor_back_links a {
+ display: list-item;
+}
+sdoc-anchor[visible] .anchor_back_links a::marker {
+ content: '⇠ ';
+ width: calc(var(--base-rhythm)*4);
+}
+
+sdoc-anchor[visible] .anchor_back_links_number {
+ color: var(--color-fg-accent);
+ position: absolute;
+ width: calc(var(--base-rhythm)*4);
+ text-align: center;
+ top: calc(var(--base-rhythm)*3);
+ left: 0;
+ font-weight: bold;
+}
+
+sdoc-anchor[visible]:hover .anchor_back_links_number {
+ top: calc(var(--base-rhythm)*5);
+}
+
+/* nav */
+
+.nav {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+
+ display: flex;
+ flex-flow: column nowrap;
+ background-color: var(--color-bg-ui);
+ width: var(--base-gap);
+ height: 100%;
+}
+
+.nav_list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.nav_list li {
+ margin-bottom: var(--base-rhythm);
+}
+
+.nav_list__link {
+ display: flex;
+ column-gap: var(--base-rhythm);
+}
+
+/* nav_button */
+
+.nav_button {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+
+ text-decoration: none;
+
+ height: var(--base-gap);
+ width: var(--base-gap);
+ transition: 0.3s;
+
+ color: var(--color-fg-secondary);
+}
+
+.nav_button:hover {
+ color: var(--color-fg-contrast);
+}
+
+.nav .nav_button {
+ color: var(--color-fg-secondary-invert);
+ background-color: transparent;
+ border-left: 2px solid transparent;
+}
+
+.nav .nav_button:hover {
+ color: var(--color-bg-contrast);
+ border-color: var(--color-bg-contrast);
+}
+
+/* should be like .nav .nav_button:hover */
+[data-viewtype="document-tree"] [data-link="index"],
+[data-viewtype="search"] [data-link="search"],
+[data-viewtype="diff"] [data-link="diff"],
+[data-viewtype="requirements-coverage"] [data-link="requirements_coverage"],
+[data-viewtype="traceability-matrix"] [data-link="traceability-matrix"],
+[data-viewtype="coverage-tree"] [data-link="source_coverage"] {
+ color: var(--color-bg-contrast);
+ border-color: var(--color-bg-contrast);
+ cursor: default;
+}
+
+/* sdoc tabs (page nav) */
+
+.sdoc-tabs {
+ border-bottom: 1px solid var(--color-border);
+}
+
+.sdoc-tab-list {
+ display: flex;
+ overflow: auto;
+ margin-bottom: -1px;
+}
+
+.sdoc-tab {
+ padding: var(--base-rhythm) calc(2 * var(--base-rhythm));
+ font-size: var(--font-size-xsm);
+ font-weight: 600;
+ line-height: 1;
+ color: var(--color-link);
+ text-decoration: none;
+ background-color: transparent;
+ border-width: 1px 1px 0px;
+ border-top-style: solid;
+ border-right-style: solid;
+ border-left-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-image: initial;
+ border-bottom-style: initial;
+ border-bottom-color: initial;
+
+ color: var(--color-fg-contrast);
+}
+
+.sdoc-tab:hover {
+ color: var(--color-hover);
+}
+
+.sdoc-tab[active] {
+ color: var(--color-fg-contrast);
+ border-color: var(--color-border);
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ background-color: var(--color-bg-main);
+}
+
+/* tags */
+
+.tags {
+ padding-bottom: var(--base-gap);
+}
+
+.tag {
+ display: inline-flex;
+ align-items: center;
+ background-color: rgba(0,0,0,0.1);
+ border: 2px solid rgba(0,0,0,0.05);
+ font-size: 12px;
+ line-height: 1;
+ vertical-align: middle;
+ margin: 2px 0px;
+ padding-left: 8px;
+ border-radius: 2em;
+}
+
+.tag_badge {
+ display: inline-flex;
+ justify-content: center;
+ align-items: center;
+ font-size: var(--font-size-xxsm);
+ background-color: rgba(255, 255, 255, 0.75);
+ border: 4px solid transparent;
+ min-width: 18px;
+ height: 18px;
+ border-radius: 2em;
+ margin-left: 4px;
+}
+
+/* coverage */
+
+.value-bar {
+ display: flex;
+ height: 1rem;
+ align-items: center;
+ gap: 4px;
+}
+
+.value-bar_bar {
+ width: 3rem;
+ border-radius: .5rem;
+
+ /* box-shadow: inset 0px 2px 2px 0px #ccc; */
+ border: 1px solid rgba(0,0,0,0.1);
+ position: relative;
+ overflow: hidden;
+
+ height: 0.75rem;
+
+ background-color: rgba(255, 255, 255, 0.2);
+}
+
+.value-bar_bar[data-value] {
+ border: 1px solid rgb(80, 240, 40);
+ background-color: rgba(255, 255, 255, 1);
+}
+
+.value-bar_filler {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ background: rgb(80, 240, 40);
+}
+
+.value-bar_text {
+ width: 2.5rem;
+ text-align: right;
+ font-size: 0.75rem;
+ line-height: 1;
+ font-weight: 600;
+}
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+/* svg icon */
+
+svg.svg_icon polyline,
+svg.svg_icon line,
+svg.svg_icon circle,
+svg.svg_icon rect,
+svg.svg_icon path {
+ fill: none;
+ fill-rule: evenodd;
+ stroke-width: 1.5;
+ /* stroke: #000; */
+ stroke: currentColor;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ /* transition: 0.2s; */
+}
+
+svg.svg_icon {
+ width: calc(var(--base-rhythm)*2);
+ height: calc(var(--base-rhythm)*2);
+ flex: 0 0 auto;
+ background: transparent;
+ /* color: rgb(246, 153, 13); */
+}
+
+.svg_icon_hover_visible {
+ display: none;
+}
+.anchor_button:hover .svg_icon_hover_visible,
+svg:hover .svg_icon_hover_visible {
+ display: inline;
+}
+.svg_icon_not_hover_visible {
+ display: inline;
+}
+.anchor_button:hover .svg_icon_not_hover_visible,
+svg:hover .svg_icon_not_hover_visible {
+ display: none;
+}
+
+/* .header */
+
+.header {
+ height: calc(var(--base-rhythm)*6);
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ column-gap: calc(var(--base-rhythm)/2);
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: var(--base-rhythm);
+ border-bottom: var(--base-border);
+ min-width: 0;
+}
+
+.header__document_title {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-size: var(--font-size-sm);
+ font-weight: 700;
+
+ flex-shrink: 0.1;
+}
+
+.header__project_name {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ font-size: var(--font-size-sm);
+ font-weight: 400;
+ min-width: calc(var(--base-rhythm)*2.5);
+
+ flex-shrink: 100;
+}
+
+/* .footer */
+
+.footer {
+ display: flex;
+ align-items: center;
+ justify-content: flex-end;
+ height: 100%;
+ padding: var(--base-rhythm) calc(var(--base-rhythm)*2);
+ column-gap: calc(var(--base-rhythm)/2);
+ background-color: var(--color-bg-ui);
+ color: var(--color-fg-secondary-invert);
+ font-size: .85rem;
+}
+
+a.strictdoc__link {
+ color: var(--color-fg-accent);
+ fill: var(--color-fg-accent);
+}
+
+a.strictdoc__version {
+ color: var(--color-fg-secondary-invert);
+ fill: var(--color-fg-secondary-invert);
+ display: flex;
+ column-gap: calc(var(--base-rhythm)/2);
+ align-items: center;
+}
+
+a.strictdoc__link:hover,
+a.strictdoc__version:hover {
+ color: var(--color-bg-main);
+ fill: var(--color-bg-main);
+}
+
+/* --md-source-version-icon: url(data:image/svg+xml;charset=utf-8, ); */
+
+
+/* pagetype */
+
+.pagetype {
+ font-size: var(--font-size-xxsm);
+ font-weight: 700;
+ text-transform: uppercase;
+ color: var(--color-fg-secondary);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ line-height: 1;
+}
+
+/* viewtype */
+
+.viewtype {
+ position: relative;
+ font-size: var(--font-size-xsm);
+}
+
+.viewtype__handler {
+ font-weight: 500;
+ color: var(--color-fg-accent);
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ column-gap: calc(var(--base-rhythm)/2);
+ user-select: none;
+}
+
+.viewtype__menu {
+ position: absolute;
+ z-index: 99;
+ left: calc(var(--base-rhythm)*(-2));
+ top: calc(var(--base-rhythm)*3);
+ margin: 0;
+ list-style: none;
+ padding: var(--base-rhythm);
+ background: var(--color-bg-contrast);
+ box-shadow: 0 2px 8px rgb(0 0 0 / 20%);
+ border-radius: var(--base-rhythm);
+ font-weight: 500;
+ display: flex;
+ flex-direction: column;
+ row-gap: calc(var(--base-rhythm)/2);
+}
+
+.viewtype__menu[aria-hidden="true"] {
+ display: none;
+}
+
+.viewtype__menu[aria-hidden="false"] {
+ display: flex;
+}
+
+.viewtype__menu_header {
+ padding: var(--base-rhythm);
+ text-transform: uppercase;
+ color: var(--color-fg-secondary);
+ font-weight: 700;
+ font-size: var(--font-size-xxsm);
+}
+
+.viewtype__menu_item {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ white-space: nowrap;
+ display: block;
+ padding: var(--base-rhythm);
+ border-radius: calc(var(--base-rhythm)/2);
+}
+
+.viewtype__menu_item,
+.viewtype__menu_item:link,
+.viewtype__menu_item:visited {
+ text-decoration: none;
+ color: var(--color-fg-main);
+}
+
+.viewtype__menu_item:hover {
+ background-color: var(--color-bg-secondary);
+ color: var(--color-fg-accent);
+}
+
+[data-viewtype="document"] [data-viewtype_link="document"],
+[data-viewtype="table"] [data-viewtype_link="table"],
+[data-viewtype="traceability"] [data-viewtype_link="traceability"],
+[data-viewtype="deep_traceability"] [data-viewtype_link="deep_traceability"],
+[data-viewtype="standalone_document"] [data-viewtype_link="standalone_document"],
+[data-viewtype="html2pdf"] [data-viewtype_link="html2pdf"],
+.viewtype__menu_item.active {
+ background-color: var(--color-bg-accent);
+ color: var(--color-fg-accent);
+ cursor: default;
+}
+
+/* sdoc-menu */
+
+sdoc-menu menu {
+ position: absolute;
+ z-index: 99;
+ right: 100%;
+ top: 0;
+ margin: 0;
+ list-style: none;
+ padding: var(--base-rhythm);
+ background: var(--color-bg-contrast);
+ box-shadow: 0 2px 8px rgb(0 0 0 / 20%);
+ border-radius: var(--base-rhythm);
+ font-weight: 500;
+
+ display: flex;
+ flex-direction: column;
+ row-gap: calc(var(--base-rhythm)/2);
+
+}
+
+sdoc-menu.add_node menu {
+ display: grid;
+ grid-template-columns: minmax(min-content, max-content)
+ minmax(min-content, max-content)
+ minmax(min-content, max-content)
+ minmax(min-content, max-content);
+}
+
+sdoc-menu menu[aria-hidden="true"] {
+ display: none;
+}
+
+sdoc-menu menu[aria-hidden="false"] {
+ display: flex;
+}
+sdoc-menu.add_node menu[aria-hidden="false"] {
+ display: grid;
+}
+
+sdoc-menu header:first-child {
+ /* "Add node" */
+ grid-column: 1 / -1;
+ border-bottom: var(--base-border);
+}
+
+sdoc-menu menu a {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ white-space: nowrap;
+ display: flex; /* affects the 'add node' buttons */
+ padding: var(--base-rhythm);
+ border-radius: calc(var(--base-rhythm)/2);
+ font-size: var(--font-size-xsm);
+}
+
+sdoc-menu menu a,
+sdoc-menu menu a:link,
+sdoc-menu menu a:visited {
+ text-decoration: none;
+ color: var(--color-fg-main);
+}
+
+sdoc-menu menu a:hover {
+ background-color: var(--color-bg-secondary);
+ color: var(--color-fg-accent);
+}
+
+sdoc-menu menu header {
+ padding: var(--base-rhythm);
+ text-transform: uppercase;
+ color: var(--color-fg-secondary);
+ font-weight: 700;
+ font-size: var(--font-size-xxsm);
+}
+
+/* plus to close */
+sdoc-menu-handler[aria-expanded="true"] svg {
+ transform: rotate(45deg);
+ color: black;
+}
+
+/* affects other menus: */
+[aria-expanded="true"] svg {
+ color: black;
+}
+
+/* tree */
+
+.tree {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ gap: var(--base-rhythm);
+ margin-top: calc(var(--base-rhythm) * 2);
+ margin-bottom: calc(var(--base-rhythm) * 8);
+ padding-left: calc(var(--base-rhythm) * 2);
+ padding-right: calc(var(--base-rhythm) * 2);
+}
+
+.tree_fragments { /* ul */
+ margin-top: 0;
+ margin-bottom: 0;
+ padding-left: calc(var(--base-rhythm) * 2);
+ padding-right: 0;
+ list-style: none;
+ width: 100%;
+}
+
+.tree_fragments li {
+ list-style: none;
+ width: 100%;
+}
+
+.tree_fragments,
+.tree_fragments li {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ gap: var(--base-rhythm);
+}
+
+.tree_folder {
+ display: flex;
+ align-items: flex-start;
+ justify-content: flex-start;
+ column-gap: var(--base-rhythm);
+ min-width: 0;
+ line-height: 1.5;
+ width: 99%;
+ padding-top: 8px;
+ margin-top: 8px;
+ opacity: 0.6;
+ position: relative;
+ border-top: var(--base-border);
+}
+
+.tree_folder:first-child {
+ border-top: none;
+}
+
+.tree_folder_path {
+ font-size: var(--font-size-xsm);
+ font-weight: 400;
+}
+
+a.tree_item,
+.tree_item {
+ display: flex;
+ align-items: flex-start;
+ justify-content: flex-start;
+ column-gap: var(--base-rhythm);
+ font-size: var(--font-size-sm);
+ min-width: 0;
+ line-height: 1.5;
+ width: 99%; /* To calculate cite overflow */
+}
+
+.tree_item[active] {
+ color: var(--color-fg-contrast);
+}
+
+.document_title {
+ font-size: var(--font-size-sm);
+ font-weight: 700;
+ width: 99%; /* To calculate cite overflow */
+}
+
+.document_title[data-file_name]::after {
+ content: attr(data-file_name);
+ display: block;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ width: 99%; /* To calculate cite overflow */
+ font-weight:400;
+ opacity:0.6;
+}
+
+/** TOC **/
+
+.toc,
+.toc ul,
+.toc li {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+.toc {
+ margin-top: calc(var(--base-rhythm) * 2);
+ padding-left: calc(var(--base-rhythm) * 2);
+ font-size: var(--font-size-sm);
+ line-height: 1.2;
+ padding-bottom: var(--base-gap);
+}
+
+.toc li {
+ margin: 0;
+ padding-left: var(--base-rhythm);
+ position: relative;
+}
+
+.toc a {
+ display: block;
+ position: relative;
+ padding-top: var(--base-rhythm);
+ padding-bottom: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+}
+
+.toc a,
+.toc a:link,
+.toc a:visited {
+ text-decoration: none;
+ color: var(--color-fg-secondary);
+}
+.toc a:hover {
+ color: var(--color-fg-contrast);
+}
+
+.toc a:focus,
+.toc a:active {
+ background: transparent;
+}
+
+.toc-title-no-link {
+ color: var(--color-fg-secondary);
+ opacity: .6;
+ display: block;
+ padding-top: var(--base-rhythm);
+ padding-bottom: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+}
+
+/* TOC targeted */
+.toc a[targeted]::before {
+ position: absolute;
+ z-index: -1;
+ content: '';
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: -200px; /* parent has overflow */
+ background-color: var(--color-highlight);
+}
+
+/* TOC intersected */
+.toc a::after {
+ position: absolute;
+ z-index: -1;
+ content: '';
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 8px;
+ background-color: var(--color-bg-main);
+}
+
+.toc a[intersected]::after {
+ position: absolute;
+ z-index: -1;
+ content: '';
+ top: 0;
+ right: 0;
+ bottom: 0;
+ width: 8px;
+ background-color: var(--color-highlight);
+}
+
+/* TOC parented */
+/* behavior depends on collapsible_list.js */
+.toc [data-collapsible_list__branch="closed"] ~ a[parented]::after {
+ background-color: var(--color-highlight);
+}
+
+/* pdf-toc */
+
+.pdf-toc {
+ display: table;
+ width: 100%;
+}
+.pdf-toc-row {
+ display: table-row;
+}
+.pdf-toc-cell {
+ display: table-cell;
+ padding-top: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+ font-size: 1em;
+ line-height: 1.5;
+}
+.pdf-toc-cell[dotted] {
+ position: relative;
+ width: 100%; /* to get max */
+}
+.pdf-toc-cell[dotted] > * {
+ background-color: white;
+ display: inline;
+ padding-right: 8px;
+ position: relative;
+}
+.pdf-toc-cell[dotted]::before {
+ content: '';
+ position: absolute;
+ border-bottom: dotted 2px rgba(0,0,0,.4);
+ bottom: .4em;
+ left: .8em;
+ right: .8em;
+}
+.pdf-toc-cell:last-child { /* page number */
+ vertical-align: bottom;
+ padding-right: 0;
+ text-align: right;
+}
+
+/* table_key_value component */
+
+.sdoc-table_key_value {
+ display: grid;
+ grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr);
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ position: relative;
+ border: var(--base-border);
+ border-radius: calc(var(--base-rhythm)*0.5);
+
+ margin: var(--base-padding) 0;
+ padding: calc(var(--base-rhythm)*0.5);
+ gap: 2px;
+
+ width: fit-content;
+ max-width: 100%;
+ /* overflow-x: auto; */
+}
+
+.sdoc-table_key_value-section,
+.sdoc-table_key_value-key,
+.sdoc-table_key_value-value {
+ padding: var(--base-rhythm) calc(var(--base-rhythm)*2);
+ background-color: var(--color-bg-secondary);
+}
+
+.sdoc-table_key_value-key {
+ grid-column: 1 / 2;
+ color: var(--color-fg-main);
+
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: flex-start;
+
+ position: relative;
+ transition: 0.3s all;
+}
+
+a.sdoc-table_key_value-key {
+ background-color: rgba(255,255,255,0.5);
+ color: var(--color-fg-contrast);
+ padding-right: calc(var(--base-rhythm)*5);
+ align-items: center;
+}
+
+a.sdoc-table_key_value-key:hover {
+ background-color: rgba(255,255,255,1);
+ color: var(--color-fg-accent);
+}
+
+a.sdoc-table_key_value-key::after {
+ content: "▸";
+ position: absolute;
+ right: calc(var(--base-rhythm)*2);
+ color: var(--color-fg-accent);
+ font-size: var(--font-size-sm);
+}
+
+.sdoc-table_key_value-value {
+ grid-column: 2 / 3;
+}
+
+.sdoc-table_key_value-section {
+ grid-column: 1 / -1;
+
+ padding: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*4);
+ padding-bottom: calc(var(--base-rhythm)*1);
+ font-family: var(--code-font-family);
+
+ font-size: 0.85em;
+ font-weight: 500;
+ text-transform: uppercase;
+ color: var(--color-fg-secondary);
+ background-color: var(--color-bg-main);
+}
+
+/* badge */
+
+.badge {
+ white-space: nowrap;
+}
+
+.badge::before {
+ content: attr(text);
+ padding: 0 calc(var(--base-rhythm)/2);
+ border: 1px solid;
+ border-radius: calc(var(--base-rhythm)/2);
+ font-size: var(--font-size-xxsm);
+ font-weight: 600;
+ text-transform: uppercase;
+}
+
+.error {
+ color: var(--color-danger);
+}
+
+/* tabs */
+
+sdoc-tab-content {
+ display: none;
+}
+sdoc-tab-content[active] {
+ display: contents;
+}
+
+sdoc-tabs {
+ grid-column: 1 / -1;
+
+ /* compensate top padding for sdoc-form-grid: */
+ /* margin-top: calc(var(--base-rhythm)*(-4)); */
+ padding: calc(var(--base-rhythm)*(1)) calc(var(--base-rhythm)*(2)) 0;
+
+ background-color: var(--color-bg-main);
+ border-radius: 4px;
+
+ display: flex;
+}
+
+sdoc-tab {
+ font-size: var(--font-size-xsm);
+ font-weight: 600;
+ text-align: left;
+ text-decoration: none;
+ white-space: nowrap;
+ position: relative;
+ display: inline-flex;
+
+ align-items: center;
+ justify-content: center;
+ -webkit-box-align: center;
+ -webkit-box-pack: center;
+
+ border: 1px solid transparent;
+ border-bottom: none;
+ border-radius: 4px 4px 0 0;
+
+ user-select: none;
+ cursor: pointer;
+ appearance: none;
+
+ /* 1.5 column-gap is compensated by SVG negative margin */
+ /* column-gap: calc(var(--base-rhythm)*1.5); */
+
+ min-height: calc(var(--base-rhythm)*4);
+ padding-left: calc(var(--base-rhythm)*1.5);
+ padding-right: calc(var(--base-rhythm)*1.5);
+
+ color: rgba(0, 0, 0, 0.5);
+ background-color: rgba(255, 255, 255, 0);
+ background-clip: padding-box;
+
+ transition: 0.2s;
+}
+
+sdoc-tab:hover {
+ background-color: rgba(255, 255, 255, 0.5);
+}
+
+sdoc-tab[active] {
+ color: var(--color-hover);
+ background-color: rgba(255, 255, 255, 1);
+ cursor: default;
+}
+
+sdoc-tab[data-errors] {
+ color: var(--color-danger);
+ border-color: var(--color-danger);
+}
+
+sdoc-tab[data-errors]::after {
+ content: attr(data-errors);
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background-color: var(--color-danger);
+ color: var(--color-bg-contrast);
+ font-size: var(--font-size-xsm);
+ height: calc(var(--font-size-xsm)*1.75);
+ width: calc(var(--font-size-xsm)*1.75);
+ aspect-ratio: 1;
+ border-radius: 50%;
+
+ /* parent column-gap == 0 */
+ position: relative;
+ right: calc(var(--base-rhythm)*(-1));
+}
+
+sdoc-tabs.in_aside_panel {
+ background-color: var(--color-highlight-secondary);
+ border-bottom: 4px solid var(--color-bg-main);
+}
+
+sdoc-tabs.in_aside_panel sdoc-tab:hover {
+ background-color: rgba(255, 255, 255, 0.25);
+}
+
+sdoc-tabs.in_aside_panel sdoc-tab[active] {
+ background-color: var(--color-bg-main);
+}
+
+/* document_issues */
+
+.document_issues-banner {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+ margin-bottom: var(--base-gap);
+ font-size: var(--font-size-sm);
+}
+
+.document_issues-toggler {
+ text-align: right;
+}
+
+.document_issues-banner_details {
+ display: block;
+ overflow: hidden;
+ color: var(--color-danger);
+ border: 1px solid;
+ border-radius: var(--requirement-border-radius);
+}
+
+.document_issues-banner_summary {
+ font-weight: 600;
+ position: relative;
+ color: var(--color-danger);
+ padding-inline: calc(2 * var(--base-rhythm));
+ padding-block: var(--base-rhythm);
+ cursor: pointer;
+ user-select: none;
+ display: flex;
+}
+
+.document_issues-banner_summary::before {
+ content: '▸';
+ margin-right: var(--base-rhythm);
+}
+
+[open] > .document_issues-banner_summary::before {
+ content: '▾';
+}
+
+.document_issues-banner_summary::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-color: currentColor;
+ opacity: 0.1;
+}
+
+.document_issues-banner_content {
+ position: relative;
+ color: var(--color-fg-contrast);
+ padding-inline: calc(2 * var(--base-rhythm));
+ padding-block: calc(1 * var(--base-rhythm));
+}
+
+.document_issues-banner ul {
+ margin: 0;
+ padding-inline-start: 20px;
+}
+
+.field_issue {
+ grid-column: 1 / -1;
+ position: relative;
+ color: var(--color-danger);
+ padding: var(--base-rhythm);
+ font-size: var(--font-size-sm);
+ line-height: 1.5;
+}
+
+.field_issue-ribbon {
+ position: relative;
+ padding: calc(.5 * var(--base-rhythm)) var(--base-rhythm);
+ border-radius: calc(.5 * var(--base-rhythm));
+ border: 2px solid;
+}
+
+.field_issue-ribbon::before {
+ position: absolute;
+ content: '';
+ bottom: 100%;
+ left: var(--base-rhythm);
+ width: 0;
+ height: 0;
+ border-left: 6px solid transparent;
+ border-right: 6px solid transparent;
+ border-bottom: 6px solid currentColor;
+}
+
+.field_issue-ribbon::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/form.css b/tests/fuzz/_incremental/30_pusher_example/css/form.css
new file mode 100644
index 0000000..be530b8
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/form.css
@@ -0,0 +1,595 @@
+/* form */
+
+sdoc-backdrop {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background: rgba(0,0,0,.5);
+ z-index: 99999;
+}
+
+sdoc-modal {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ grid-template-rows: min-content minmax(0, 1fr) min-content;
+ grid-template-areas:
+ "modal-header"
+ "modal-content"
+ "modal-footer";
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+
+ background-color: var(--color-bg-contrast);
+ border-radius: 8px;
+
+ width: 600px;
+ max-width: 90vw;
+ min-width: 375px;
+ max-height: 90vh;
+
+ box-shadow: var(--base-elevation-modal);
+ overflow: hidden;
+ overflow-y: auto;
+}
+
+sdoc-modal[context="confirm"] {
+ width: 600px;
+}
+
+sdoc-modal[context="form"] {
+ width: 90vw;
+ height: 90vh;
+ max-width: 600px;
+ max-height: 90vh;
+}
+
+sdoc-modal-container {
+ padding: calc(var(--base-rhythm)*4);
+}
+
+sdoc-modal-header {
+ grid-area: modal-header;
+ padding-top: calc(var(--base-rhythm)*2);
+ padding-bottom: calc(var(--base-rhythm)*2);
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*4);
+ font-size: 1.25rem;
+ font-weight: 600;
+}
+
+.sdoc-modal-header-back-button {
+ position: relative;
+ left: calc(var(--base-rhythm) * (-1));
+ display: inline-flex;
+ padding-right: var(--base-rhythm);
+}
+
+.sdoc-modal-header-back-button:hover {
+ color: var(--color-action);
+}
+
+sdoc-modal-content {
+ grid-area: modal-content;
+ border-top: var(--base-border);
+ border-bottom: var(--base-border);
+ /* padding-top: calc(var(--base-rhythm)*2); */
+ /* padding-bottom: calc(var(--base-rhythm)*2); */
+ overflow: auto;
+ scroll-behavior: smooth;
+}
+
+sdoc-modal-message {
+ display: block;
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*4);
+ margin-top: calc(var(--base-rhythm)*2);
+ margin-bottom: calc(var(--base-rhythm)*2);
+}
+
+sdoc-modal-footer {
+ grid-area: modal-footer;
+ display: flex;
+ justify-content: flex-end; /* buttons to right */
+ padding-top: calc(var(--base-rhythm)*2);
+ padding-bottom: calc(var(--base-rhythm)*2);
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*3); /* buttons to right */
+ column-gap: var(--base-rhythm);
+}
+
+/* sdoc-form */
+
+sdoc-form {
+ display: block;
+ position: relative;
+ background-color: var(--color-bg-contrast);
+ border-radius: 4px;
+ z-index: 11;
+ border: 1px solid var(--color-fg-accent);
+}
+
+sdoc-form-header {
+ display: block;
+ padding-top: 0;
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*4);
+ font-size: 1.25rem;
+ font-weight: 600;
+}
+
+sdoc-form-descr {
+ display: block;
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*4);
+ margin-top: calc(var(--base-rhythm)*2);
+ margin-bottom: calc(var(--base-rhythm)*2);
+}
+
+sdoc-form-footer {
+ display: flex;
+ justify-content: flex-start; /* buttons to left */
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: calc(var(--base-rhythm)*3); /* buttons to left */
+ padding-right: calc(var(--base-rhythm)*4);
+ margin-top: calc(var(--base-rhythm)*2);
+ margin-bottom: calc(var(--base-rhythm)*2);
+ column-gap: var(--base-rhythm);
+}
+
+sdoc-form-field {
+ /*
+ Flex can not be used, it is necessary exactly "display: block" because of
+ the effect on the display of the contenteditable element contained inside.
+ Extra spaces are formed there and it breaks the Selenium end2end tests.
+ */
+ display: block;
+ position: relative;
+ padding-top: 0;
+ padding-bottom: 0;
+ padding-left: calc(var(--base-rhythm)*4);
+ padding-right: calc(var(--base-rhythm)*4);
+ margin-top: calc(var(--base-rhythm)*4);
+ margin-bottom: calc(var(--base-rhythm)*4);
+ min-width: 200px;
+}
+
+sdoc-form-row-main {
+ display: flex;
+ flex-direction: column;
+ position: relative;
+}
+
+sdoc-form-row-aside {
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: flex-start;
+ justify-content: flex-end;
+ position: relative;
+}
+
+sdoc-form-row-aside [data-action-type="delete"]:hover,
+sdoc-form-row-aside [data-action-type="delete"] {
+ color: var(--color-danger);
+}
+
+sdoc-form-row-aside [data-action-type="action"]:hover,
+sdoc-form-row-aside [data-action-type="action"] {
+ color: var(--color-action);
+}
+
+sdoc-form-row-aside [data-action-type="move_up"]:hover,
+sdoc-form-row-aside [data-action-type="move_up"] {
+ color: var(--color-green);
+}
+
+sdoc-form-row-aside [data-action-type="move_down"]:hover,
+sdoc-form-row-aside [data-action-type="move_down"] {
+ color: var(--color-blue);
+}
+
+sdoc-form-row [data-action-type="add_field"]:only-child {
+ /*
+ It is expected to be a button (.action_button)
+ to add fields like "comment" or "link"
+ to the requirement edit form.
+ */
+ justify-content: flex-start;
+ /* color: rgba(0,0,0,0.5) !important; */
+ border: none;
+ top: -40%;
+}
+
+/*
+ fields grid:
+ inside sdoc-form-grid
+*/
+
+sdoc-form-grid {
+ display: grid;
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ grid-template-columns: minmax(0, min-content)
+ minmax(0, 1fr) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ minmax(0, min-content);
+ gap:
+ calc(var(--base-rhythm)*4)
+ var(--base-rhythm);
+
+ padding:
+ calc(var(--base-rhythm)*4)
+ calc(var(--base-rhythm)*3); /* (4-1) related to column gap */
+
+ overflow-x: clip; /* Prevents overflow issues affecting:
+ - field_action::before (highlight visibility on delete) and
+ - autocompletable (dropdown visibility) */
+
+ /* content container has no padding-block */
+ margin-top: calc(var(--base-rhythm)*2);
+ margin-bottom: calc(var(--base-rhythm)*2);
+}
+
+sdoc-form-grid
+ sdoc-form-field {
+ padding: 0;
+ margin: 0;
+ }
+
+sdoc-form-grid
+ sdoc-form-row {
+ display: contents;
+ }
+
+sdoc-form-grid
+ sdoc-form-row-aside:first-of-type {
+ grid-column: 1 / 2; /* left */
+ }
+
+sdoc-form-grid
+ sdoc-form-row-main {
+ grid-column: 2 / 3; /* center */
+ }
+
+sdoc-form-grid
+ sdoc-form-row-aside:last-of-type {
+ grid-column: 3 / 4; /* right */
+ }
+
+/* sdoc-form-field-group */
+
+sdoc-form-field-group {
+ /* display: grid;
+ place-items: stretch stretch;
+ place-content: stretch stretch; */
+
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+
+ padding: var(--base-rhythm);
+ border: var(--base-border);
+ border-radius: var(--base-rhythm);
+
+ gap: calc(var(--base-rhythm)*3); /* label (2) + 1 */
+ padding-top: calc(var(--base-rhythm)*3); /* related to column gap */
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ position: relative;
+}
+
+sdoc-form-field-group::before {
+ /* TODO move to other label */
+ content: attr(data-field-label);
+ position: absolute;
+ font-family: var(--code-font-family);
+ font-size: var(--font-size-xsm);
+ font-weight: 500;
+ color: var(--color-placeholder);
+ text-transform: uppercase;
+ top: calc(var(--base-rhythm)*(-1.25));
+ right: var(--base-rhythm);
+ padding: 0 var(--base-rhythm);
+ background: var(--color-bg-contrast);
+ transition: color .2s ease;
+}
+
+sdoc-form-field-group:focus-within::before {
+ color: var(--color-fg-accent);
+}
+
+/**
+ * sdoc-contenteditable
+ */
+
+sdoc-contenteditable,
+sdoc-autocompletable {
+ display: block;
+ position: relative;
+}
+
+sdoc-contenteditable[contenteditable="false"],
+sdoc-autocompletable[contenteditable="false"] {
+ color: var(--color-fg-secondary);
+}
+
+.autocomplete-items {
+ position: absolute;
+ border: 1px solid var(--color-action);
+ background-color: var(--color-bg-contrast);
+ top: 100%;
+ left: 0;
+ right: 0;
+ width: 33vw;
+ max-height: 60vh;
+ overflow-y: auto;
+ z-index: 999;
+}
+
+.autocomplete-active {
+ /*when navigating through the items using the arrow keys:*/
+ background-color: var(--color-highlight) !important;
+}
+
+.autocompletable-result-item {
+ position:relative;
+ display:block;
+ padding:.25rem 0.25rem;
+ margin-bottom:-1px;
+ border:1px solid rgba(0,0,0,.125)
+}
+
+.monospace {
+ font-family: var(--code-font-family);
+}
+
+.form__requirement_title {
+ font-size: 1.125em;
+ font-weight: 700;
+}
+
+/* field name // before */
+
+/* todo: Join sdoc-contenteditable with sdoc-form-field */
+
+sdoc-form-field label,
+sdoc-contenteditable::before,
+sdoc-autocompletable::before {
+ /* for contenteditable */
+ content: attr(data-field-label);
+ /* for all */
+ position: absolute;
+ font-family: var(--code-font-family);
+ font-size: var(--font-size-xsm);
+ font-weight: 500;
+ color: var(--color-placeholder);
+ text-transform: uppercase;
+ top: calc(var(--base-rhythm)*(-2.25));
+ transition: color .2s ease;
+
+ white-space: nowrap;
+}
+
+sdoc-form-field:focus-within label,
+sdoc-contenteditable:focus::before,
+sdoc-autocompletable:focus::before {
+ color: var(--color-fg-accent);
+}
+
+/* sdoc-form-field select */
+sdoc-form-field select {
+ /* A reset of styles, including removing the default dropdown arrow */
+ /* appearance: none; */
+ background-color: transparent;
+ /* border: none; */
+ border: 1px solid var(--color-placeholder);
+ border-radius: 6px;
+
+ padding: 0 1em 0 .5em;
+ margin: 0;
+ width: 100%;
+ font-family: inherit;
+ font-size: inherit;
+ cursor: inherit;
+ line-height: inherit;
+ /* Stack above custom arrow */
+ z-index: 1;
+ /* Remove focus outline, will add on alternate element */
+ outline: none;
+}
+
+sdoc-form-field select:focus {
+ border: 1px solid var(--color-fg-accent);
+}
+
+/* Remove dropdown arrow in IE10 & IE11
+ @link https://www.filamentgroup.com/lab/select-css.html
+*/
+sdoc-form-field select::-ms-expand {
+ display: none;
+}
+
+/* placeholder // after */
+
+[placeholder]:empty::after {
+ content: attr(placeholder);
+ pointer-events: none;
+ color: var(--color-placeholder);
+ /* For Firefox: */
+ display: block;
+}
+
+[placeholder]:empty:focus::after {
+ color: rgba(242, 100, 42,.2);
+}
+
+sdoc-contenteditable[data-field-suffix]:not(:empty)::after,
+sdoc-autocompletable[data-field-suffix]:not(:empty)::after {
+ content: attr(data-field-suffix);
+ color: var(--color-fg-accent);
+ margin-left: 4px;
+}
+
+/* data-field-suffix */
+
+[contenteditable=true] {
+ white-space: pre-wrap;
+ word-break: break-word;
+ overflow-wrap: anywhere;
+ outline: none;
+ /* Without this hack ( display: inline-block )
+ Chrome generates duplicated new lines when Enter pressed.
+ Add style "display:inline-block;" to contenteditable,
+ it will not generate div, p, span automatic in chrome */
+ /* https://stackoverflow.com/a/24689390/598057 */
+ /* Also, the parent element should not be allowed to have a flex display.
+ In order to isolate the 'contenteditable,
+ the structure "sdoc-form-row-main > sdoc-form-field > contenteditable"
+ is implemented.
+ */
+ display: inline-block;
+ /* This is to prevent the field from shifting when the second line appears while typing: */
+ vertical-align: top;
+ width: 100%;
+}
+
+[contenteditable=true][data-field-type="multiline"] {
+ font-family: var(--code-font-family);
+}
+
+
+
+form[data-controller~="scroll_into_view"] {
+ /* fix on 1px border and smth unruly */
+ scroll-snap-margin-top: calc(var(--base-padding) + 1px);
+ scroll-margin-top: calc(var(--base-padding) + 1px);
+}
+
+/* input */
+
+sdoc-form input[type="text"] {
+ padding: var(--base-rhythm);
+ font-size: var(--font-size);
+ border: 1px solid var(--color-border);
+ border-radius: 3px;
+ outline: transparent;
+ width: 100%;
+ transition: border-color calc(var(--transition, 0.2) * 1s) ease;
+}
+
+sdoc-form input[type="text"]:focus {
+ border-color: var(--color-action);
+ color: var(--color-action);
+}
+
+/* diff */
+
+sdoc-form[diff] {
+ grid-column: 1 / -1;
+
+ margin: 0;
+ background-color: transparent;
+ border: none;
+}
+
+sdoc-form[diff] form {
+ display: flex;
+ gap: var(--base-rhythm);
+ position: relative;
+ padding: var(--base-rhythm);
+ background-color: var(--color-bg-contrast);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+}
+
+/* search */
+
+sdoc-form[search] {
+ display: block;
+ background-color: transparent;
+ border: none;
+ border-radius: 0;
+}
+
+sdoc-form[search] form {
+ display: flex;
+ gap: var(--base-rhythm);
+ position: relative;
+ padding: var(--base-rhythm);
+ background-color: var(--color-bg-contrast);
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+}
+
+sdoc-form[search][success] {
+ border-bottom: 1px solid var(--color-border);
+}
+
+sdoc-form-error {
+ display: block;
+ color: var(--color-danger);
+ font-size: 12px;
+ /*
+ set 'order' to be displayed after any other items,
+ in the context of using flex:
+ */
+ order: 11;
+ /*
+ FOR:
+ components/grammar_form_element/index.jinja
+ "Relations_Row"
+ id="document__editable_grammar_relations"
+ */
+ grid-column: 2 / -1;
+}
+
+sdoc-form-error + sdoc-form-error {
+ margin-top: var(--base-rhythm);
+}
+
+sdoc-form-error + sdoc-form-field-group {
+ border-color: var(--color-danger);
+}
+
+
+sdoc-form-field-group[errors]::before, /* Grammar -> label for group of fields */
+sdoc-contenteditable[errors]::before, /* inside contenteditable errors block does not affected */
+sdoc-autocompletable[errors]::before,
+sdoc-form-error + sdoc-form-field > label, /* Grammar -> relation field ; File filed */
+sdoc-form-error + sdoc-form-field > sdoc-contenteditable::before,
+sdoc-form-error + sdoc-form-field > sdoc-autocompletable::before {
+ color: var(--color-danger);
+}
+
+.sdoc-form-error,
+.sdoc-form-success,
+.sdoc-form-reset {
+ display: block;
+ padding: var(--base-rhythm) calc(var(--base-rhythm)*2);
+ position: relative;
+}
+
+.sdoc-form-error {
+ color: var(--color-danger);
+}
+
+.sdoc-form-success {
+ color: var(--color-action);
+}
+
+.sdoc-form-reset {
+ position: absolute;
+ right: 0;
+ bottom: 0;
+}
+
+.sdoc-form-error,
+.sdoc-form-success {
+ padding-right: 120px; /* == sdoc-form-reset width */
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/html2pdf4doc.css b/tests/fuzz/_incremental/30_pusher_example/css/html2pdf4doc.css
new file mode 100644
index 0000000..f7ead23
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/html2pdf4doc.css
@@ -0,0 +1,4 @@
+html2pdf-print-forced-page-break + sdoc-node-content[node-view="narrative"],
+html2pdf-page + sdoc-node-content[node-view="narrative"] {
+ border-top: none;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/layout.css b/tests/fuzz/_incremental/30_pusher_example/css/layout.css
new file mode 100644
index 0000000..8ecd6df
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/layout.css
@@ -0,0 +1,116 @@
+.layout {
+ height: 100vh;
+ width: 100%;
+ display: grid;
+
+ grid-template-columns:
+ fit-content(var(--base-gap))
+ fit-content(20%)
+ fit-content(20%)
+ minmax( 0, 1fr ) /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ fit-content(20%)
+ auto;
+ grid-template-rows:
+ var(--base-gap)
+ minmax( 0, 1fr ) /* https://github.com/w3c/csswg-drafts/issues/1777 */
+ calc(var(--base-rhythm)*4);
+ grid-template-areas:
+ "nav header header header header aside"
+ "nav tree bar_left main bar_right aside"
+ "nav footer footer footer footer aside";
+
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+
+ overflow: hidden; /* Prevents scrolling before children's styles are triggered */
+}
+
+.layout_nav {
+ grid-area: nav;
+ position: relative;
+ z-index: 10;
+}
+
+.layout_tree {
+ grid-area: tree;
+ min-width: 0;
+}
+
+.layout_toc,
+.layout_toc[data-position='left'] {
+ grid-area: bar_left;
+}
+.layout_toc[data-position='right'] {
+ grid-area: bar_right;
+}
+
+.layout_footer {
+ grid-area: footer;
+}
+
+.layout_header {
+ grid-area: header;
+ min-width: 0;
+}
+
+.layout_aside {
+ grid-area: aside;
+ min-width: 0;
+}
+
+.layout_main {
+ grid-area: main;
+ min-width: 0;
+}
+
+/* */
+
+.section-number {
+ margin-right: .5rem;
+ font-size: 0.85em;
+ font-weight: bold;
+}
+
+/* messages */
+
+.mars {
+ position: fixed;
+ z-index: 1111;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ pointer-events: none;
+
+ display: flex;
+ justify-content: center;
+ /* align-items: flex-end */
+ align-items: center;
+
+ padding: calc(var(--base-rhythm)*10);
+}
+
+/* */
+
+sdoc-toast {
+ pointer-events: initial;
+ text-align: center;
+ border-radius: var(--base-rhythm);
+ box-shadow: 0 8px 32px rgba(0,0,0,.3);
+ background: var(--color-bg-ui);
+ color: var(--color-fg-secondary-invert);
+}
+
+sdoc-toast:not(:empty) {
+ padding: .75rem 2rem;
+}
+
+sdoc-toast a,
+sdoc-toast a:link,
+sdoc-toast a:visited {
+ color: var(--color-bg-contrast);
+}
+
+sdoc-toast a:hover {
+ color: var(--color-fg-accent);
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/main.css b/tests/fuzz/_incremental/30_pusher_example/css/main.css
new file mode 100644
index 0000000..60734e9
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/main.css
@@ -0,0 +1,53 @@
+body {
+ font-size: 16px;
+ line-height: 1.25;
+}
+
+[filler] {
+ background:repeating-linear-gradient(
+ -45deg,
+ rgba(100, 100, 100, .1),
+ rgba(100, 100, 100, .1) 10px,
+ rgba(100, 100, 100, .15) 10px,
+ rgba(100, 100, 100, .15) 20px
+ );
+}
+
+[filler='blue'] {
+ background:repeating-linear-gradient(
+ -45deg,
+ rgba(0, 175, 255, .1),
+ rgba(0, 175, 255, .1) 10px,
+ rgba(0, 175, 255, .15) 10px,
+ rgba(0, 175, 255, .15) 20px
+ );
+}
+
+[filler='red'] {
+ background:repeating-linear-gradient(
+ -45deg,
+ rgba(255, 25, 0, .1),
+ rgba(255, 25, 0, .1) 10px,
+ rgba(255, 25, 0, .15) 10px,
+ rgba(255, 25, 0, .15) 20px
+ );
+}
+
+[filler='green'] {
+ background:repeating-linear-gradient(
+ -45deg,
+ rgba(0, 175, 0, .1),
+ rgba(0, 175, 0, .1) 10px,
+ rgba(0, 175, 0, .15) 10px,
+ rgba(0, 175, 0, .15) 20px
+ );
+}
+
+[floater] {
+ outline: rgba(255, 0, 200, 0.2) 1px solid;
+}
+
+[floater='solid'] {
+ outline: rgba(255, 0, 55, 0.55) 1px solid;
+ overflow: auto;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/node.css b/tests/fuzz/_incremental/30_pusher_example/css/node.css
new file mode 100644
index 0000000..0b33e1b
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/node.css
@@ -0,0 +1,230 @@
+turbo-frame {
+ display: contents;
+}
+
+sdoc-node {
+ display: block;
+ position: relative;
+}
+
+/* sdoc-node[show-node-type-name] sdoc-node-content {
+ margin-top: calc(2 * var(--base-rhythm));
+} */
+
+sdoc-node[show-node-type-name]::before {
+ content: attr(show-node-type-name);
+ position: absolute;
+ top: calc(1 * var(--base-rhythm));
+ right: calc(4 * var(--base-rhythm));
+
+ font-size: 10px;
+ font-family: var(--code-font-family);
+ font-weight: 600;
+ line-height: 1;
+ text-transform: uppercase;
+
+ padding-top: calc(0.25 * var(--base-rhythm));
+ padding-bottom: calc(0.5 * var(--base-rhythm));
+ padding-left: calc(0.75 * var(--base-rhythm));
+ padding-right: calc(0.75 * var(--base-rhythm));
+ border-radius: 3px;
+ border: var(--requirement-border-width, 1px) solid var(--requirement-border-color, #bfbfbf);
+
+ color: var(--requirement-label-color);
+ background-color: var(--color-bg-contrast);
+}
+
+/* sdoc-node */
+
+sdoc-node {
+ background-color: var(--color-bg-contrast);
+ border-radius: 3px;
+
+ /* padding: calc(3 * var(--base-rhythm)) calc(4 * var(--base-rhythm)); */
+ padding-inline: calc(4 * var(--base-rhythm));
+ padding-block: calc(3 * var(--base-rhythm));
+}
+
+sdoc-node[node-role="root"] {
+ padding-top: calc(3 * var(--base-rhythm));
+}
+
+sdoc-node[node-style="readonly"][node-role="requirement"] {
+ background: none;
+ background-color: transparent;
+ outline: none;
+ padding-left: 0;
+ padding-right: 0;
+ padding-bottom: 0;
+ margin: 0;
+}
+
+sdoc-node[show-node-type-name][node-style="readonly"]::before {
+ right: 0;
+}
+
+sdoc-node[show-node-type-name][node-view="plain"]::before {
+ content: none;
+}
+
+/* editable_node */
+
+sdoc-node[node-style="card"][node-role="requirement"],
+[data-editable_node="on"] {
+ box-shadow: var(--base-elevation-0);
+ transition: box-shadow .5s;
+}
+
+sdoc-node[node-style="card"][node-role="requirement"]:hover,
+[data-editable_node="on"]:hover {
+ box-shadow: var(--base-elevation-node);
+ z-index: 10;
+}
+
+/* sdoc-node[node-style="card"] */
+
+sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-contrast);
+ border-radius: 3px;
+ padding: 0;
+}
+
+sdoc-node[node-style="card"][node-role="text"],
+sdoc-node[node-style="card"][node-role="section"] {
+ background-color: var(--color-bg-contrast);
+ padding: calc(var(--base-rhythm)) calc(var(--base-rhythm)*2);
+}
+
+[data-role='current'] sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-contrast);
+}
+
+[data-role='current'] [node-role="requirement"] {
+
+}
+
+[data-role='parents'] sdoc-node[node-style="card"],
+[data-role='children'] sdoc-node[node-style="card"] {
+ background-color: var(--color-bg-secondary);
+ width: var(--card-width);
+}
+
+sdoc-node[node-style="card"].highlighted {
+ background-color: var(--color-highlight);
+}
+
+[data-viewtype="traceability"] sdoc-node[node-style="card"] + sdoc-node[node-style="card"] {
+ margin-top: var(--base-padding);
+}
+
+[data-viewtype="deep_traceability"] sdoc-node[node-style="card"] {
+ /* width: var(--card-width); */
+ /* flex-grow: 1; */
+}
+
+[data-viewtype="requirements-coverage"] sdoc-node[node-style="card"] {
+ width: calc(var(--card-width)*0.75);
+ /* width: auto; */
+ font-size: .85em;
+ line-height: 1.4;
+}
+
+/* nouid */
+
+sdoc-node.nouid {
+ /* background-color: rgb(240, 220, 220); */
+}
+
+.nouid sdoc-node-title,
+.nouid .requirement__title {
+ color: #502222;
+}
+
+/* sdoc-node-controls */
+
+sdoc-node-controls[data-direction~="column"],
+sdoc-node-controls {
+ position: absolute;
+
+ display: flex;
+ justify-content: flex-start;
+
+ transition: .5s ease-out;
+ opacity: 0;
+
+ /* HACK: [sdoc-node outline hack] */
+ left: calc(100% + 1px);
+ top: -2px;
+
+ /* default: column to right */
+ bottom: 0;
+ right: unset;
+ width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ height: unset;
+
+ justify-content: flex-start;
+ flex-direction: column;
+}
+
+sdoc-node-controls[data-direction~="column"] {
+ flex-direction: column;
+ justify-content: flex-start;
+
+ left: 100%;
+ top: 0;
+ bottom: 0;
+ right: unset;
+ width: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ height: unset;
+}
+
+sdoc-node-controls[data-direction~="row"] {
+ flex-direction: row;
+ justify-content: flex-end;
+
+ top: calc(100% - 4px);
+ left: 0;
+ right: 0;
+ bottom: unset;
+ height: calc(var(--base-rhythm)*4); /* determines the size of the buttons */
+ width: unset;
+}
+
+sdoc-main-placeholder + sdoc-node-controls {
+ opacity: 1;
+}
+
+sdoc-node-controls:hover,
+sdoc-node:hover sdoc-node-controls {
+ opacity: 1;
+}
+
+sdoc-node:hover sdoc-node-controls:hover {
+ opacity: 1;
+}
+
+sdoc-menu {
+ display: flex;
+ align-items: stretch;
+ /* default: */
+ flex-direction: column;
+}
+
+sdoc-menu-handler {
+ display: flex;
+ align-items: stretch;
+ /* default: */
+ flex-direction: column;
+}
+
+sdoc-menu, /* default: */
+sdoc-menu-handler, /* default: */
+sdoc-node-controls[data-direction~="column"] sdoc-menu,
+sdoc-node-controls[data-direction~="column"] sdoc-menu-handler {
+ flex-direction: column;
+}
+
+sdoc-node-controls[data-direction~="row"] sdoc-menu,
+sdoc-node-controls[data-direction~="row"] sdoc-menu-handler {
+ flex-direction: row;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/node_content.css b/tests/fuzz/_incremental/30_pusher_example/css/node_content.css
new file mode 100644
index 0000000..e736efb
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/node_content.css
@@ -0,0 +1,478 @@
+:root {
+ --requirement-container-limit: 500px;
+ --requirement-border-color: rgb(230, 230, 230); /* = var(--color-border) on white without opacity */
+ --requirement-border-width: 1px;
+ --requirement-border-radius: 4px;
+ --requirement-inner-borders-width: 1px;
+ --requirement-label-color: var(--color-fg-secondary, #808080);
+ --requirement-bg-dark-color: var(--color-bg-main, #F2F5F9);
+ --requirement-bg-light-color: var(--color-bg-contrast, #FFFFFF);
+}
+
+/* sdoc-node-content */
+
+sdoc-node-content {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ gap: var(--requirement-inner-borders-width);
+
+ position: relative;
+ background-color: var(--color-bg-contrast); /* affects the color of the space between cells */
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color);
+
+ border-radius: var(--requirement-border-radius);
+
+
+ min-width: 300px;
+
+ /* and use overflow-wrap: break-word; in the field */
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+sdoc-node-title {
+ display: block;
+
+ font-size: 1.125em;
+ font-weight: 700;
+}
+
+sdoc-node-title:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-node-title * {
+ /* affect H inside title, if applicable */
+ margin: 0;
+}
+
+[node-style="card"] sdoc-node-title {
+ font-size: 1em;
+}
+
+/* synonym to [node-view="inline"] */
+sdoc-node-content[node-view="simple"] sdoc-node-title {
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+/* sdoc-node-content[node-view="simple"] sdoc-node-title, */
+sdoc-node-content[node-view="table"] sdoc-node-title,
+sdoc-node-content[node-view="zebra"] sdoc-node-title {
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ border-top-right-radius: var(--requirement-border-radius);
+ border-top-left-radius: var(--requirement-border-radius);
+
+ background-color: var(--requirement-bg-dark-color);
+ /* border-bottom: */
+ outline: 1px solid var(--requirement-border-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+sdoc-node-uid {
+ display: block;
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 700;
+
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+sdoc-node-field-label {
+ display: flex;
+ align-items:flex-start;
+
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1.75);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+
+ /* @mettta and @stanislaw are commenting this out because the REQUIREMENT's field names
+ were split apart, even though there was enough screen width
+ word-break: break-word;
+ */
+ overflow-wrap: break-word;
+}
+
+sdoc-node-field {
+ display: block;
+ position: relative;
+
+ padding-left: calc(var(--base-rhythm)*2);
+ padding-right: calc(var(--base-rhythm)*2);
+ padding-top: calc(var(--base-rhythm)*1);
+ padding-bottom: calc(var(--base-rhythm)*1);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+[data-viewtype="html2pdf"] sdoc-node-field-label {
+ word-break: normal;
+}
+
+/* for relations in requirement */
+sdoc-node-field > ol:first-child,
+sdoc-node-field > ul:first-child {
+ margin-top: 0;
+}
+sdoc-node-field > ol:last-child,
+sdoc-node-field > ul:last-child {
+ margin-bottom: 0;
+}
+
+/* node-view="plain" */
+
+sdoc-node-content[node-view="plain"] {
+ border: 0;
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-rhythm);
+}
+
+sdoc-node-content[node-view="plain"] sdoc-node-field-label {
+ display: none;
+}
+
+sdoc-node-content[node-view="plain"] sdoc-node-field {
+ padding: 0;
+}
+
+/* node-view="table" */
+
+sdoc-node-content[node-view="table"] {
+ /* grid: */
+ grid-template-columns: minmax(80px, min-content) minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* border: */
+ background-color: var(--requirement-border-color);
+}
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-title {
+ grid-column: 1 / 3;
+ }
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-field-label {
+ grid-column: 1 / 2;
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ grid-column: 2 / 3;
+ background-color: var(--requirement-bg-light-color);
+ }
+
+sdoc-node:not([node-style="card"]) {
+ /* Making the node a container for the requirement: */
+ container: node / inline-size;
+ /*
+ HACK: [sdoc-node outline hack]
+ Buggy behavior for @container CSS feature:
+ after window resize, the 1px vertically space
+ appears randomly between nodes.
+ */
+ outline: 1px solid #fff;
+ margin: 1px 0;
+}
+
+/* calc(var(--card-width) + calc(var(--base-padding)*4)) */
+/* 300 + 16*4 = 364 */
+@container node (width < 400px) {
+ sdoc-node-content[node-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-node-content[node-view="table"]
+ sdoc-node-title,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field-label,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+}
+
+@supports not (container-type: inline-size) {
+ /* TODO test 888px */
+ @media (max-width: 888px) {
+ /* Do the same as if there was a container support */
+
+ sdoc-node-content[node-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-node-content[node-view="table"]
+ sdoc-node-title,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field-label,
+ sdoc-node-content[node-view="table"]
+ sdoc-node-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+ }
+}
+
+/* node-view="zebra" */
+
+sdoc-node-content[node-view="zebra"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-node-content[node-view="zebra"]
+ sdoc-node-field-label {
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-node-content[node-view="zebra"]
+ sdoc-node-field {
+ background-color: var(--requirement-bg-light-color);
+ }
+
+/* node-view="simple" */
+/* synonym to "inline" */
+
+sdoc-node-content[node-view="simple"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-node-content[node-view="simple"]
+sdoc-node-field-label {
+ background-color: #fff;
+ padding-bottom: 0;
+}
+
+/* node-view="narrative" */
+
+sdoc-node-content[node-view="narrative"] {
+ display: flex;
+ flex-direction: column;
+ padding-top: var(--base-rhythm);
+ border-radius: 0;
+ border-left: none;
+ border-right: none;
+ border-bottom: none;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-title {
+ border: none;
+ outline: none;
+ background: none;
+ background-color: transparent;
+ padding: 0;
+ margin-bottom: var(--base-padding);
+ grid-column: 1 / -1;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-field {
+ padding: 0;
+}
+
+sdoc-node-content[node-view="narrative"] sdoc-node-field-label {
+ opacity: 0.8;
+ font-size: var(--font-size-sm);
+ line-height: calc(var(--font-size-sm) * 1.5);
+ padding: 0;
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary {
+ display: flex;
+ flex-direction: column;
+ padding-top: var(--base-padding);
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field {
+ margin-bottom: var(--base-padding);
+ color: var(--color-fg-contrast);
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-primary sdoc-node-field:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-secondary {
+ display: grid;
+ grid-template-columns: max-content 1fr;
+ gap: calc(.5 * var(--base-rhythm));
+}
+
+sdoc-node-content[node-view="narrative"] .node_fields_group-secondary sdoc-node-field {
+ font-size: var(--font-size-sm);
+ line-height: calc(var(--font-size-sm) * 1.5);
+ opacity: 0.6;
+}
+
+sdoc-node-content[node-view="narrative"] .requirement__parent-uid,
+sdoc-node-content[node-view="narrative"] .requirement__child-uid {
+ /*
+ affects UID in links;
+ make them lighter:
+ */
+ font-weight: normal;
+}
+
+/* section */
+
+sdoc-section,
+sdoc-section-title {
+ display: block;
+ margin: 0;
+}
+
+sdoc-section-title {
+ font-weight: 700;
+}
+
+sdoc-section-title {
+ margin-bottom: var(--base-padding);
+}
+
+sdoc-section-title:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-section-title * {
+ margin: 0;
+
+ /* This rule, when the element starts the page when printed,
+ creates illegal margins,
+ which breaks the rhythm of HTML2PDF4DOC
+ and generates blank pages:
+ */
+ /* display: inline; */
+}
+
+/* TEXT node */
+
+sdoc-text,
+sdoc-section-text {
+ display: block;
+ margin: 0;
+}
+
+[node-style="card"] sdoc-text {
+ padding: var(--base-padding);
+}
+
+sdoc-section-text {
+ margin-top: var(--base-padding);
+}
+
+sdoc-section-text:first-child {
+ margin-top: 0;
+}
+
+/* meta */
+
+sdoc-meta {
+ display: grid;
+ grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr);
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ position: relative;
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color);
+ border-radius: var(--requirement-border-radius);
+
+ font-size: var(--font-size-sm);
+ line-height: 24px; /* to keep the copy button from expanding out of the content line */
+ /* margin: var(--base-padding) 0; */
+ margin: 0;
+ padding: calc(var(--base-rhythm)*0.5);
+ row-gap: 2px;
+
+ width: fit-content;
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+sdoc-meta-section,
+sdoc-meta-label,
+sdoc-meta-field {
+ display: flex;
+ align-items: flex-start;
+ padding: calc(var(--base-rhythm)*0.25) var(--base-rhythm);
+ background-color: var(--color-bg-contrast);
+}
+
+sdoc-meta-label {
+ grid-column: 1 / 2;
+ font-family: var(--code-font-family);
+ font-weight: 700;
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+ background-color: var(--color-bg-secondary);
+}
+
+sdoc-meta-field {
+ grid-column: 2 / 3;
+}
+
+sdoc-meta-section {
+ grid-column: 1 / -1;
+}
+
+/* PDF */
+/* There is no sdoc-node wrapper, so such neighbours and nesting is possible. */
+sdoc-text + sdoc-text,
+sdoc-text + sdoc-section,
+sdoc-text + sdoc-section-title,
+sdoc-section + sdoc-text,
+sdoc-section + sdoc-section,
+sdoc-section + sdoc-section sdoc-section-title {
+ margin-top: calc(var(--base-rhythm)*4);
+}
+
+/* requirement type tag */
+
+.requirement__type-tag {
+ /* font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ text-transform: uppercase; */
+ color: var(--requirement-label-color);
+ white-space: nowrap;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/project_coverage.css b/tests/fuzz/_incremental/30_pusher_example/css/project_coverage.css
new file mode 100644
index 0000000..16df13a
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/project_coverage.css
@@ -0,0 +1,283 @@
+.project_coverage {
+ width: 100%;
+ /* font-size: 0.875rem; */
+}
+
+.project_coverage thead {
+ position: sticky;
+ z-index: 1;
+ top: calc(-1 * var(--base-gap)); /* compensate .main top padding when scrolling */
+}
+
+.project_coverage thead th {
+ /* adding a background prevents the th-button background from working */
+ vertical-align: bottom;
+ border-bottom: var(--base-border);
+ font-size: 0.875em;
+}
+
+.project_coverage thead::before {
+ content: '';
+ position: absolute;
+ z-index: -1;
+ left: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ right: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ top: calc(-1 * var(--base-gap)); /* compensate .main padding to overlap content */
+ bottom: 0;
+ background: var(--color-bg-main);
+}
+
+.project_coverage th,
+.project_coverage td {
+ padding: calc(0.5 * var(--base-rhythm)) var(--base-rhythm);
+ border-right: var(--base-border);
+ position: relative;
+}
+
+.project_coverage td {
+ text-align: right;
+}
+
+.project_coverage th:last-child,
+.project_coverage td:last-child {
+ border-right: none;
+}
+
+.project_coverage tr:first-child th:first-child, /* tr compensate colspan */
+.project_coverage td:first-child {
+ width: auto;
+ text-align: left;
+}
+
+.project_coverage td:not(:first-child) {
+ width: 1px;
+ white-space: nowrap;
+}
+
+.project_coverage tr.project_coverage-file:hover {
+ background: rgba(255,255,255,0.3);
+}
+
+.project_coverage tr.project_coverage-folder td {
+ padding-right: 0;
+}
+
+.project_coverage-folder-title {
+ /* font-weight: bold; */
+ display: flex;
+ align-items: flex-end;
+ column-gap: calc(0.5 * var(--base-rhythm));
+ /* font-size: 0.75em; */
+ line-height: 1;
+ color: #999;
+ padding: calc(0.5 * var(--base-rhythm));
+ position: relative;
+ background: var(--color-bg-secondary);
+}
+
+.project_coverage-file-link {
+ display: flex;
+ /* column-gap: var(--base-rhythm); */
+ padding: calc(0.5 * var(--base-rhythm));
+ border-radius: calc(0.5 * var(--base-rhythm));
+ transition: background .3s;
+ border: 1px solid rgba(255,255,255,0);
+}
+
+.project_coverage-file-icon {}
+
+.project_coverage-file-title {
+ font-size: 1em;
+ font-weight: 500;
+ line-height: 1.2;
+ transition: color .2s;
+ display: flex;
+ column-gap: var(--base-rhythm);
+}
+
+.project_coverage-file-path {
+ font-size: 0.75em;
+ color: var(--color-fg-secondary);
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: none;
+}
+
+.project_coverage-file-details {
+ position: relative;
+ flex-grow: 1;
+}
+
+.project_coverage-file-link:not([href]):hover {
+ /* color: gray; */
+ /* all this file have no links -> they are red */
+}
+
+.project_coverage-file_uncovered .project_coverage-file-link,
+.project_coverage-file_uncovered .project_coverage-file-title {
+ color: var(--color-danger);
+ font-weight: 400 !important;
+}
+
+.project_coverage-file-link[href]:hover .project_coverage-file-icon,
+.project_coverage-file-link[href]:hover .project_coverage-file-title {
+ color: var(--color-fg-accent);
+}
+
+.project_coverage-file-link[href] .project_coverage-file-icon,
+.project_coverage-file-link[href] .project_coverage-file-title {
+ color: var(--color-fg-main);
+}
+
+/* cols */
+
+.project_coverage-col-line {
+ background-color: rgba(255, 155, 0, 0.05) !important;
+}
+
+.project_coverage-col-func {
+ background-color: rgba(175, 0, 255, 0.05) !important;
+}
+
+.sorted_col.project_coverage-col-line,
+th.project_coverage-col-line {
+ background-color: rgba(255, 155, 0, 0.15) !important;
+}
+
+.sorted_col.project_coverage-col-func,
+th.project_coverage-col-func {
+ background-color: rgba(175, 0, 255, 0.15) !important;
+}
+
+/* value_extended */
+
+.value_extended[data-ext]::after {
+content: attr(data-ext);
+margin-left: 2px;
+font-size: 0.85em;
+font-weight: 200;
+}
+
+/* project_coverage-sort_handler */
+
+.project_coverage-sort_handler {
+ cursor: pointer;
+}
+
+.project_coverage-sort_handler::after {
+ content: '○';
+ display: block;
+}
+
+.project_coverage-sort_handler::before {
+ content: '';
+ cursor: pointer;
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+}
+
+.project_coverage-sort_handler:hover {
+ color: var(--color-blue);
+}
+
+.project_coverage-sort_handler:hover::before {
+ border: 3px solid white;
+}
+
+.project_coverage-sort_handler[sorted]::before {
+ border: 3px solid white;
+}
+
+/* ▿ ▵ △ ▽ ▾ ▴ */
+
+.project_coverage-sort_handler:hover::after {
+ /* the first act: desc */
+ content: '▽';
+}
+
+.project_coverage-sort_handler[sorted='asc']::after {
+ content: '▴';
+}
+
+.project_coverage-sort_handler[sorted='dsc']::after {
+ content: '▾';
+}
+
+.project_coverage-sort_handler[sorted='dsc']:hover::after {
+ content: '△';
+}
+
+.project_coverage-sort_handler[sorted='asc']:hover::after {
+ content: '▽';
+}
+
+/* sort_reset */
+
+.project_coverage-sort_reset {
+ display: flex;
+ flex-direction: column;
+ gap: var(--base-padding);
+}
+
+.project_coverage-sort_reset::after {
+ content: ' ';
+ display: block;
+}
+
+/* sorted sort_reset */
+
+.project_coverage.sorted .project_coverage-sort_reset {
+ cursor: pointer;
+}
+
+.project_coverage.sorted .project_coverage-sort_reset::after {
+ content: 'reset sorting';
+ font-weight: 400;
+ text-align: right;
+ color: var(--color-fg-accent);
+}
+
+.project_coverage.sorted .project_coverage-sort_reset::before {
+ content: '';
+ cursor: pointer;
+ position: absolute;
+ inset: 0;
+ z-index: -1;
+}
+
+.project_coverage.sorted .project_coverage-sort_reset:hover::before {
+ background-color: rgb(255 255 255 / 50%);
+}
+
+/* sorted mods */
+
+.project_coverage.sorted .project_coverage-folder,
+.project_coverage.sorted .project_coverage-file-indent {
+ display: none;
+}
+
+.project_coverage.sorted .project_coverage-file-path {
+ display: block;
+}
+
+.project_coverage.sorted .project_coverage-file-details {
+ position: relative;
+ flex-grow: 1;
+ padding: 0 0 var(--base-padding) 0;
+}
+
+/* color */
+
+.color-secondary {
+ color: var(--color-fg-secondary);
+}
+
+.color-uncovered {
+ color: var(--color-danger);
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/project_tree.css b/tests/fuzz/_incremental/30_pusher_example/css/project_tree.css
new file mode 100644
index 0000000..940d06b
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/project_tree.css
@@ -0,0 +1,218 @@
+
+/* tree */
+.project_tree {
+ position: relative;
+ /* width: -moz-fit-content;
+ width: fit-content; */
+ /* margin: 0 auto; */
+}
+
+.project_tree details>summary {
+ list-style: none;
+}
+
+.project_tree summary::-webkit-details-marker {
+ display: none
+}
+
+/* folder */
+
+.project_tree-folder {
+ border: var(--base-border);
+ border-radius: calc(0.5 * var(--base-rhythm));
+ overflow: hidden;
+ position: relative;
+ padding-left: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder[open] {
+ background: transparent;
+}
+
+.project_tree-folder.source {
+ padding-right: 0;
+ border-right: none;
+ border-bottom: none;
+}
+
+.project_tree-folder summary {
+ position: relative;
+ cursor: pointer;
+ user-select: none;
+}
+
+.project_tree-folder-title {
+ font-weight: bold;
+ display: flex;
+ column-gap: calc(0.5 * var(--base-rhythm));
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: #666;
+ padding: calc(0.5 * var(--base-rhythm));
+ position: relative;
+}
+
+.project_tree-folder-title::before,
+.project_tree-folder-title::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: -20px;
+ left: -20px;
+ bottom: 0;
+}
+
+.project_tree-folder-title::after {
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder summary:hover > .project_tree-folder-title::before {
+ background: var(--color-bg-secondary);
+}
+
+.project_tree-folder summary:hover > .project_tree-folder-title,
+.project_tree-folder summary:hover::after {
+ color: var(--color-fg-accent);
+}
+
+/* .icon_collapse_expand is class inside SVG */
+.project_tree-folder-title .icon_collapse_expand {
+ margin-left: auto;
+}
+/* .collapsed and .expanded are classes inside SVG .icon_collapse */
+.project_tree-folder > summary .icon_collapse_expand .collapsed {
+ display: initial;
+}
+.project_tree-folder > summary .icon_collapse_expand .expanded {
+ display: none;
+}
+.project_tree-folder[open] > summary .icon_collapse_expand .expanded {
+ display: initial;
+}
+.project_tree-folder[open] > summary .icon_collapse_expand .collapsed {
+ display: none;
+}
+
+.project_tree-folder-content {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ gap: var(--base-rhythm);
+ padding-top: var(--base-rhythm);
+ padding-bottom: var(--base-rhythm);
+}
+
+/* file */
+
+.project_tree-file {
+ display: flex;
+ column-gap: var(--base-rhythm);
+ padding: calc(0.5 * var(--base-rhythm));
+ border-radius: calc(0.5 * var(--base-rhythm));
+ transition: background .3s;
+ border: 1px solid rgba(255,255,255,0);
+}
+
+.project_tree-file:not([href]):hover {
+ border: 1px solid rgba(255,255,255,0.75);
+ background: rgba(0,0,0,0.01);
+}
+
+.project_tree-file[href]:hover {
+ background: rgba(255,255,255,0.5);
+}
+
+.project_tree-file[href]:hover .project_tree-file-icon,
+.project_tree-file[href]:hover .project_tree-file-title {
+ color: var(--color-fg-accent);
+}
+
+.project_tree-file-details {
+ display: block;
+}
+
+.project_tree-file-icon {
+ line-height: 0;
+}
+
+.project_tree-file-title {
+ font-size: 1em;
+ font-weight: 500;
+ line-height: 1.2;
+ transition: color .2s;
+}
+
+.project_tree-file-icon,
+.project_tree-file-title {
+ color: var(--color-fg-secondary);
+}
+
+.project_tree-file[href] .project_tree-file-icon,
+.project_tree-file[href] .project_tree-file-title {
+ color: var(--color-fg-main);
+}
+
+.project_tree-file-name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: var(--color-fg-secondary);
+ margin-top: 0.25rem;
+}
+
+.project_tree-file-aside {
+ margin-left: auto;
+}
+
+/* dashboard */
+
+.dashboard {
+ display: flex;
+ align-items: flex-start;
+ gap: var(--base-rhythm);
+}
+
+.dashboard-main {
+ flex-grow: 1;
+}
+
+.dashboard-aside {
+ width: 30%;
+ /* max-width: 300px; */
+ font-size: 0.75rem;
+ display: flex;
+ gap: var(--base-rhythm);
+ flex-direction: column;
+}
+
+.dashboard-block:empty {
+ display: none;
+}
+
+.dashboard-block {
+ border: var(--base-border);
+ border-radius: calc(0.5 * var(--base-rhythm));
+ overflow: hidden;
+ position: relative;
+ padding: var(--base-rhythm);
+}
+
+.dashboard-block-title {
+ font-weight: 600;
+ position: relative;
+ top: calc(-1 * var(--base-rhythm));
+ color: var(--color-fg-secondary);
+ padding: calc(0.5 * var(--base-rhythm)) 0;
+}
+
+.dashboard-block-title::after {
+ content: '';
+ position: absolute;
+ top: -20px;
+ left: -20px;
+ right: -20px;
+ bottom: 0;
+ background-color: rgba(0,0,0,0.025);
+ border-bottom: var(--base-border);
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/requirement-tree.css b/tests/fuzz/_incremental/30_pusher_example/css/requirement-tree.css
new file mode 100644
index 0000000..b0aa443
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/requirement-tree.css
@@ -0,0 +1,283 @@
+:root {
+ --requirement-tree-line-width: 1px;
+ --requirement-tree-line-color: var(--color-border);
+ --requirement-tree-margin: var(--tree-gap);
+ --requirement-tree-downward-margin: calc(var(--requirement-tree-margin)*.5);
+ --requirement-tree-downward-string-margin: calc(var(--requirement-tree-downward-margin)*0.25);
+ --requirement-tree-line: var(--requirement-tree-line-width) solid;
+ --requirement-tree-downward-line: var(--requirement-tree-line-color) var(--requirement-tree-line-width) solid;
+ --requirement-tree-arrow-size: calc(var(--requirement-tree-margin)/4);
+ /* var(--color-fg-contrast) */
+ /* var(--color-accent) */
+}
+
+/* requirement-tree */
+
+.requirement-tree {
+ position: relative;
+
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ box-sizing: border-box;
+
+ display: flex;
+ justify-content: flex-start;
+ flex-direction: column;
+ align-content: flex-start;
+
+ /* default aka right direction */
+ align-items: flex-start;
+ margin-left: var(--requirement-tree-margin);
+}
+
+.requirement-tree_right.requirement-tree {
+ align-items: flex-start;
+ margin-right: 0;
+ margin-left: var(--requirement-tree-margin);
+}
+
+.requirement-tree_left.requirement-tree {
+ align-items: flex-end;
+ margin-left: 0;
+ margin-right: var(--requirement-tree-margin);
+}
+
+.requirement-tree_branch {
+ position: relative;
+
+ display: flex;
+ justify-content: center;
+ align-items: flex-start;
+ align-content: stretch;
+ margin-bottom: var(--requirement-tree-margin);
+}
+
+.requirement-tree_left .requirement-tree_branch {
+ flex-direction: row-reverse;
+}
+
+.requirement-tree_branch:last-child {
+ margin-bottom: 0;
+}
+
+.requirement-tree_node {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+
+ /* for width restrictions in deep trace */
+ max-width: var(--card-width);
+}
+
+[data-viewtype="requirements-coverage"] .requirement-tree_node {
+ width: calc(var(--card-width)*0.75);
+}
+
+ /* arrows */
+
+.requirement-tree_right.requirement-tree::before {
+ /* arrow from children, show only in right tree */
+ content: '';
+ position: absolute;
+ width: var(--requirement-tree-arrow-size);
+ height: var(--requirement-tree-arrow-size);
+ top: var(--requirement-tree-margin);
+ left: calc(var(--requirement-tree-margin)*(-1) - var(--requirement-tree-line-width)*0.5);
+ box-sizing: border-box;
+ border-top: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ transform-origin: top left;
+ transform: rotate(-45deg);
+ z-index: 2;
+}
+
+.requirement-tree_left .requirement-tree_node::before {
+ /* arrow to parents inside tree */
+ content: '';
+ position: absolute;
+ width: var(--requirement-tree-arrow-size);
+ height: var(--requirement-tree-arrow-size);
+ top: var(--requirement-tree-margin);
+ right: calc(var(--requirement-tree-arrow-size)*(-1));
+ box-sizing: border-box;
+ border-top: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ transform-origin: top left;
+ transform: rotate(-45deg);
+ z-index: 2;
+}
+
+/* corner connector to node */
+
+.requirement-tree_branch::before {
+ content: '';
+ position: absolute;
+ width: calc(var(--requirement-tree-margin)*0.5);
+ height: var(--requirement-tree-margin);
+ top: 0;
+ box-sizing: border-box;
+ /* default aka right direction */
+ border-bottom: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_right .requirement-tree_branch::before {
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ border-left: var(--requirement-tree-line);
+}
+
+.requirement-tree_left .requirement-tree_branch::before {
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1)*0.5);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ border-right: var(--requirement-tree-line);
+}
+
+/* horizontal line to top node instead corner */
+
+.requirement-tree_branch:first-child::before {
+ width: var(--requirement-tree-margin);
+ border: none;
+ border-bottom: var(--requirement-tree-line);
+ /* default aka right direction */
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1));
+}
+
+.requirement-tree_right .requirement-tree_branch:first-child::before {
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1));
+}
+
+.requirement-tree_left .requirement-tree_branch:first-child::before {
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1));
+}
+
+/* vertical line */
+
+.requirement-tree_branch::after {
+ content: '';
+ position: absolute;
+ width: calc(var(--requirement-tree-margin)*0.5);
+ top: var(--requirement-tree-margin);
+ bottom: calc(var(--requirement-tree-margin)*(-1));
+ box-sizing: border-box;
+ /* default aka right direction */
+ border: none;
+ border-left: var(--requirement-tree-line);
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_right .requirement-tree_branch::after {
+ border: none;
+ border-left: var(--requirement-tree-line);
+ right: unset;
+ left: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+.requirement-tree_left .requirement-tree_branch::after {
+ border: none;
+ border-right: var(--requirement-tree-line);
+ left: unset;
+ right: calc(var(--requirement-tree-margin)*(-1)*0.5);
+}
+
+/* vertical line on last node is not showing */
+.requirement-tree_branch:last-child:after {
+ content: none;
+}
+
+/* downward */
+
+.requirement-tree_downward {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ margin-left: var(--requirement-tree-downward-margin);
+ box-sizing: border-box;
+
+ font-size: .75rem;
+ line-height: 1.2;
+}
+
+.requirement-tree_downward_node {
+ position: relative;
+ border-left: var(--requirement-tree-downward-line);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node {
+ padding-top: calc(var(--requirement-tree-downward-margin)*0.5);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:first-child {
+ padding-top: var(--requirement-tree-downward-margin);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:last-child {
+ border-color: transparent;
+}
+
+.requirement-tree_downward .requirement-tree_downward_node::before {
+ position: absolute;
+ content: '';
+ width: var(--requirement-tree-downward-margin);
+ border-bottom: var(--requirement-tree-downward-line);
+ box-sizing: border-box;
+ top: 0;
+ left: calc(var(--requirement-tree-line-width)*(-1));
+ bottom: calc(100% - var(--requirement-tree-downward-margin)*0.5 - 0.75rem);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:last-child::before {
+ border-left: var(--requirement-tree-downward-line);
+}
+
+.requirement-tree_downward .requirement-tree_downward_node:first-child::before {
+ bottom: calc(100% - var(--requirement-tree-downward-margin)*1 - 0.75rem);
+}
+
+.requirement-tree_downward_node .requirement-tree_downward_item {
+ position: relative;
+ /* margin-left: calc(var(--requirement-tree-downward-margin) + var(--requirement-tree-downward-string-margin)); */
+ margin-left: calc(var(--requirement-tree-downward-margin) - 0.25rem);
+
+ border-radius: 4px;
+ overflow: clip;
+ border: 1px solid var(--requirement-tree-line-color);
+ background-color: var(--color-bg-main);
+
+ overflow-wrap: break-word;
+}
+
+.requirement-tree_downward_item span,
+.requirement-tree_downward_item a {
+ padding: 4px 6px;
+ display: inline-block;
+ width: 100%;
+ overflow-wrap: break-word;
+}
+
+.requirement-tree_downward_item a {
+ color: var(--color-accent);
+ text-decoration: none;
+}
+
+.requirement-tree_downward_item a:hover {
+ text-decoration: underline;
+}
+
+/* hover */
+
+/* .requirement-tree_node:hover + .requirement-tree::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::before,
+.requirement-tree_node:hover + .requirement-tree .requirement-tree_branch::after {
+ border-width: 2px;
+} */
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/requirement.css b/tests/fuzz/_incremental/30_pusher_example/css/requirement.css
new file mode 100644
index 0000000..441e5d6
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/requirement.css
@@ -0,0 +1,370 @@
+:root {
+ --requirement-container-limit: 500px;
+ --requirement-border-color: rgb(191,191,191);
+ --requirement-border-width: 1px;
+ --requirement-border-radius: 4px;
+ --requirement-inner-borders-width: 1px;
+ --requirement-label-color: var(--color-fg-secondary, #808080);
+ --requirement-bg-dark-color: var(--color-bg-main, #F2F5F9);
+ --requirement-bg-light-color: var(--color-bg-contrast, #FFFFFF);
+
+ --requirement-base-rhythm: var(--base-rhythm, 8px);
+}
+
+/* sdoc-requirement */
+
+sdoc-requirement {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ gap: var(--requirement-inner-borders-width);
+
+ position: relative;
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color, #bfbfbf);
+
+ border-radius: var(--requirement-border-radius);
+ background-color: var(--color-bg-contrast);
+
+ min-width: 300px;
+
+ /* and use overflow-wrap: break-word; in the field */
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+sdoc-requirement-title {
+ display: block;
+
+ font-size: 1.125em;
+ font-weight: 700;
+
+ padding-left: calc(var(--requirement-base-rhythm)*2);
+ padding-right: calc(var(--requirement-base-rhythm)*2);
+ padding-top: calc(var(--requirement-base-rhythm)*1);
+ padding-bottom: calc(var(--requirement-base-rhythm)*1);
+
+ border-top-right-radius: var(--requirement-border-radius);
+ border-top-left-radius: var(--requirement-border-radius);
+
+ background-color: var(--requirement-bg-dark-color);
+ /* border-bottom: */
+ outline: 1px solid var(--requirement-border-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+[node-style="card"] sdoc-requirement-title {
+ font-size: 1em;
+}
+
+sdoc-requirement-uid {
+ display: block;
+ padding-left: calc(var(--requirement-base-rhythm)*2);
+ padding-right: calc(var(--requirement-base-rhythm)*2);
+ padding-top: calc(var(--requirement-base-rhythm)*1);
+ padding-bottom: calc(var(--requirement-base-rhythm)*1);
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 700;
+
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+sdoc-requirement-field-label {
+ display: flex;
+ align-items:flex-start;
+
+ padding-left: calc(var(--requirement-base-rhythm)*2);
+ padding-right: calc(var(--requirement-base-rhythm)*2);
+ padding-top: calc(var(--requirement-base-rhythm)*1.75);
+ padding-bottom: calc(var(--requirement-base-rhythm)*1);
+
+ font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+
+ /* @mettta and @stanislaw are commenting this out because the REQUIREMENT's field names
+ were split apart, even though there was enough screen width
+ word-break: break-word;
+ */
+ overflow-wrap: break-word;
+}
+
+sdoc-requirement-field {
+ display: block;
+ position: relative;
+
+ padding-left: calc(var(--requirement-base-rhythm)*2);
+ padding-right: calc(var(--requirement-base-rhythm)*2);
+ padding-top: calc(var(--requirement-base-rhythm)*1);
+ padding-bottom: calc(var(--requirement-base-rhythm)*1);
+
+ word-break: break-word;
+ overflow-wrap: break-word;
+}
+
+[data-viewtype="html2pdf"] sdoc-requirement-field-label {
+ word-break: normal;
+}
+
+/* for relations in requirement */
+sdoc-requirement-field > ol:first-child,
+sdoc-requirement-field > ul:first-child {
+ margin-top: 0;
+}
+sdoc-requirement-field > ol:last-child,
+sdoc-requirement-field > ul:last-child {
+ margin-bottom: 0;
+}
+
+/* requirement-view="table" */
+
+sdoc-requirement[requirement-view="table"] {
+ /* grid: */
+ grid-template-columns: minmax(80px, min-content) minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* border: */
+ background-color: var(--requirement-border-color);
+}
+
+sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-title {
+ grid-column: 1 / 3;
+ }
+
+sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field-label {
+ grid-column: 1 / 2;
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field {
+ grid-column: 2 / 3;
+ background-color: var(--requirement-bg-light-color);
+ }
+
+sdoc-node:not([node-style="card"]) {
+ /* Making the node a container for the requirement: */
+ container: node / inline-size;
+ /*
+ HACK: [sdoc-node outline hack]
+ Buggy behavior for @container CSS feature:
+ after window resize, the 1px vertically space
+ appears randomly between nodes.
+ */
+ outline: 1px solid #fff;
+ margin: 1px 0;
+}
+
+/* calc(var(--card-width) + calc(var(--base-padding)*4)) */
+/* 300 + 16*4 = 364 */
+@container node (width < 400px) {
+ sdoc-requirement[requirement-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-title,
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field-label,
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+}
+
+@supports not (container-type: inline-size) {
+ /* TODO test 888px */
+ @media (max-width: 888px) {
+ /* Do the same as if there was a container support */
+
+ sdoc-requirement[requirement-view="table"] {
+ /* removes columns: */
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ /* removes inner border: */
+ background-color: var(--requirement-bg-light-color);
+ }
+
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-title,
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field-label,
+ sdoc-requirement[requirement-view="table"]
+ sdoc-requirement-field {
+ /* removes columns: */
+ grid-column: unset;
+ }
+ }
+}
+
+/* requirement-view="zebra" */
+
+sdoc-requirement[requirement-view="zebra"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-requirement[requirement-view="zebra"]
+ sdoc-requirement-field-label {
+ background-color: var(--requirement-bg-dark-color);
+ }
+
+sdoc-requirement[requirement-view="zebra"]
+ sdoc-requirement-field {
+ background-color: var(--requirement-bg-light-color);
+ }
+
+/* requirement-view="simple" */
+
+sdoc-requirement[requirement-view="simple"] {
+ grid-template-columns: minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+}
+
+sdoc-requirement[requirement-view="simple"]
+sdoc-requirement-field-label {
+ background-color: #fff;
+ padding-bottom: 0;
+}
+
+/* section */
+
+sdoc-section,
+sdoc-section-title {
+ display: block;
+ margin: 0;
+}
+
+sdoc-section-title {
+ font-weight: 700;
+}
+
+sdoc-section-title {
+ margin-bottom: var(--base-padding);
+}
+
+sdoc-section-title:last-child {
+ margin-bottom: 0;
+}
+
+sdoc-section-title * {
+ margin: 0;
+
+ /* This rule, when the element starts the page when printed,
+ creates illegal margins,
+ which breaks the rhythm of HTML2PDF4DOC
+ and generates blank pages:
+ */
+ /* display: inline; */
+}
+
+/* TEXT node */
+
+sdoc-text,
+sdoc-section-text {
+ display: block;
+ margin: 0;
+}
+
+sdoc-section-text {
+ margin-top: var(--base-padding);
+}
+
+sdoc-section-text:first-child {
+ margin-top: 0;
+}
+
+/* meta */
+
+sdoc-meta {
+ display: grid;
+ grid-template-columns: minmax(min-content, max-content) minmax(min-content, 1fr);
+ place-items: stretch stretch;
+ place-content: stretch stretch;
+ position: relative;
+ border:
+ var(--requirement-border-width, 1px)
+ solid
+ var(--requirement-border-color, #bfbfbf);
+ border-radius: var(--requirement-border-radius);
+
+ font-size: var(--font-size-sm);
+ line-height: 24px; /* to keep the copy button from expanding out of the content line */
+ /* margin: var(--base-padding) 0; */
+ margin: 0;
+ padding: calc(var(--requirement-base-rhythm)*0.5);
+ row-gap: 2px;
+
+ width: fit-content;
+ max-width: 100%;
+ overflow-x: auto;
+}
+
+sdoc-meta-section,
+sdoc-meta-label,
+sdoc-meta-field {
+ display: flex;
+ align-items: flex-start;
+ padding: calc(var(--requirement-base-rhythm)*0.25) var(--requirement-base-rhythm);
+ background-color: var(--color-bg-contrast);
+}
+
+sdoc-meta-label {
+ grid-column: 1 / 2;
+ font-family: var(--code-font-family);
+ font-weight: 700;
+ text-transform: uppercase;
+ color: var(--requirement-label-color);
+ background-color: var(--color-bg-secondary);
+}
+
+sdoc-meta-field {
+ grid-column: 2 / 3;
+}
+
+sdoc-meta-section {
+ grid-column: 1 / -1;
+}
+
+/* PDF */
+/* There is no sdoc-node wrapper, so such neighbours and nesting is possible. */
+sdoc-text + sdoc-text,
+sdoc-text + sdoc-section,
+sdoc-text + sdoc-requirement,
+sdoc-text + sdoc-section-title,
+sdoc-section + sdoc-text,
+sdoc-section + sdoc-section,
+sdoc-section + sdoc-requirement,
+sdoc-section + sdoc-section sdoc-section-title,
+sdoc-requirement + sdoc-text,
+sdoc-requirement + sdoc-requirement,
+sdoc-requirement + sdoc-section,
+sdoc-requirement + sdoc-section sdoc-section-title {
+ margin-top: calc(var(--base-rhythm)*4);
+}
+
+/* requirement type tag */
+
+.requirement__type-tag {
+ /* font-size: var(--font-size-sm);
+ font-family: var(--code-font-family);
+ font-weight: 500;
+ line-height: 1;
+ text-transform: uppercase; */
+ color: var(--requirement-label-color);
+ white-space: nowrap;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/requirement__temporary.css b/tests/fuzz/_incremental/30_pusher_example/css/requirement__temporary.css
new file mode 100644
index 0000000..24122fe
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/requirement__temporary.css
@@ -0,0 +1,138 @@
+/* TODO: should be revised and then moved to a permanent location or removed */
+
+/* requirement__title */
+
+.requirement__title {
+ margin: 0;
+ line-height: 1.6;
+ font-weight: bold;
+}
+
+/* requirement: parent / child / file */
+
+ul.requirement__link {
+ font-size: .85rem;
+ line-height: 1.4;
+ list-style: none;
+ padding: 0;
+}
+
+[data-viewtype="source-file"] ul.requirement__link li {
+ margin-top: 0.5rem;
+}
+
+.requirement__link a,
+.requirement__link li > span {
+ display: inline-block;
+ position: relative;
+ margin-left: 1.5rem;
+ width: calc(100% - 1.5rem);
+ overflow-wrap: break-word;
+}
+
+.requirement__link a::before,
+.requirement__link li > span::before {
+ color: #808080;
+ position: absolute;
+ left: -1.5rem;
+}
+
+.requirement__link a:link,
+.requirement__link a:visited {
+ color: var(--color-fg-contrast);
+ text-decoration: none;
+}
+
+.requirement__link a:hover {
+ /* color: var(--color-fg-accent); */
+ text-decoration: underline;
+}
+
+/* .requirement__link a::before {
+ content: '\2014';
+} */
+
+a.requirement__link-file::before,
+.requirement__link-file::before {
+ content: '>';
+}
+
+a.requirement__link-parent::before {
+ content: '\2190';
+}
+
+a.requirement__link-child::before {
+ content: '\2192';
+}
+
+.requirement__link-external::before {
+ content: '\21D6';
+}
+
+.requirement__parent-uid,
+.requirement__child-uid {
+ position: relative;
+ font-weight: bold;
+}
+
+/* switch (injected by JS) */
+
+.std-switch {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+
+ user-select: none;
+ cursor: pointer;
+}
+
+.std-switch input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ position: absolute;
+}
+
+.std-switch_slider {
+
+ position: relative;
+ cursor: pointer;
+ background-color: #ccc;
+ -webkit-transition: .4s;
+ transition: .4s;
+
+ display: inline-block;
+ width: 44px;
+ height: 26px;
+ margin-right: 10px;
+
+ border-radius: 22px;
+}
+
+.std-switch_slider::before {
+ position: absolute;
+ content: "";
+ height: 18px;
+ width: 18px;
+ left: 4px;
+ bottom: 4px;
+ background-color: white;
+ -webkit-transition: .4s;
+ transition: .4s;
+
+ border-radius: 50%;
+}
+
+input:checked + .std-switch_slider {
+ background-color: rgb(100, 222, 50);
+}
+
+input:focus + .std-switch_slider {
+ box-shadow: 0 0 1px rgb(100, 222, 50);
+}
+
+input:checked + .std-switch_slider:before {
+ -webkit-transform: translateX(18px);
+ -ms-transform: translateX(18px);
+ transform: translateX(18px);
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/source.css b/tests/fuzz/_incremental/30_pusher_example/css/source.css
new file mode 100644
index 0000000..06a393a
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/source.css
@@ -0,0 +1,410 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+[data-viewtype="source-file"] {
+ --source-line: 1px solid rgba(0, 0, 0, .05);
+}
+
+[data-viewtype="source-file"] .layout {
+ grid-template-columns:
+ fit-content(var(--base-gap))
+ minmax(222px, 22%) /* replaced: fit-content(20%) */
+ fit-content(20%)
+ minmax(0, 1fr)
+ fit-content(20%)
+ auto;
+ grid-template-areas:
+ "nav header header header header aside"
+ "nav tree bar_left main bar_right aside"
+ "nav footer footer footer footer aside";
+}
+
+/* left panel */
+
+.source-file__aside {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+/* left scrollable panel */
+
+.source-file__refer { /* wrapper */
+ position: relative;
+ height: 100%;
+ overflow-y: hidden;
+}
+
+.source-file__toc {
+ position: relative;
+ height: 100%;
+ overflow-y: scroll;
+ padding: calc(var(--base-padding)*2)
+ calc(var(--base-padding) / 2)
+ calc(var(--base-padding)*4)
+ calc(var(--base-padding) / 1);
+
+ font-size: var(--font-size-sm);
+
+ transition: margin-left .5s;
+ scrollbar-color: transparent var(--scrollbarBG);
+}
+
+.source-file__toc:hover {
+ scrollbar-color: var(--thumbBG) var(--scrollbarBG);
+}
+
+.source-file__toc::-webkit-scrollbar-thumb {
+ background-color: transparent;
+}
+
+.source-file__toc:hover::-webkit-scrollbar-thumb {
+ background-color: var(--thumbBG)
+}
+
+.source-file__toc-range {
+ background-color: var(--color-highlight-secondary);
+ border-radius: var(--base-rhythm);
+ margin-bottom: var(--tree-gap);
+}
+
+.source-file__toc-range-header {
+ padding: var(--base-rhythm);
+}
+
+.source-file__toc-range-node {
+ border-top: 2px solid var(--color-bg-main);
+}
+
+.source-file__toc-node {
+ border-top: 1px solid var(--color-border);
+ margin-bottom: 2rem;
+}
+
+/* SDOC-NODE in SOURCE */
+
+.source-file__requirement {
+ position: relative;
+ padding: var(--base-rhythm) 0;
+ transition: background-color 0.3s ease-in, border-color 0.3s ease-in;
+ font-size: var(--font-size-xsm);
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+}
+
+.source-file__requirement-links {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+ margin-top: var(--base-rhythm);
+}
+
+.source-file__requirement-info {
+ word-break: break-word;
+}
+
+.source-file__requirement-uid {
+ display: block;
+ position: relative;
+ font-weight: bold;
+ word-break: break-word;
+}
+
+.source-file__requirement details {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 0.25rem;
+}
+
+.source-file__requirement summary {
+ list-style: none;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ position: relative;
+ gap: var(--base-rhythm);
+ align-items: flex-start;
+}
+
+.source-file__requirement summary::-webkit-details-marker {
+ display: none;
+}
+
+.source-file__requirement summary::after {
+ content: "➕";
+ user-select: none;
+ padding: calc(var(--base-rhythm) / 2);
+ margin-left: auto;
+ transition: transform 0.2s;
+ font-size: 8px;
+ color: var(--color-link);
+}
+
+.source-file__requirement:hover summary::after {
+ color: var(--color-hover);
+}
+
+.source-file__requirement details[open] summary::after {
+ content: "➖";
+}
+
+.source-file__requirement-header {
+ display: flex;
+ gap: var(--base-rhythm);
+ align-items: flex-start; /* to push action icon to top */
+}
+
+/* requirement_file */
+
+[data-viewtype="source-file"] .requirement_file li {
+ position: relative;
+}
+
+[data-viewtype="source-file"] .requirement_file li > a,
+[data-viewtype="source-file"] .requirement_file li > span {
+ display: inline-block;
+ padding: .15rem .25rem .15rem 0;
+ line-height: 1;
+}
+
+[data-viewtype="source-file"] .current_file_pseudolink {
+ font-weight: bold;
+ color: #808080;
+}
+
+/* CODE */
+
+.source-file__source {
+ /* position: relative; */
+ position: absolute;
+ inset: 0px;
+ left: var(--tree-gap);
+ overflow: auto;
+
+ padding: var(--tree-gap) 0 calc(var(--tree-gap)*10);
+ transition: box-shadow 0.3s ease-in;
+}
+
+.source-file__source .sdoc-table_key_value {
+ /* font-size: var(--font-size-sm); */
+ font-size: 14px;
+ min-width: 100%;
+ margin-bottom: var(--tree-gap);
+}
+
+.source {
+ display: grid;
+ grid-template-columns:
+ minmax(min-content, max-content)
+ minmax(0, 1fr); /* issue#1370 https://css-tricks.com/preventing-a-grid-blowout/ */
+ gap: 0 0;
+ place-items: stretch stretch;
+ transition: transform 0.3s ease-in;
+ position: relative;
+
+ min-width: 100%;
+ width: max-content;
+
+ font-size: 14px;
+ z-index: 1;
+}
+
+.source_highlight {
+ position: absolute;
+ left: 0;
+ right: 0;
+ background-color: var(--color-highlight);
+ z-index: -1;
+ transition: height 0.3s ease-in, top 0.3s ease-in;
+}
+
+/* source__range */
+
+.source__range {
+ grid-column: 1 / -1;
+ display: contents;
+}
+
+.source__range-closer {
+ grid-column: 1 / -1;
+ /* margin-bottom: var(--tree-gap); */
+ margin-bottom: var(--base-padding);
+}
+
+.source__range-closer-label {
+ display: flex;
+ border-radius: 0 0 6px 6px;
+ column-gap: calc(var(--base-rhythm)* 1);
+ background-color: var(--color-highlight-secondary);
+ padding: var(--base-rhythm);
+}
+
+.source__range-closer-label .source__range-definition::before {
+ content: 'End of';
+ display: inline-block;
+ margin-right: 6px;
+}
+
+.focus .source__range:not(.active),
+.focus .source__range-closer:not(.active) {
+ display: none;
+}
+
+.source__range-cell {
+ background-color: var(--color-highlight-secondary);
+}
+
+.source__range-header {
+ grid-column: 1 / -1;
+ background-color: var(--color-highlight-secondary);
+ padding: var(--base-rhythm);
+ margin-top: var(--tree-gap);
+ border-top-left-radius: var(--base-rhythm);
+}
+
+.source__range-button {
+ display: flex;
+ flex-direction: column;
+ align-items: stretch;
+ justify-content: center;
+ height: 100%;
+}
+
+.source__range-banner {
+ padding: 0 1rem 1rem 0;
+}
+
+.source__range.collapsed .source__range-banner {
+ display: none;
+}
+
+ul.source__range-titles-list {
+ margin: var(--base-rhythm);
+ list-style-type: none;
+}
+
+.source__range.collapsed .source__range-titles-list {
+ display: block;
+}
+
+.source__range.expanded .source__range-titles-list {
+ display: none;
+}
+
+.source__range-title-icon {
+ cursor: help;
+}
+
+/* sdoc-node-content */
+
+.source__range-banner sdoc-node-content[node-view="table"] sdoc-node-field-label {
+ background-color: var(--requirement-bg-light-color);
+}
+
+/* source__range-handler */
+
+.source__range-handler {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ height: 100%;
+ color: var(--color-link);
+}
+
+.source__range-handler:hover {
+ color: var(--color-hover);
+}
+
+.source__range .source__range-handler .expanded,
+.source__range.expanded .source__range-handler .collapsed {
+ display: none;
+}
+
+.source__range .source__range-handler .collapsed,
+.source__range.expanded .source__range-handler .expanded {
+ display: unset;
+}
+
+/* source__line */
+
+.source__line {
+ grid-column: 1 / -1;
+ display: contents;
+}
+
+.source.coverage .source__line.covered > div {
+ background: rgba(75, 255, 0, 0.2);
+}
+
+.source__line.highlighted > div {
+ background: var(--color-highlight) !important;
+}
+
+/* line-number */
+
+.source__line-number {
+ grid-column: 1 / 2;
+ padding: 0.25rem 1rem 0.25rem 2rem;
+ text-align: right;
+ border-bottom: var(--source-line);
+ color: var(--color-fg-secondary);
+ background: var(--color-bg-contrast);
+ user-select: none;
+ position: relative;
+}
+
+/* line content */
+
+.source__line-content {
+ grid-column: 2 / 3;
+ padding: 0.25rem 1rem 0.25rem .5rem;
+ border-bottom: var(--source-line);
+ border-left: var(--source-line);
+ background: var(--color-bg-contrast);
+}
+
+/* pointers */
+
+.source__range-pointer {
+ display: inline-block;
+ padding-left: calc(var(--base-rhythm)* 1);
+ padding-right: calc(var(--base-rhythm)* 1);
+ border-radius: 6px;
+}
+
+.source__range-pointer.active {
+ background-color: var(--color-highlight) !important;
+ color: var(--color-fg-contrast) !important;
+}
+
+.focus .source__range-pointer.active {
+ outline: solid 3px yellow;
+}
+
+.source__range-pointer .source__range-pointer_description {
+ font-weight: normal;
+ word-break: break-word;
+}
+
+.source__range-definition {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 100%;
+ min-width: 0;
+ display: inline-block;
+}
+
+/* Pygments */
+
+.highlight {
+ background: transparent !important;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/table_vew.css b/tests/fuzz/_incremental/30_pusher_example/css/table_vew.css
new file mode 100644
index 0000000..263332e
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/table_vew.css
@@ -0,0 +1,79 @@
+/* ultimate table view */
+
+.content-view-table {
+ border-collapse: collapse;
+ width: 100%;
+ background-color: var(--color-bg-contrast);
+}
+
+/* .content-view-table td,
+.content-view-table th, */
+.content-view-th,
+.content-view-td {
+ padding: .5rem 1rem;
+ border: 1px solid #666;
+ vertical-align: top;
+}
+
+.content-view-th {
+ text-align: left;
+ text-transform: uppercase;
+ background-color: var(--color-border);
+ font-size: .85em;
+ font-weight: bold;
+}
+
+.content-view-td-type,
+.content-view-td-meta {
+ background-color: var(--color-bg-main);
+ font-size: .85em;
+}
+
+.content-view-td-type {
+ background-color: var(--color-bg-main);
+ text-align: left;
+ font-weight: normal;
+ text-transform: uppercase;
+}
+
+.content-view-table div.document {
+ /* TODO */
+ display: block;
+ max-width: 900px;
+}
+
+.content-view-table p:first-child {
+ margin-top: 0;
+}
+
+.content-view-table p:last-child {
+ margin-bottom: 0;
+}
+
+.content-view-td:empty {
+ width: 1%;
+}
+
+.content-view-td-content:not(:empty) {
+ min-width: 333px;
+ width: 30%;
+}
+
+.content-view-td-title:not(:empty) {
+ font-weight: bold;
+ min-width: 264px;
+}
+
+.content-view-td-related:not(:empty) {
+ min-width: 264px;
+}
+
+.content-view-td-related,
+.content-view-td-related > ul.requirement__link {
+ font-size: .85rem;
+ margin-top: 0;
+}
+
+.content-view-td-related > ul.requirement__link:last-child {
+ margin-bottom: 0;
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/traceability_matrix.css b/tests/fuzz/_incremental/30_pusher_example/css/traceability_matrix.css
new file mode 100644
index 0000000..6c9c279
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/traceability_matrix.css
@@ -0,0 +1,148 @@
+.traceability_matrix {
+ --traceability_matrix-thead-height: calc(4 * var(--base-rhythm));
+
+
+ display: table;
+ border-collapse: collapse;
+}
+
+.traceability_matrix__anchor {
+ /* for Fixed Headers + Section Anchors */
+ scroll-snap-margin-top: var(--base-gap);
+ scroll-margin-top: var(--base-gap);
+}
+
+.traceability_matrix .traceability_matrix__thead {
+ position: sticky;
+ top: calc(-1 * var(--traceability_matrix-thead-height));
+ z-index: 2;
+ background-color: var(--color-bg-main);
+}
+
+.traceability_matrix .traceability_matrix__thead::before {
+ content: '';
+ position: absolute;
+ top: calc(-1 * var(--base-gap));
+ left: calc(-1 * var(--base-gap));
+ right: calc(-1 * var(--base-gap));
+ bottom: 0;
+ z-index: 0;
+ background-color: var(--color-bg-main);
+}
+
+.traceability_matrix__thead th {
+ height: var(--traceability_matrix-thead-height);
+ text-align: left;
+ vertical-align: middle;
+ line-height: 1;
+ position: relative;
+ background-color: var(--color-bg-secondary-invert);
+ padding-left: var(--base-rhythm);
+ border: 1px solid var(--color-border);
+}
+
+.traceability_matrix td {
+ border: 1px solid var(--color-border);
+ background-color: var(--color-bg-contrast);
+ vertical-align: top;
+}
+
+td.traceability_matrix__document {
+ position: sticky;
+ padding: 0;
+ top: 0;
+ z-index: 1;
+}
+
+.traceability_matrix__placeholder {
+ padding: var(--base-rhythm);
+ text-align: center;
+ font-size: var(--font-size-sm);
+}
+
+td.traceability_matrix__null {
+ height: calc(4 * var(--base-rhythm));
+ background-color: var(--color-bg-main);
+ border: none;
+}
+
+.traceability_matrix__document_line {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ column-gap: calc(2 * var(--base-rhythm));
+ font-size: var(--font-size-l);
+ font-weight: 600;
+ line-height: 1.2;
+ width: 100%;
+
+ padding: var(--base-rhythm);
+ padding-top: calc(1.5 * var(--base-rhythm));
+
+ border-bottom: 1px solid var(--color-border);
+}
+
+.traceability_matrix__document_stat {
+ margin-left: auto;
+}
+
+.traceability_matrix__requirement {
+ display: block;
+ position: relative;
+ font-size: var(--font-size-sm);
+ line-height: 1.2;
+ padding: var(--base-rhythm);
+}
+
+.traceability_matrix__file {
+ position: relative;
+ font-size: var(--font-size-sm);
+ line-height: 1.2;
+ margin-top: var(--base-rhythm);
+ margin-bottom: var(--base-rhythm);
+ padding-right: var(--base-rhythm);
+}
+
+.traceability_matrix__file a {
+ /* overflow-wrap: break-word; */
+ overflow-wrap: anywhere;
+ color: var(--color-link);
+ text-decoration: none;
+}
+
+.traceability_matrix__file a:hover {
+ color: var(--color-hover);
+}
+
+[with_relation] {
+ padding-left: calc(4 * var(--base-rhythm));
+}
+
+[with_relation]::before {
+ content: '';
+ font-size: var(--font-size);
+ line-height: 1;
+ position: absolute;
+ left: var(--base-rhythm);
+}
+
+.traceability_matrix__requirement[with_relation]::before {
+ top: var(--base-rhythm);
+}
+
+.traceability_matrix__file[with_relation]::before {
+ top: 0
+}
+
+/* ← → */
+[with_relation="parent"]::before {
+ content: '→';
+}
+
+[with_relation="child"]::before {
+ content: '←';
+}
+
+[with_relation="file"]::before {
+ content: '→';
+}
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/tree(not_in_use).css b/tests/fuzz/_incremental/30_pusher_example/css/tree(not_in_use).css
new file mode 100644
index 0000000..acd2a13
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/tree(not_in_use).css
@@ -0,0 +1,146 @@
+.std-tree {
+ --tree-font-size: 16px;
+ --tree-line-height: calc(var(--tree-font-size)*1.25);
+ --tree-level-padding: calc(var(--tree-font-size)*1.5);
+ --tree-cell-padding: calc(var(--tree-font-size)*0.5);
+
+ --tree-level-line-width: 1px;
+
+ --tree-color-line: #808080;
+ --tree-color-fg: var(--color-fg-main, #444444);
+ --tree-color-bg: var(--color-bg-main, #F2F5F9);
+ --tree-color-row-hover-bg: var(--color-bg-contrast, #FFFFFF);
+ --tree-btn-bg-color: var(--color-bg-contrast, #FFFFFF);
+
+ --tree-half-sell-height: calc( var(--tree-line-height)/2 + var(--tree-cell-padding) );
+
+ --tree-ico-size: var(--tree-font-size, 1rem);
+
+ --tree-max-width: 800px;
+}
+
+
+/* tree */
+.std-tree {
+ font-size: var(--tree-font-size, 1rem);
+ line-height: var(--tree-line-height, 1.25);
+ color: var(--tree-color-fg, #444444);
+
+ position: relative;
+ width: -moz-fit-content;
+ width: fit-content;
+ /* margin: 0 auto; */
+}
+
+.std-tree ul {
+ list-style: none;
+ width: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.std-tree li {
+ position: relative;
+ padding-left: var(--tree-level-padding);
+}
+
+.std-tree ul ul > li::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ top: calc(var(--tree-ico-size)*(-0.5));
+ height: 100%;
+ border-left: 1px solid var(--tree-color-line);
+}
+
+.std-tree ul > li:last-child::before {
+ height: calc(var(--tree-ico-size) + var(--tree-cell-padding));
+}
+
+.std-tree_ico {
+ display: inline-flex;
+ align-items: center;
+
+ position: absolute;
+ left: 0;
+ top: calc(var(--tree-cell-padding));
+}
+
+ ul ul .std-tree_ico::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ right: 100%;
+ border-bottom: 1px solid var(--tree-color-line);
+ }
+
+ .std-tree_ico svg {
+ display: inline-block;
+ width: var(--tree-ico-size);
+ height: var(--tree-ico-size);
+
+ fill: var(--tree-color-line);
+ }
+
+ .std-tree_row {
+ padding-top: var(--tree-cell-padding);
+ padding-bottom: var(--tree-cell-padding);
+ padding-left: var(--tree-cell-padding);
+
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .std-tree_folder {
+ font-weight: bold;
+ display: flex;
+ }
+
+ .std-tree_file {
+ order: 1;
+ flex-grow: 1;
+ }
+
+ .std-tree_file__title {
+ font-size: 1.25em;
+ color: #000;
+ transition: color .2s ease;
+ }
+
+ .std-tree_file-link:hover .std-tree_file__title {
+ color: var(--color-fg-accent);
+ }
+
+ .std-tree_file__name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: var(--color-fg-secondary);
+ margin-top: 0.25rem;
+ }
+
+ .std-tree_desc {
+ position: relative;
+ top: -2px;
+ color: #000;
+ }
+
+ .std-tree_name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: #666;
+ }
+
+ .std-tree_aside {
+ width: -moz-fit-content;
+ width: fit-content;
+ padding-left: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ order: 3;
+ }
+
+ .std-tree_file-link {
+ position: relative;
+ top: -2px;
+ }
diff --git a/tests/fuzz/_incremental/30_pusher_example/css/tree.css b/tests/fuzz/_incremental/30_pusher_example/css/tree.css
new file mode 100644
index 0000000..acd2a13
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/css/tree.css
@@ -0,0 +1,146 @@
+.std-tree {
+ --tree-font-size: 16px;
+ --tree-line-height: calc(var(--tree-font-size)*1.25);
+ --tree-level-padding: calc(var(--tree-font-size)*1.5);
+ --tree-cell-padding: calc(var(--tree-font-size)*0.5);
+
+ --tree-level-line-width: 1px;
+
+ --tree-color-line: #808080;
+ --tree-color-fg: var(--color-fg-main, #444444);
+ --tree-color-bg: var(--color-bg-main, #F2F5F9);
+ --tree-color-row-hover-bg: var(--color-bg-contrast, #FFFFFF);
+ --tree-btn-bg-color: var(--color-bg-contrast, #FFFFFF);
+
+ --tree-half-sell-height: calc( var(--tree-line-height)/2 + var(--tree-cell-padding) );
+
+ --tree-ico-size: var(--tree-font-size, 1rem);
+
+ --tree-max-width: 800px;
+}
+
+
+/* tree */
+.std-tree {
+ font-size: var(--tree-font-size, 1rem);
+ line-height: var(--tree-line-height, 1.25);
+ color: var(--tree-color-fg, #444444);
+
+ position: relative;
+ width: -moz-fit-content;
+ width: fit-content;
+ /* margin: 0 auto; */
+}
+
+.std-tree ul {
+ list-style: none;
+ width: 100%;
+ padding: 0;
+ margin: 0;
+}
+
+.std-tree li {
+ position: relative;
+ padding-left: var(--tree-level-padding);
+}
+
+.std-tree ul ul > li::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ top: calc(var(--tree-ico-size)*(-0.5));
+ height: 100%;
+ border-left: 1px solid var(--tree-color-line);
+}
+
+.std-tree ul > li:last-child::before {
+ height: calc(var(--tree-ico-size) + var(--tree-cell-padding));
+}
+
+.std-tree_ico {
+ display: inline-flex;
+ align-items: center;
+
+ position: absolute;
+ left: 0;
+ top: calc(var(--tree-cell-padding));
+}
+
+ ul ul .std-tree_ico::before {
+ content: '';
+ position: absolute;
+ left: calc(var(--tree-ico-size)*0.5 - var(--tree-level-padding));
+ right: 100%;
+ border-bottom: 1px solid var(--tree-color-line);
+ }
+
+ .std-tree_ico svg {
+ display: inline-block;
+ width: var(--tree-ico-size);
+ height: var(--tree-ico-size);
+
+ fill: var(--tree-color-line);
+ }
+
+ .std-tree_row {
+ padding-top: var(--tree-cell-padding);
+ padding-bottom: var(--tree-cell-padding);
+ padding-left: var(--tree-cell-padding);
+
+ display: flex;
+ justify-content: space-between;
+ }
+
+ .std-tree_folder {
+ font-weight: bold;
+ display: flex;
+ }
+
+ .std-tree_file {
+ order: 1;
+ flex-grow: 1;
+ }
+
+ .std-tree_file__title {
+ font-size: 1.25em;
+ color: #000;
+ transition: color .2s ease;
+ }
+
+ .std-tree_file-link:hover .std-tree_file__title {
+ color: var(--color-fg-accent);
+ }
+
+ .std-tree_file__name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: var(--color-fg-secondary);
+ margin-top: 0.25rem;
+ }
+
+ .std-tree_desc {
+ position: relative;
+ top: -2px;
+ color: #000;
+ }
+
+ .std-tree_name {
+ font-size: 0.85rem;
+ line-height: 1.2;
+ color: #666;
+ }
+
+ .std-tree_aside {
+ width: -moz-fit-content;
+ width: fit-content;
+ padding-left: 20px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ order: 3;
+ }
+
+ .std-tree_file-link {
+ position: relative;
+ top: -2px;
+ }
diff --git a/tests/fuzz/_incremental/30_pusher_example/test_case.py b/tests/fuzz/_incremental/30_pusher_example/test_case.py
new file mode 100644
index 0000000..af99bfd
--- /dev/null
+++ b/tests/fuzz/_incremental/30_pusher_example/test_case.py
@@ -0,0 +1,30 @@
+import os
+
+from html2pdf4doc.main_fuzzer import fuzz_test, rewrite_js_path_to_local, \
+ MutationType
+from tests.fuzz.conftest import create_build_folder, FuzzConfig, create_failed_mutants_folder
+
+PATH_TO_THIS_FOLDER = os.path.dirname(__file__)
+
+def test(fuzz_config: FuzzConfig):
+ build_folder = create_build_folder(PATH_TO_THIS_FOLDER)
+
+ path_to_system_under_test = os.path.join(
+ build_folder,
+ "case_001.html"
+ )
+
+ with open(path_to_system_under_test, "r", encoding="utf-8") as f:
+ html_text = f.read()
+ html_text = rewrite_js_path_to_local(html_text)
+ with open(path_to_system_under_test, "w", encoding="utf-8") as f:
+ f.write(html_text)
+
+ fuzz_test(
+ path_to_input_file=path_to_system_under_test,
+ path_to_root=build_folder,
+ path_to_failed_mutants_dir=create_failed_mutants_folder(PATH_TO_THIS_FOLDER),
+ total_mutations=fuzz_config.total_mutations,
+ mutation_type=MutationType.INCREMENTAL,
+ strict_mode_2=fuzz_config.strict_mode_2,
+ )
diff --git a/tests/fuzz/conftest.py b/tests/fuzz/conftest.py
index 77ffaf4..38dcd62 100644
--- a/tests/fuzz/conftest.py
+++ b/tests/fuzz/conftest.py
@@ -6,6 +6,8 @@
import pytest
+from html2pdf4doc import PATH_TO_HTML2PDF4DOC_JS
+
PATH_TO_TESTS_FUZZ_FOLDER = os.path.dirname(__file__)
@@ -55,6 +57,8 @@ def create_build_folder(test_folder: str) -> str:
shutil.copytree(test_folder, build_folder)
+ shutil.copy(PATH_TO_HTML2PDF4DOC_JS, build_folder)
+
return build_folder
diff --git a/tests/integration/20_fuzz_integration/test.itest b/tests/integration/20_fuzz_integration/test.itest
index d261940..850f444 100644
--- a/tests/integration/20_fuzz_integration/test.itest
+++ b/tests/integration/20_fuzz_integration/test.itest
@@ -4,5 +4,6 @@
RUN: mkdir -p %project_root/build/tests_integration_fuzz/
RUN: cp -rv %project_root/tests/fuzz/01_strictdoc_guide_202510 %project_root/build/tests_integration_fuzz/
-RUN: PYTHONPATH=%project_root python -m html2pdf4doc.main_fuzzer %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510 %T/ --total-mutations 1 | filecheck %s --dump-input=fail
+RUN: PYTHONPATH=%project_root python -m html2pdf4doc.main_fuzzer %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510 %T/ --total-mutations 1 --mutations=random | filecheck %s --dump-input=fail
+RUN: PYTHONPATH=%project_root python -m html2pdf4doc.main_fuzzer %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510/strictdoc/docs/strictdoc_01_user_guide-PDF.html %project_root/build/tests_integration_fuzz/01_strictdoc_guide_202510 %T/ --total-mutations 1 --mutations=incremental | filecheck %s --dump-input=fail
CHECK: html2pdf4doc_fuzzer: finished ✅ — Success rate: 1/1 (100.0%)