@localix-ai/flowdown 0.0.0-stage → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -2
- package/dist/browser/file-actions.js +80 -0
- package/dist/browser/file-actions.js.map +1 -0
- package/dist/core/block-facts.js +72 -0
- package/dist/core/block-facts.js.map +1 -0
- package/dist/core/blocks.d.ts +25 -0
- package/dist/core/blocks.js +464 -0
- package/dist/core/blocks.js.map +1 -0
- package/dist/core/bounded-cache.js +42 -0
- package/dist/core/bounded-cache.js.map +1 -0
- package/dist/core/continues.js +15 -0
- package/dist/core/continues.js.map +1 -0
- package/dist/core/dollars.d.ts +12 -0
- package/dist/core/dollars.js +88 -0
- package/dist/core/dollars.js.map +1 -0
- package/dist/core/fence-scan.js +62 -0
- package/dist/core/fence-scan.js.map +1 -0
- package/dist/core/file-tree-parse.d.ts +26 -0
- package/dist/core/file-tree-parse.js +51 -0
- package/dist/core/file-tree-parse.js.map +1 -0
- package/dist/core/forms-html.js +63 -0
- package/dist/core/forms-html.js.map +1 -0
- package/dist/core/forms.d.ts +28 -0
- package/dist/core/forms.js +23 -0
- package/dist/core/forms.js.map +1 -0
- package/dist/core/headings.d.ts +11 -0
- package/dist/core/headings.js +74 -0
- package/dist/core/headings.js.map +1 -0
- package/dist/core/heal.d.ts +11 -0
- package/dist/core/heal.js +220 -0
- package/dist/core/heal.js.map +1 -0
- package/dist/core/load-once.js +23 -0
- package/dist/core/load-once.js.map +1 -0
- package/dist/core/math-delimiters.js +33 -0
- package/dist/core/math-delimiters.js.map +1 -0
- package/dist/core/math-syntax.js +56 -0
- package/dist/core/math-syntax.js.map +1 -0
- package/dist/core/prose.d.ts +10 -0
- package/dist/core/prose.js +77 -0
- package/dist/core/prose.js.map +1 -0
- package/dist/core/remark-answer-blocks.d.ts +5 -0
- package/dist/core/remark-answer-blocks.js +172 -0
- package/dist/core/remark-answer-blocks.js.map +1 -0
- package/dist/core/remark-answer-containers.js +299 -0
- package/dist/core/remark-answer-containers.js.map +1 -0
- package/dist/core/sanitize-schema.d.ts +18 -0
- package/dist/core/sanitize-schema.js +62 -0
- package/dist/core/sanitize-schema.js.map +1 -0
- package/dist/core/syntax.d.ts +8 -0
- package/dist/core/syntax.js +32 -0
- package/dist/core/syntax.js.map +1 -0
- package/dist/dialect.d.ts +92 -0
- package/dist/dialect.js +176 -0
- package/dist/dialect.js.map +1 -0
- package/dist/document/fence.d.ts +25 -0
- package/dist/document/fence.js +102 -0
- package/dist/document/fence.js.map +1 -0
- package/dist/document/index.d.ts +46 -0
- package/dist/document/index.js +66 -0
- package/dist/document/index.js.map +1 -0
- package/dist/document/table.d.ts +11 -0
- package/dist/document/table.js +35 -0
- package/dist/document/table.js.map +1 -0
- package/dist/dom/index.d.ts +21 -0
- package/dist/dom/index.js +141 -0
- package/dist/dom/index.js.map +1 -0
- package/dist/dom/patch.js +104 -0
- package/dist/dom/patch.js.map +1 -0
- package/dist/element/index.d.ts +35 -0
- package/dist/element/index.js +64 -0
- package/dist/element/index.js.map +1 -0
- package/dist/engine/blocks.js +785 -0
- package/dist/engine/blocks.js.map +1 -0
- package/dist/engine/entities.js +83 -0
- package/dist/engine/entities.js.map +1 -0
- package/dist/engine/entity-core.js +9 -0
- package/dist/engine/entity-core.js.map +1 -0
- package/dist/engine/entity-table.js +9 -0
- package/dist/engine/entity-table.js.map +1 -0
- package/dist/engine/html.d.ts +7 -0
- package/dist/engine/html.js +207 -0
- package/dist/engine/html.js.map +1 -0
- package/dist/engine/index.d.ts +7 -0
- package/dist/engine/index.js +74 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/inlines.js +887 -0
- package/dist/engine/inlines.js.map +1 -0
- package/dist/engine/types.d.ts +109 -0
- package/dist/engine/url.d.ts +11 -0
- package/dist/engine/url.js +16 -0
- package/dist/engine/url.js.map +1 -0
- package/dist/engine/visit.d.ts +10 -0
- package/dist/engine/visit.js +29 -0
- package/dist/engine/visit.js.map +1 -0
- package/dist/highlight/highlight.d.ts +4 -0
- package/dist/highlight/highlight.js +144 -0
- package/dist/highlight/highlight.js.map +1 -0
- package/dist/highlight/index.d.ts +4 -0
- package/dist/highlight/index.js +18 -0
- package/dist/highlight/index.js.map +1 -0
- package/dist/html/index.d.ts +4 -0
- package/dist/html/index.js +544 -0
- package/dist/html/index.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +13 -0
- package/dist/math/index.d.ts +17 -0
- package/dist/math/index.js +20 -0
- package/dist/math/index.js.map +1 -0
- package/dist/math/typeset.d.ts +12 -0
- package/dist/math/typeset.js +74 -0
- package/dist/math/typeset.js.map +1 -0
- package/dist/mermaid/diagram.d.ts +8 -0
- package/dist/mermaid/diagram.js +114 -0
- package/dist/mermaid/diagram.js.map +1 -0
- package/dist/mermaid/drawing.js +139 -0
- package/dist/mermaid/drawing.js.map +1 -0
- package/dist/mermaid/icons.js +16 -0
- package/dist/mermaid/icons.js.map +1 -0
- package/dist/mermaid/index.d.ts +13 -0
- package/dist/mermaid/index.js +3 -0
- package/dist/mermaid/loader.d.ts +5 -0
- package/dist/mermaid/loader.js +18 -0
- package/dist/mermaid/loader.js.map +1 -0
- package/dist/mermaid/look.d.ts +16 -0
- package/dist/mermaid/look.js +167 -0
- package/dist/mermaid/look.js.map +1 -0
- package/dist/mermaid/normalize-svg.js +44 -0
- package/dist/mermaid/normalize-svg.js.map +1 -0
- package/dist/mermaid/renderer.d.ts +22 -0
- package/dist/mermaid/renderer.js +132 -0
- package/dist/mermaid/renderer.js.map +1 -0
- package/dist/mermaid/viewer.js +309 -0
- package/dist/mermaid/viewer.js.map +1 -0
- package/dist/prompt/index.d.ts +19 -0
- package/dist/prompt/index.js +54 -0
- package/dist/prompt/index.js.map +1 -0
- package/dist/react/callout.d.ts +9 -0
- package/dist/react/callout.js +12 -0
- package/dist/react/callout.js.map +1 -0
- package/dist/react/code-block.d.ts +18 -0
- package/dist/react/code-block.js +94 -0
- package/dist/react/code-block.js.map +1 -0
- package/dist/react/context.d.ts +18 -0
- package/dist/react/context.js +17 -0
- package/dist/react/context.js.map +1 -0
- package/dist/react/draw.d.ts +2 -0
- package/dist/react/draw.js +17 -0
- package/dist/react/draw.js.map +1 -0
- package/dist/react/file-tree.d.ts +16 -0
- package/dist/react/file-tree.js +69 -0
- package/dist/react/file-tree.js.map +1 -0
- package/dist/react/growing-code.js +36 -0
- package/dist/react/growing-code.js.map +1 -0
- package/dist/react/helpers.d.ts +6 -0
- package/dist/react/helpers.js +17 -0
- package/dist/react/helpers.js.map +1 -0
- package/dist/react/icons.js +23 -0
- package/dist/react/icons.js.map +1 -0
- package/dist/react/labels.js +9 -0
- package/dist/react/labels.js.map +1 -0
- package/dist/react/markdown.d.ts +78 -0
- package/dist/react/markdown.js +206 -0
- package/dist/react/markdown.js.map +1 -0
- package/dist/react/render.d.ts +8 -0
- package/dist/react/render.js +41 -0
- package/dist/react/render.js.map +1 -0
- package/dist/react/scrolls.js +62 -0
- package/dist/react/scrolls.js.map +1 -0
- package/dist/react/table-rows.js +66 -0
- package/dist/react/table-rows.js.map +1 -0
- package/dist/react/table.js +22 -0
- package/dist/react/table.js.map +1 -0
- package/dist/react/tabs.d.ts +25 -0
- package/dist/react/tabs.js +58 -0
- package/dist/react/tabs.js.map +1 -0
- package/dist/react/use-smooth-text.d.ts +6 -0
- package/dist/react/use-smooth-text.js +157 -0
- package/dist/react/use-smooth-text.js.map +1 -0
- package/dist/react/use-stage.d.ts +9 -0
- package/dist/react/use-stage.js +57 -0
- package/dist/react/use-stage.js.map +1 -0
- package/dist/remark.d.ts +20 -0
- package/dist/remark.js +10 -0
- package/dist/render/factory.d.ts +15 -0
- package/dist/render/labels.d.ts +46 -0
- package/dist/render/labels.js +46 -0
- package/dist/render/labels.js.map +1 -0
- package/dist/render/tree.js +314 -0
- package/dist/render/tree.js.map +1 -0
- package/dist/render/view.d.ts +58 -0
- package/dist/render/view.js +306 -0
- package/dist/render/view.js.map +1 -0
- package/dist/render/views.d.ts +16 -0
- package/dist/render/views.js +261 -0
- package/dist/render/views.js.map +1 -0
- package/dist/render/vnode.d.ts +21 -0
- package/dist/render/vnode.js +194 -0
- package/dist/render/vnode.js.map +1 -0
- package/dist/static/index.d.ts +28 -0
- package/dist/static/index.js +27 -0
- package/dist/static/index.js.map +1 -0
- package/dist/stream.d.ts +12 -0
- package/dist/stream.js +3 -0
- package/dist/styles.css +1362 -0
- package/dist/tui/code.d.ts +5 -0
- package/dist/tui/code.js +240 -0
- package/dist/tui/code.js.map +1 -0
- package/dist/tui/index.d.ts +54 -0
- package/dist/tui/index.js +99 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/math.js +242 -0
- package/dist/tui/math.js.map +1 -0
- package/dist/tui/printable.d.ts +12 -0
- package/dist/tui/printable.js +31 -0
- package/dist/tui/printable.js.map +1 -0
- package/dist/tui/render.d.ts +12 -0
- package/dist/tui/render.js +524 -0
- package/dist/tui/render.js.map +1 -0
- package/dist/tui/style.d.ts +35 -0
- package/dist/tui/style.js +77 -0
- package/dist/tui/style.js.map +1 -0
- package/dist/tui/table.js +73 -0
- package/dist/tui/table.js.map +1 -0
- package/dist/tui/width.d.ts +2 -0
- package/dist/tui/width.js +133 -0
- package/dist/tui/width.js.map +1 -0
- package/dist/tui/wrap.d.ts +8 -0
- package/dist/tui/wrap.js +191 -0
- package/dist/tui/wrap.js.map +1 -0
- package/package.json +128 -4
package/dist/styles.css
ADDED
|
@@ -0,0 +1,1362 @@
|
|
|
1
|
+
/* flowdown styles. Import once: `import "@localix-ai/flowdown/styles.css"`. */
|
|
2
|
+
/* tokens.css */
|
|
3
|
+
/*
|
|
4
|
+
* flowdown tokens. Every colour, font and radius the renderer draws with is one of these,
|
|
5
|
+
* so a page restyles the whole of it by setting them:
|
|
6
|
+
*
|
|
7
|
+
* .flowdown { --fd-fg: var(--foreground); --fd-bg: var(--background); }
|
|
8
|
+
*
|
|
9
|
+
* The tokens sit at zero specificity (`:where`), so any rule that sets them wins. The rest of the
|
|
10
|
+
* package is scoped under `.flowdown`: a page restyles an element with a selector that starts
|
|
11
|
+
* there too. It is not in a cascade layer on purpose: a page's own `button` or `ul` reset, in no
|
|
12
|
+
* layer, would then win over the tabs and the lists.
|
|
13
|
+
* Light and dark are one list, written with `light-dark()`: the renderer follows the colour scheme
|
|
14
|
+
* of the page around it (`color-scheme: dark`, a `.dark` class or `data-theme="dark"` on an
|
|
15
|
+
* ancestor or on the root itself), and a page that has no dark mode stays light.
|
|
16
|
+
*/
|
|
17
|
+
:where(.flowdown) {
|
|
18
|
+
/* Text, from the body copy to the quietest annotation. */
|
|
19
|
+
--fd-fg: light-dark(#1f2328, #e6edf3);
|
|
20
|
+
--fd-fg-soft: light-dark(#4b535d, #b1bac4);
|
|
21
|
+
--fd-fg-faint: light-dark(#656d76, #8b949e);
|
|
22
|
+
/* The ground the Markdown sits on: diagrams mix their fills over it. Set it to your page's. */
|
|
23
|
+
--fd-bg: light-dark(#ffffff, #0d1117);
|
|
24
|
+
/* What shows through --fd-bg when it is translucent (a glass panel): the opaque colour under it.
|
|
25
|
+
Diagrams lay the ground over it once. Unset, white. */
|
|
26
|
+
--fd-border: light-dark(#d0d7de, #30363d);
|
|
27
|
+
--fd-border-subtle: light-dark(#e6e9ed, #21262d);
|
|
28
|
+
--fd-border-strong: light-dark(#afb8c1, #484f58);
|
|
29
|
+
/* A panel (a callout, a figure, a stat): the text colour at a few percent, right on any ground. */
|
|
30
|
+
--fd-veil: color-mix(in oklab, var(--fd-fg) 4.5%, transparent);
|
|
31
|
+
--fd-veil-strong: color-mix(in oklab, var(--fd-fg) 8%, transparent);
|
|
32
|
+
--fd-link: var(--fd-fg);
|
|
33
|
+
--fd-focus: light-dark(#0969da, #4493f8);
|
|
34
|
+
|
|
35
|
+
/* Status hues: the callouts' glyphs and the pros/cons marks, never a fill. */
|
|
36
|
+
--fd-info: light-dark(#0969da, #4493f8);
|
|
37
|
+
--fd-success: light-dark(#1a7f37, #3fb950);
|
|
38
|
+
--fd-important: light-dark(#8250df, #ab7df8);
|
|
39
|
+
--fd-warning: light-dark(#9a6700, #d29922);
|
|
40
|
+
--fd-danger: light-dark(#cf222e, #f85149);
|
|
41
|
+
|
|
42
|
+
/* Diagram series, in order. */
|
|
43
|
+
--fd-chart-1: light-dark(#0969da, #4493f8);
|
|
44
|
+
--fd-chart-2: light-dark(#1a7f37, #3fb950);
|
|
45
|
+
--fd-chart-3: light-dark(#bc4c00, #f0883e);
|
|
46
|
+
--fd-chart-4: light-dark(#8250df, #ab7df8);
|
|
47
|
+
--fd-chart-5: light-dark(#bf3989, #db61a2);
|
|
48
|
+
--fd-chart-6: light-dark(#1b7c83, #39c5cf);
|
|
49
|
+
--fd-chart-7: light-dark(#9a6700, #d29922);
|
|
50
|
+
--fd-chart-8: light-dark(#57606a, #8b949e);
|
|
51
|
+
|
|
52
|
+
/* Code: the block's ground and the highlighter's hues. */
|
|
53
|
+
--fd-code-bg: var(--fd-veil);
|
|
54
|
+
--fd-code-fg: var(--fd-fg);
|
|
55
|
+
--fd-code-comment: var(--fd-fg-faint);
|
|
56
|
+
--fd-code-keyword: light-dark(#cf222e, #ff7b72);
|
|
57
|
+
--fd-code-string: light-dark(#0a3069, #a5d6ff);
|
|
58
|
+
--fd-code-number: light-dark(#0550ae, #79c0ff);
|
|
59
|
+
--fd-code-function: light-dark(#8250df, #d2a8ff);
|
|
60
|
+
--fd-code-type: light-dark(#953800, #ffa657);
|
|
61
|
+
--fd-code-tag: light-dark(#116329, #7ee787);
|
|
62
|
+
|
|
63
|
+
--fd-font-heading: inherit;
|
|
64
|
+
--fd-font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
|
65
|
+
--fd-radius: 0.75rem;
|
|
66
|
+
--fd-radius-small: 0.375rem;
|
|
67
|
+
--fd-duration: 120ms;
|
|
68
|
+
/* What opens, turns or arrives: slower, and easing out so it settles instead of stopping. */
|
|
69
|
+
--fd-duration-slow: 200ms;
|
|
70
|
+
--fd-ease: cubic-bezier(0.2, 0, 0, 1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/*
|
|
74
|
+
* A bundler that builds for browsers older than `light-dark()` (Vite 8 does, with Lightning CSS)
|
|
75
|
+
* rewrites each colour above as `var(--lightningcss-light, …) var(--lightningcss-dark, …)` and
|
|
76
|
+
* sets that pair only where the CSS it reads declares `color-scheme`. On a page that declares
|
|
77
|
+
* none, both fallbacks applied and every colour was invalid. This makes light the default there,
|
|
78
|
+
* as it is for `light-dark()` itself; any `color-scheme` the bundler does read still wins.
|
|
79
|
+
*/
|
|
80
|
+
:where(:root) {
|
|
81
|
+
--lightningcss-dark: ;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
:where(.dark, [data-theme='dark']) :where(.flowdown),
|
|
85
|
+
:where(.flowdown[data-theme='dark']) {
|
|
86
|
+
color-scheme: dark;
|
|
87
|
+
}
|
|
88
|
+
:where(.light, [data-theme='light']) :where(.flowdown),
|
|
89
|
+
:where(.flowdown[data-theme='light']) {
|
|
90
|
+
color-scheme: light;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* markdown.css */
|
|
94
|
+
/* ─── Prose: GitHub Markdown, set for reading inside an interface ─── */
|
|
95
|
+
.flowdown {
|
|
96
|
+
width: 100%;
|
|
97
|
+
color: var(--fd-fg);
|
|
98
|
+
overflow-wrap: anywhere;
|
|
99
|
+
}
|
|
100
|
+
.flowdown > :first-child {
|
|
101
|
+
margin-top: 0;
|
|
102
|
+
}
|
|
103
|
+
.flowdown > :last-child {
|
|
104
|
+
margin-bottom: 0;
|
|
105
|
+
}
|
|
106
|
+
.flowdown p,
|
|
107
|
+
.flowdown ul,
|
|
108
|
+
.flowdown ol,
|
|
109
|
+
.flowdown blockquote,
|
|
110
|
+
.flowdown table {
|
|
111
|
+
margin: 0.65rem 0;
|
|
112
|
+
}
|
|
113
|
+
/* A heading belongs to the text BELOW it: more space above than under, so a section reads as
|
|
114
|
+
one group instead of a title floating between two. The scale is a chat reply's, not a page's —
|
|
115
|
+
a 1.5rem h1 inside a message outweighed everything around it, the header of the message
|
|
116
|
+
included. `balance` keeps a two-line heading from ending on one orphaned word. */
|
|
117
|
+
.flowdown h1,
|
|
118
|
+
.flowdown h2,
|
|
119
|
+
.flowdown h3,
|
|
120
|
+
.flowdown h4,
|
|
121
|
+
.flowdown h5,
|
|
122
|
+
.flowdown h6 {
|
|
123
|
+
margin: 1.5em 0 0.45em;
|
|
124
|
+
font-family: var(--fd-font-heading);
|
|
125
|
+
font-weight: 600;
|
|
126
|
+
line-height: 1.3;
|
|
127
|
+
letter-spacing: -0.015em;
|
|
128
|
+
text-wrap: balance;
|
|
129
|
+
}
|
|
130
|
+
.flowdown :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) {
|
|
131
|
+
margin-top: 0.6em;
|
|
132
|
+
}
|
|
133
|
+
/* An author's section number (`## 1.2 Title`): the outline position, set
|
|
134
|
+
quieter than the title it precedes. */
|
|
135
|
+
.flowdown .fd-section-number {
|
|
136
|
+
margin-right: 0.45em;
|
|
137
|
+
font-weight: 500;
|
|
138
|
+
font-variant-numeric: tabular-nums;
|
|
139
|
+
color: var(--fd-fg-faint);
|
|
140
|
+
}
|
|
141
|
+
.flowdown h1 {
|
|
142
|
+
font-size: 1.32rem;
|
|
143
|
+
}
|
|
144
|
+
.flowdown h2 {
|
|
145
|
+
font-size: 1.16rem;
|
|
146
|
+
}
|
|
147
|
+
.flowdown h3 {
|
|
148
|
+
font-size: 1.03rem;
|
|
149
|
+
}
|
|
150
|
+
/* Paragraphs avoid a lone last word. Not on the tail of a streaming reply: that paragraph is
|
|
151
|
+
the one still growing, and re-balancing its last lines on every token is a visible wobble. */
|
|
152
|
+
.flowdown :is(p, li) {
|
|
153
|
+
text-wrap: pretty;
|
|
154
|
+
}
|
|
155
|
+
.flowdown[data-streaming] > :last-child,
|
|
156
|
+
.flowdown[data-streaming] > :last-child :is(p, li, h1, h2, h3, h4, h5, h6) {
|
|
157
|
+
text-wrap: wrap;
|
|
158
|
+
}
|
|
159
|
+
/* Bold marks what a reader scans for; Inter's 700 turned a bolded phrase into a shout. */
|
|
160
|
+
.flowdown :is(strong, b) {
|
|
161
|
+
font-weight: 600;
|
|
162
|
+
}
|
|
163
|
+
/* Nested headings (`####`+): consistent with h1–h3, just smaller, instead of
|
|
164
|
+
browser defaults (no heading font, awkward margins). */
|
|
165
|
+
.flowdown h4 {
|
|
166
|
+
font-size: 1rem;
|
|
167
|
+
}
|
|
168
|
+
.flowdown h5 {
|
|
169
|
+
font-size: 0.9rem;
|
|
170
|
+
}
|
|
171
|
+
.flowdown h6 {
|
|
172
|
+
font-size: 0.85rem;
|
|
173
|
+
color: var(--fd-fg-soft);
|
|
174
|
+
}
|
|
175
|
+
/* Tailwind's preflight strips every list marker, and nothing here gave them back, so a numbered
|
|
176
|
+
answer rendered as unnumbered lines and a bulleted one as a loose stack of sentences. */
|
|
177
|
+
.flowdown ul,
|
|
178
|
+
.flowdown ol {
|
|
179
|
+
padding-left: 1.35rem;
|
|
180
|
+
}
|
|
181
|
+
.flowdown ul {
|
|
182
|
+
list-style: disc;
|
|
183
|
+
}
|
|
184
|
+
.flowdown ol {
|
|
185
|
+
list-style: decimal;
|
|
186
|
+
}
|
|
187
|
+
.flowdown :is(ul, ol) ul {
|
|
188
|
+
list-style: circle;
|
|
189
|
+
}
|
|
190
|
+
.flowdown li + li {
|
|
191
|
+
margin-top: 0.25rem;
|
|
192
|
+
}
|
|
193
|
+
/* Bullets and numbers are scaffolding: quieter than the text they carry, and numbers set in
|
|
194
|
+
tabular figures so a list past nine keeps one column. */
|
|
195
|
+
.flowdown li::marker {
|
|
196
|
+
color: var(--fd-fg-faint);
|
|
197
|
+
}
|
|
198
|
+
.flowdown ol > li::marker {
|
|
199
|
+
font-variant-numeric: tabular-nums;
|
|
200
|
+
}
|
|
201
|
+
.flowdown li > :is(ul, ol) {
|
|
202
|
+
margin: 0.25rem 0;
|
|
203
|
+
}
|
|
204
|
+
/* Section divider (`---`): a thin token-colored rule, not the browser's 3D inset. */
|
|
205
|
+
.flowdown hr {
|
|
206
|
+
margin: 1.1rem 0;
|
|
207
|
+
border: 0;
|
|
208
|
+
border-top: 1px solid var(--fd-border);
|
|
209
|
+
}
|
|
210
|
+
/* Strikethrough (`~~text~~`) = removed/done — mute it so it reads as de-emphasized. */
|
|
211
|
+
.flowdown del {
|
|
212
|
+
color: var(--fd-fg-soft);
|
|
213
|
+
}
|
|
214
|
+
/* A link is marked by a faint underline that firms up on hover: a full-strength line under
|
|
215
|
+
every reference striped a source-heavy reply. */
|
|
216
|
+
.flowdown a {
|
|
217
|
+
color: var(--fd-link);
|
|
218
|
+
text-decoration: underline;
|
|
219
|
+
text-decoration-thickness: 1px;
|
|
220
|
+
text-decoration-color: color-mix(in oklab, var(--fd-link) 35%, transparent);
|
|
221
|
+
text-underline-offset: 0.2em;
|
|
222
|
+
transition: text-decoration-color var(--fd-duration) ease;
|
|
223
|
+
/* A long bare URL as link text wraps instead of overflowing the bubble. */
|
|
224
|
+
overflow-wrap: anywhere;
|
|
225
|
+
}
|
|
226
|
+
.flowdown a:hover {
|
|
227
|
+
text-decoration-color: currentColor;
|
|
228
|
+
}
|
|
229
|
+
.flowdown :focus-visible {
|
|
230
|
+
outline: 2px solid var(--fd-focus);
|
|
231
|
+
outline-offset: 2px;
|
|
232
|
+
border-radius: var(--fd-radius-small);
|
|
233
|
+
}
|
|
234
|
+
.flowdown blockquote {
|
|
235
|
+
border-left: 2px solid var(--fd-border);
|
|
236
|
+
padding-left: 0.85rem;
|
|
237
|
+
color: var(--fd-fg-soft);
|
|
238
|
+
}
|
|
239
|
+
/* A quote's closing `— Author` line: set right, below the quotation, so
|
|
240
|
+
the source reads as a signature instead of one more line of the quote. */
|
|
241
|
+
.flowdown blockquote > :has(+ .fd-quote-source) {
|
|
242
|
+
margin-bottom: 0;
|
|
243
|
+
}
|
|
244
|
+
.flowdown blockquote > .fd-quote-source {
|
|
245
|
+
margin-top: 0.3rem;
|
|
246
|
+
text-align: right;
|
|
247
|
+
font-size: 0.9em;
|
|
248
|
+
font-style: italic;
|
|
249
|
+
color: var(--fd-fg-faint);
|
|
250
|
+
}
|
|
251
|
+
.flowdown blockquote > .fd-quote-source::before {
|
|
252
|
+
content: '\2014\00a0';
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/* ─── Callouts (`> [!NOTE]` … `> [!CAUTION]`) ───
|
|
256
|
+
Status on the glyph, never as a wash: the note itself is a veil —
|
|
257
|
+
the foreground at a few percent over whatever ground it sits on — so it is right in every
|
|
258
|
+
theme and under glass, and five of them in a reply read as asides rather than as banners.
|
|
259
|
+
The glyph hangs in its own column beside the first line; the text keeps the prose colour. */
|
|
260
|
+
.flowdown .fd-callout {
|
|
261
|
+
--fd-callout: var(--fd-info);
|
|
262
|
+
display: grid;
|
|
263
|
+
grid-template-columns: 1rem minmax(0, 1fr);
|
|
264
|
+
column-gap: 0.7rem;
|
|
265
|
+
margin: 0.8rem 0;
|
|
266
|
+
border-radius: var(--fd-radius);
|
|
267
|
+
background: var(--fd-veil);
|
|
268
|
+
padding: 0.65rem 0.9rem;
|
|
269
|
+
}
|
|
270
|
+
.flowdown .fd-callout-icon {
|
|
271
|
+
width: 1rem;
|
|
272
|
+
height: 1rem;
|
|
273
|
+
/* Centre the glyph on the first line box, whatever the line height. */
|
|
274
|
+
margin-top: calc((1lh - 1rem) / 2);
|
|
275
|
+
color: var(--fd-callout);
|
|
276
|
+
}
|
|
277
|
+
.flowdown .fd-callout[data-callout='tip'] {
|
|
278
|
+
--fd-callout: var(--fd-success);
|
|
279
|
+
}
|
|
280
|
+
.flowdown .fd-callout[data-callout='important'] {
|
|
281
|
+
--fd-callout: var(--fd-important);
|
|
282
|
+
}
|
|
283
|
+
.flowdown .fd-callout[data-callout='warning'] {
|
|
284
|
+
--fd-callout: var(--fd-warning);
|
|
285
|
+
}
|
|
286
|
+
.flowdown .fd-callout[data-callout='caution'] {
|
|
287
|
+
--fd-callout: var(--fd-danger);
|
|
288
|
+
}
|
|
289
|
+
.flowdown .fd-callout-title {
|
|
290
|
+
margin-bottom: 0.15rem;
|
|
291
|
+
font-weight: 600;
|
|
292
|
+
color: var(--fd-fg);
|
|
293
|
+
}
|
|
294
|
+
/* The title and its text are one unit: no paragraph gap between them. */
|
|
295
|
+
.flowdown .fd-callout-title + * {
|
|
296
|
+
margin-top: 0;
|
|
297
|
+
}
|
|
298
|
+
.flowdown .fd-callout-body > :first-child {
|
|
299
|
+
margin-top: 0;
|
|
300
|
+
}
|
|
301
|
+
.flowdown .fd-callout-body > :last-child {
|
|
302
|
+
margin-bottom: 0;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/* Steps, tabs, stats, pros/cons, file trees and checklists: `forms.css`. */
|
|
306
|
+
|
|
307
|
+
/* ─── Figures (`` alone in a paragraph) ─── */
|
|
308
|
+
/* A figure is set like one in a document: centred, and bounded to a share of the reply so a
|
|
309
|
+
photo illustrates the text instead of becoming the whole message. */
|
|
310
|
+
.flowdown .fd-figure {
|
|
311
|
+
margin: 1.1rem 0;
|
|
312
|
+
text-align: center;
|
|
313
|
+
}
|
|
314
|
+
.flowdown .fd-figure img {
|
|
315
|
+
display: block;
|
|
316
|
+
margin: 0 auto;
|
|
317
|
+
max-width: min(100%, 34rem);
|
|
318
|
+
max-height: 20rem;
|
|
319
|
+
object-fit: contain;
|
|
320
|
+
border-radius: var(--fd-radius);
|
|
321
|
+
}
|
|
322
|
+
.flowdown .fd-figure > figcaption {
|
|
323
|
+
margin-top: 0.45rem;
|
|
324
|
+
text-align: center;
|
|
325
|
+
font-size: 0.86em;
|
|
326
|
+
font-style: normal;
|
|
327
|
+
color: var(--fd-fg-faint);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/* ─── Diagrams (```mermaid) ───
|
|
331
|
+
A figure, not a panel: no frame, fill or header, so a diagram sits in the reply the way an
|
|
332
|
+
image does. Its colours come from the tokens (`mermaid/look.ts`); only shape is here. Its
|
|
333
|
+
toolbar and the enlarged viewer are in `diagram.css`. */
|
|
334
|
+
.flowdown .fd-diagram {
|
|
335
|
+
margin: 0.8rem 0;
|
|
336
|
+
}
|
|
337
|
+
.flowdown .fd-diagram-canvas {
|
|
338
|
+
display: flex;
|
|
339
|
+
justify-content: center;
|
|
340
|
+
overflow-x: auto;
|
|
341
|
+
padding: 0.5rem 0;
|
|
342
|
+
}
|
|
343
|
+
.flowdown .fd-diagram-canvas svg {
|
|
344
|
+
max-width: 100%;
|
|
345
|
+
height: auto;
|
|
346
|
+
}
|
|
347
|
+
/* Nodes take the control radius instead of Mermaid's square corners. */
|
|
348
|
+
.flowdown .fd-diagram-canvas :is(.node rect.label-container, rect.actor, rect.note) {
|
|
349
|
+
rx: 6px;
|
|
350
|
+
ry: 6px;
|
|
351
|
+
}
|
|
352
|
+
/* The parser's message under a source that could not be drawn, tucked up to its code block. */
|
|
353
|
+
.flowdown .fd-diagram-note {
|
|
354
|
+
margin-top: 0.35rem;
|
|
355
|
+
font-size: 0.85em;
|
|
356
|
+
color: var(--fd-fg-faint);
|
|
357
|
+
}
|
|
358
|
+
/* Inline code: wherever it is not a block's (in text, in bold or a link, in a form's own text). */
|
|
359
|
+
.flowdown :where(:not(pre)) > code:where(:not(.math-inline, .math-display)) {
|
|
360
|
+
border-radius: var(--fd-radius-small);
|
|
361
|
+
font-family: var(--fd-font-mono);
|
|
362
|
+
background: var(--fd-veil-strong);
|
|
363
|
+
padding: 0.1rem 0.3rem;
|
|
364
|
+
font-size: 0.92em;
|
|
365
|
+
/* Long inline tokens (deep paths, hashes, URLs) wrap instead of overflowing. */
|
|
366
|
+
overflow-wrap: anywhere;
|
|
367
|
+
}
|
|
368
|
+
/* Tables are ruled, not gridded (the typesetting "booktabs" convention): a rule above the header,
|
|
369
|
+
a rule under it, hairlines between rows and a rule to close. The full cell grid with a filled
|
|
370
|
+
header row boxed every value in and was the loudest thing in a reply; horizontal rules alone
|
|
371
|
+
carry the rows, and the eye reads the columns from their alignment. */
|
|
372
|
+
.flowdown table {
|
|
373
|
+
width: 100%;
|
|
374
|
+
border-collapse: collapse;
|
|
375
|
+
font-size: 0.9em;
|
|
376
|
+
font-variant-numeric: tabular-nums;
|
|
377
|
+
}
|
|
378
|
+
/* Wide tables scroll inside their own box instead of widening the page. */
|
|
379
|
+
.flowdown .fd-table {
|
|
380
|
+
max-width: 100%;
|
|
381
|
+
margin: 0.65rem 0;
|
|
382
|
+
overflow-x: auto;
|
|
383
|
+
}
|
|
384
|
+
.flowdown .fd-table table {
|
|
385
|
+
width: max-content;
|
|
386
|
+
min-width: 100%;
|
|
387
|
+
margin: 0;
|
|
388
|
+
}
|
|
389
|
+
.flowdown th,
|
|
390
|
+
.flowdown td {
|
|
391
|
+
border-bottom: 1px solid var(--fd-border-subtle);
|
|
392
|
+
padding: 0.5rem 0.9rem;
|
|
393
|
+
text-align: left;
|
|
394
|
+
vertical-align: top;
|
|
395
|
+
/* Long cell values (URLs/paths) wrap instead of overflowing the table. */
|
|
396
|
+
overflow-wrap: anywhere;
|
|
397
|
+
}
|
|
398
|
+
/* The outer columns align with the prose around the table instead of an invisible cell wall. */
|
|
399
|
+
.flowdown :is(th, td):first-child {
|
|
400
|
+
padding-left: 0;
|
|
401
|
+
}
|
|
402
|
+
.flowdown :is(th, td):last-child {
|
|
403
|
+
padding-right: 0;
|
|
404
|
+
}
|
|
405
|
+
.flowdown th {
|
|
406
|
+
border-top: 1px solid var(--fd-border);
|
|
407
|
+
border-bottom-color: var(--fd-border);
|
|
408
|
+
font-weight: 600;
|
|
409
|
+
color: var(--fd-fg-soft);
|
|
410
|
+
}
|
|
411
|
+
.flowdown tbody tr:last-child td {
|
|
412
|
+
border-bottom-color: var(--fd-border);
|
|
413
|
+
}
|
|
414
|
+
.flowdown img {
|
|
415
|
+
max-width: 100%;
|
|
416
|
+
/* Inline images (badges, shields, emoji-style icons) sit on the text baseline
|
|
417
|
+
at their natural size — no block layout or large radius, so a row of badges
|
|
418
|
+
flows like on GitHub instead of stacking as full-width blobs. */
|
|
419
|
+
vertical-align: middle;
|
|
420
|
+
}
|
|
421
|
+
/* A lone image that is its paragraph's only direct child = a content figure
|
|
422
|
+
(screenshot, diagram). Badges live inside <a>, so they never match this. */
|
|
423
|
+
.flowdown p > img:only-child {
|
|
424
|
+
display: block;
|
|
425
|
+
/* Cap inline height so a tall/narrow image doesn't dominate the message. */
|
|
426
|
+
max-height: 28rem;
|
|
427
|
+
border-radius: var(--fd-radius);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/* Footnotes. The reference in the text is a raised number, quiet and not underlined: the line
|
|
431
|
+
under a superscript sat lower and wider than its digit. `line-height: 0` keeps it from pushing
|
|
432
|
+
its line apart from the others. */
|
|
433
|
+
.flowdown sup,
|
|
434
|
+
.flowdown sub {
|
|
435
|
+
line-height: 0;
|
|
436
|
+
}
|
|
437
|
+
.flowdown [data-footnote-ref],
|
|
438
|
+
.flowdown [data-footnote-backref] {
|
|
439
|
+
text-decoration: none;
|
|
440
|
+
color: var(--fd-fg-soft);
|
|
441
|
+
}
|
|
442
|
+
/* The notes themselves close the reply under a rule, smaller and quieter than the text they
|
|
443
|
+
annotate. Their heading names the section for a screen reader and is not drawn: out of the
|
|
444
|
+
flow and clipped to nothing, which leaves it in the accessibility tree. */
|
|
445
|
+
.flowdown [data-footnotes] {
|
|
446
|
+
margin-top: 1.5rem;
|
|
447
|
+
border-top: 1px solid var(--fd-border-subtle);
|
|
448
|
+
padding-top: 0.65rem;
|
|
449
|
+
font-size: 0.9em;
|
|
450
|
+
color: var(--fd-fg-soft);
|
|
451
|
+
}
|
|
452
|
+
.flowdown .sr-only {
|
|
453
|
+
position: absolute;
|
|
454
|
+
clip-path: inset(50%);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/* A key (`<kbd>⌘</kbd>`): a keycap, raised by a heavier bottom edge. */
|
|
458
|
+
.flowdown kbd {
|
|
459
|
+
display: inline-block;
|
|
460
|
+
min-width: 1.5em;
|
|
461
|
+
box-sizing: border-box;
|
|
462
|
+
border: 1px solid var(--fd-border);
|
|
463
|
+
border-bottom-width: 2px;
|
|
464
|
+
border-radius: var(--fd-radius-small);
|
|
465
|
+
padding: 0.05em 0.4em;
|
|
466
|
+
background: var(--fd-veil);
|
|
467
|
+
font-family: var(--fd-font-mono);
|
|
468
|
+
font-size: 0.82em;
|
|
469
|
+
line-height: 1.35;
|
|
470
|
+
text-align: center;
|
|
471
|
+
white-space: nowrap;
|
|
472
|
+
vertical-align: 0.06em;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/* ─── A reply arriving (`<Markdown streaming>`) ───
|
|
476
|
+
A block that starts (a paragraph, then the panel of a code block or a table under it) comes in
|
|
477
|
+
over a short fade instead of popping onto the page. Only the newest block is ever animated, and
|
|
478
|
+
only once: the blocks above it are finished and do not move. It starts faint, not invisible:
|
|
479
|
+
a block that changes kind as it grows (a line that turns out to be a table) is drawn anew, and
|
|
480
|
+
must not blink out on the way. */
|
|
481
|
+
@keyframes fd-arrive {
|
|
482
|
+
from {
|
|
483
|
+
opacity: 0.3;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
.flowdown[data-streaming] > :last-child {
|
|
487
|
+
animation: fd-arrive var(--fd-duration-slow) ease-out;
|
|
488
|
+
}
|
|
489
|
+
@media (prefers-reduced-motion: reduce) {
|
|
490
|
+
.flowdown[data-streaming] > :last-child {
|
|
491
|
+
animation: none;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* forms.css */
|
|
496
|
+
/* ─── Answer forms: the dialect's structured shapes (`dialect.ts`) ───
|
|
497
|
+
Steps, tabs, headline figures, the case for and against, file trees and checklists. Each is
|
|
498
|
+
plain Markdown underneath; these rules are what make it read as the shape it is. Nothing here
|
|
499
|
+
is a status except the pros/cons glyphs, so the neutral parts take the text tiers and the
|
|
500
|
+
veil the callouts use (the foreground at a few percent), right in every theme and under glass. */
|
|
501
|
+
|
|
502
|
+
/* ─── Steps (`> [!STEPS]` over a list) ───
|
|
503
|
+
A sequence read in order: each step's number in a round mark, a line down to the next one, the
|
|
504
|
+
step's title, its "when" quieter beneath, then its text. */
|
|
505
|
+
.flowdown .fd-steps-title,
|
|
506
|
+
.flowdown .fd-stats-title,
|
|
507
|
+
.flowdown .fd-sources-title,
|
|
508
|
+
.flowdown .fd-tabs-title {
|
|
509
|
+
margin-bottom: 0.35rem;
|
|
510
|
+
font-weight: 600;
|
|
511
|
+
color: var(--fd-fg);
|
|
512
|
+
}
|
|
513
|
+
.flowdown .fd-steps-title + .fd-steps,
|
|
514
|
+
.flowdown .fd-stats-title + .fd-stats,
|
|
515
|
+
.flowdown .fd-sources-title + .fd-sources,
|
|
516
|
+
.flowdown .fd-tabs-title + .fd-tabs {
|
|
517
|
+
margin-top: 0;
|
|
518
|
+
}
|
|
519
|
+
.flowdown ol.fd-steps,
|
|
520
|
+
.flowdown ul.fd-steps {
|
|
521
|
+
list-style: none;
|
|
522
|
+
margin: 0.8rem 0;
|
|
523
|
+
padding-left: 0;
|
|
524
|
+
}
|
|
525
|
+
.flowdown .fd-steps > li {
|
|
526
|
+
--fd-mark: 1.5rem;
|
|
527
|
+
position: relative;
|
|
528
|
+
margin: 0;
|
|
529
|
+
padding: 0 0 1rem 2.25rem;
|
|
530
|
+
}
|
|
531
|
+
.flowdown .fd-steps > li:last-child {
|
|
532
|
+
padding-bottom: 0;
|
|
533
|
+
}
|
|
534
|
+
/* A numbered mark (a step's, a source's): a round badge on the row's first line. In `line-height`,
|
|
535
|
+
`lh` is the parent's, so the mark takes the row's line whatever its own font size and the page's
|
|
536
|
+
leading (a number, a length, `normal`), and the `1lh` in `top` centres it on that line exactly.
|
|
537
|
+
That line is taller than a small mark: the track is centred, or the number would sink. */
|
|
538
|
+
.flowdown .fd-steps > li::before,
|
|
539
|
+
.flowdown .fd-sources > li::before {
|
|
540
|
+
position: absolute;
|
|
541
|
+
left: 0;
|
|
542
|
+
top: calc((1lh - var(--fd-mark)) / 2);
|
|
543
|
+
display: grid;
|
|
544
|
+
place-content: center;
|
|
545
|
+
min-width: var(--fd-mark);
|
|
546
|
+
height: var(--fd-mark);
|
|
547
|
+
border-radius: 9999px;
|
|
548
|
+
background: var(--fd-veil-strong);
|
|
549
|
+
font-size: 0.72em;
|
|
550
|
+
font-weight: 600;
|
|
551
|
+
line-height: 1lh;
|
|
552
|
+
color: var(--fd-fg-soft);
|
|
553
|
+
}
|
|
554
|
+
/* A step's mark is its place in the list, the one `start` and `value` give it; steps in no order
|
|
555
|
+
get a dot. */
|
|
556
|
+
.flowdown .fd-steps > li::before {
|
|
557
|
+
content: counter(list-item);
|
|
558
|
+
}
|
|
559
|
+
.flowdown ul.fd-steps > li::before {
|
|
560
|
+
content: '●';
|
|
561
|
+
}
|
|
562
|
+
/* The line runs from this mark to the next one, the same gap at both ends; the last step has none
|
|
563
|
+
to reach. Its box starts at this mark's bottom edge and ends at the next mark's top, and the
|
|
564
|
+
gaps are its padding: a browser snaps each box to whole pixels on its own, and a line placed by
|
|
565
|
+
its own offsets landed a pixel closer to one mark than to the other. */
|
|
566
|
+
.flowdown .fd-steps > li:not(:last-child)::after {
|
|
567
|
+
content: '';
|
|
568
|
+
position: absolute;
|
|
569
|
+
left: calc(var(--fd-mark) / 2 - 1px);
|
|
570
|
+
top: calc((1lh + var(--fd-mark)) / 2);
|
|
571
|
+
bottom: calc((var(--fd-mark) - 1lh) / 2);
|
|
572
|
+
width: 2px;
|
|
573
|
+
padding: 0.25rem 0;
|
|
574
|
+
background: var(--fd-border) content-box;
|
|
575
|
+
}
|
|
576
|
+
.flowdown .fd-step-head {
|
|
577
|
+
margin: 0;
|
|
578
|
+
}
|
|
579
|
+
.flowdown .fd-step-title {
|
|
580
|
+
font-weight: 600;
|
|
581
|
+
color: var(--fd-fg);
|
|
582
|
+
}
|
|
583
|
+
.flowdown .fd-step-meta {
|
|
584
|
+
display: block;
|
|
585
|
+
margin-top: 0.1rem;
|
|
586
|
+
font-size: 0.85em;
|
|
587
|
+
font-style: italic;
|
|
588
|
+
color: var(--fd-fg-faint);
|
|
589
|
+
}
|
|
590
|
+
/* The step's text sits one small, fixed gap under its title whatever it starts with: a block's
|
|
591
|
+
own top margin (a code block's, a list's) would otherwise set the gap, a different one per step. */
|
|
592
|
+
/* A block right under the title (a code block, a table) belongs to its step: it sits nearer its
|
|
593
|
+
own title than the next step's, whatever margin the block has elsewhere. */
|
|
594
|
+
.flowdown .fd-step-head + :not(.fd-step-body) {
|
|
595
|
+
margin-top: 0.5rem;
|
|
596
|
+
}
|
|
597
|
+
.flowdown .fd-step-body {
|
|
598
|
+
margin-top: 0.15rem;
|
|
599
|
+
}
|
|
600
|
+
.flowdown .fd-step-body > :first-child {
|
|
601
|
+
margin-top: 0;
|
|
602
|
+
}
|
|
603
|
+
.flowdown .fd-steps > li > :last-child,
|
|
604
|
+
.flowdown .fd-step-body > :last-child {
|
|
605
|
+
margin-bottom: 0;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/* ─── Tabs (`> [!TABS]` with a heading per variant) ───
|
|
609
|
+
The variants share one bordered panel, the tab row on top: the selected tab is marked by its
|
|
610
|
+
text colour and a rule under it, the rest are quiet. */
|
|
611
|
+
.flowdown .fd-tabs {
|
|
612
|
+
margin: 0.8rem 0;
|
|
613
|
+
overflow: hidden;
|
|
614
|
+
border: 1px solid var(--fd-border);
|
|
615
|
+
border-radius: var(--fd-radius);
|
|
616
|
+
}
|
|
617
|
+
.flowdown .fd-tab-list {
|
|
618
|
+
display: flex;
|
|
619
|
+
gap: 0.25rem;
|
|
620
|
+
overflow-x: auto;
|
|
621
|
+
border-bottom: 1px solid var(--fd-border);
|
|
622
|
+
/* With a tab's own 0.5rem, its label starts where a code block's text does (0.9rem). */
|
|
623
|
+
padding: 0 0.4rem;
|
|
624
|
+
scrollbar-width: none;
|
|
625
|
+
}
|
|
626
|
+
.flowdown .fd-tab {
|
|
627
|
+
position: relative;
|
|
628
|
+
flex: none;
|
|
629
|
+
margin: 0;
|
|
630
|
+
border: 0;
|
|
631
|
+
background: none;
|
|
632
|
+
padding: 0.55rem 0.5rem;
|
|
633
|
+
font: inherit;
|
|
634
|
+
font-size: 0.9em;
|
|
635
|
+
font-weight: 500;
|
|
636
|
+
color: var(--fd-fg-faint);
|
|
637
|
+
cursor: pointer;
|
|
638
|
+
transition: color var(--fd-duration) ease;
|
|
639
|
+
}
|
|
640
|
+
.flowdown .fd-tab:hover {
|
|
641
|
+
color: var(--fd-fg-soft);
|
|
642
|
+
}
|
|
643
|
+
.flowdown .fd-tab[aria-selected='true'] {
|
|
644
|
+
color: var(--fd-fg);
|
|
645
|
+
}
|
|
646
|
+
.flowdown .fd-tab[aria-selected='true']::after {
|
|
647
|
+
content: '';
|
|
648
|
+
position: absolute;
|
|
649
|
+
inset: auto 0.5rem -1px;
|
|
650
|
+
border-bottom: 2px solid var(--fd-fg);
|
|
651
|
+
}
|
|
652
|
+
.flowdown .fd-tab:focus-visible {
|
|
653
|
+
outline-offset: -2px;
|
|
654
|
+
}
|
|
655
|
+
.flowdown .fd-tab-panel {
|
|
656
|
+
padding: 0.6rem 0.9rem 0.75rem;
|
|
657
|
+
}
|
|
658
|
+
.flowdown .fd-tab-panel > :first-child {
|
|
659
|
+
margin-top: 0;
|
|
660
|
+
}
|
|
661
|
+
.flowdown .fd-tab-panel > :last-child {
|
|
662
|
+
margin-bottom: 0;
|
|
663
|
+
}
|
|
664
|
+
/* A variant that is one code block (install commands per system) is that block, edge to edge
|
|
665
|
+
under the tab row: a rounded panel inside the bordered one was a box in a box. */
|
|
666
|
+
.flowdown .fd-tab-panel:has(> .fd-code:only-child) {
|
|
667
|
+
padding: 0;
|
|
668
|
+
}
|
|
669
|
+
.flowdown .fd-tab-panel > .fd-code:only-child {
|
|
670
|
+
border-radius: 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/* ─── Headline figures (`> [!STATS]` over `- **value** label`) ───
|
|
674
|
+
A row of figures that wraps: the value large, its label quiet under it. */
|
|
675
|
+
.flowdown ul.fd-stats,
|
|
676
|
+
.flowdown ol.fd-stats {
|
|
677
|
+
display: grid;
|
|
678
|
+
grid-template-columns: repeat(auto-fit, minmax(min(8.5rem, 100%), 1fr));
|
|
679
|
+
gap: 0.5rem;
|
|
680
|
+
margin: 0.8rem 0;
|
|
681
|
+
padding: 0;
|
|
682
|
+
list-style: none;
|
|
683
|
+
}
|
|
684
|
+
.flowdown .fd-stats > li {
|
|
685
|
+
min-width: 0;
|
|
686
|
+
margin: 0;
|
|
687
|
+
border-radius: var(--fd-radius);
|
|
688
|
+
background: var(--fd-veil);
|
|
689
|
+
padding: 0.6rem 0.8rem;
|
|
690
|
+
}
|
|
691
|
+
.flowdown .fd-stat-value {
|
|
692
|
+
display: block;
|
|
693
|
+
font-size: 1.35em;
|
|
694
|
+
font-weight: 600;
|
|
695
|
+
line-height: 1.2;
|
|
696
|
+
font-variant-numeric: tabular-nums;
|
|
697
|
+
color: var(--fd-fg);
|
|
698
|
+
}
|
|
699
|
+
.flowdown .fd-stat-label {
|
|
700
|
+
display: block;
|
|
701
|
+
margin-top: 0.15rem;
|
|
702
|
+
font-size: 0.85em;
|
|
703
|
+
font-style: normal;
|
|
704
|
+
color: var(--fd-fg-soft);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
/* ─── The case for and against (`> [!PROS]` / `> [!CONS]`) ───
|
|
708
|
+
A point per row with its glyph in the status hue — the one status in these forms. Written one
|
|
709
|
+
after the other, the two sit side by side, and stack where the reply is narrow. */
|
|
710
|
+
.flowdown .fd-verdicts {
|
|
711
|
+
display: grid;
|
|
712
|
+
grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
|
|
713
|
+
gap: 0.5rem;
|
|
714
|
+
margin: 0.8rem 0;
|
|
715
|
+
}
|
|
716
|
+
.flowdown .fd-verdict {
|
|
717
|
+
min-width: 0;
|
|
718
|
+
--fd-verdict: var(--fd-success);
|
|
719
|
+
margin: 0.8rem 0;
|
|
720
|
+
border-radius: var(--fd-radius);
|
|
721
|
+
background: var(--fd-veil);
|
|
722
|
+
padding: 0.6rem 0.9rem;
|
|
723
|
+
}
|
|
724
|
+
.flowdown .fd-verdicts > .fd-verdict {
|
|
725
|
+
margin: 0;
|
|
726
|
+
}
|
|
727
|
+
.flowdown .fd-verdict[data-verdict='cons'] {
|
|
728
|
+
--fd-verdict: var(--fd-danger);
|
|
729
|
+
}
|
|
730
|
+
.flowdown .fd-verdict-title {
|
|
731
|
+
margin: 0 0 0.3rem;
|
|
732
|
+
font-weight: 600;
|
|
733
|
+
color: var(--fd-fg);
|
|
734
|
+
}
|
|
735
|
+
.flowdown ul.fd-verdict-list,
|
|
736
|
+
.flowdown ol.fd-verdict-list {
|
|
737
|
+
margin: 0;
|
|
738
|
+
padding: 0;
|
|
739
|
+
list-style: none;
|
|
740
|
+
}
|
|
741
|
+
.flowdown .fd-verdict-list > li {
|
|
742
|
+
position: relative;
|
|
743
|
+
margin: 0.2rem 0;
|
|
744
|
+
padding-left: 1.35rem;
|
|
745
|
+
}
|
|
746
|
+
.flowdown .fd-verdict-list > li::before {
|
|
747
|
+
position: absolute;
|
|
748
|
+
left: 0;
|
|
749
|
+
font-weight: 700;
|
|
750
|
+
color: var(--fd-verdict);
|
|
751
|
+
}
|
|
752
|
+
.flowdown .fd-verdict[data-verdict='pros'] .fd-verdict-list > li::before {
|
|
753
|
+
content: '✓';
|
|
754
|
+
}
|
|
755
|
+
.flowdown .fd-verdict[data-verdict='cons'] .fd-verdict-list > li::before {
|
|
756
|
+
content: '✕';
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* ─── A folded section (`> [!DETAILS] Title`, or a `<details>` written as HTML) ───
|
|
760
|
+
An outlined row with its title and a chevron that turns when it opens. Closed, it is one line;
|
|
761
|
+
open, the content sits under a hairline, inset by the panel's own padding, so text written
|
|
762
|
+
straight after the summary lines up with a paragraph or a code block beside it. */
|
|
763
|
+
.flowdown details {
|
|
764
|
+
--fd-details-pad: 0.9rem;
|
|
765
|
+
margin: 0.8rem 0;
|
|
766
|
+
border: 1px solid var(--fd-border-subtle);
|
|
767
|
+
border-radius: var(--fd-radius);
|
|
768
|
+
padding: 0 var(--fd-details-pad);
|
|
769
|
+
color: var(--fd-fg-soft);
|
|
770
|
+
}
|
|
771
|
+
.flowdown details > summary {
|
|
772
|
+
display: flex;
|
|
773
|
+
align-items: center;
|
|
774
|
+
gap: 0.6rem;
|
|
775
|
+
margin: 0 calc(-1 * var(--fd-details-pad));
|
|
776
|
+
border-radius: calc(var(--fd-radius) - 1px);
|
|
777
|
+
padding: 0.6rem var(--fd-details-pad);
|
|
778
|
+
font-weight: 600;
|
|
779
|
+
line-height: 1.4;
|
|
780
|
+
color: var(--fd-fg);
|
|
781
|
+
cursor: pointer;
|
|
782
|
+
list-style: none;
|
|
783
|
+
user-select: none;
|
|
784
|
+
transition: background-color var(--fd-duration) ease;
|
|
785
|
+
}
|
|
786
|
+
.flowdown details > summary::-webkit-details-marker {
|
|
787
|
+
display: none;
|
|
788
|
+
}
|
|
789
|
+
.flowdown details > summary::before {
|
|
790
|
+
content: '';
|
|
791
|
+
flex: none;
|
|
792
|
+
width: 0.4rem;
|
|
793
|
+
height: 0.4rem;
|
|
794
|
+
margin: 0 0.15rem;
|
|
795
|
+
border: solid var(--fd-fg-faint);
|
|
796
|
+
border-width: 0 1.5px 1.5px 0;
|
|
797
|
+
transform: translateX(-0.1rem) rotate(-45deg);
|
|
798
|
+
transition:
|
|
799
|
+
transform var(--fd-duration-slow) var(--fd-ease),
|
|
800
|
+
border-color var(--fd-duration) ease;
|
|
801
|
+
}
|
|
802
|
+
.flowdown details[open] > summary::before {
|
|
803
|
+
transform: translateY(-0.1rem) rotate(45deg);
|
|
804
|
+
}
|
|
805
|
+
.flowdown details > summary:hover {
|
|
806
|
+
background: var(--fd-veil);
|
|
807
|
+
}
|
|
808
|
+
.flowdown details > summary:hover::before {
|
|
809
|
+
border-color: var(--fd-fg);
|
|
810
|
+
}
|
|
811
|
+
.flowdown details > summary:focus-visible {
|
|
812
|
+
outline-offset: -2px;
|
|
813
|
+
}
|
|
814
|
+
.flowdown details[open] {
|
|
815
|
+
padding-bottom: 0.8rem;
|
|
816
|
+
}
|
|
817
|
+
.flowdown details[open] > summary {
|
|
818
|
+
margin-bottom: 0.8rem;
|
|
819
|
+
border-bottom: 1px solid var(--fd-border-subtle);
|
|
820
|
+
border-bottom-left-radius: 0;
|
|
821
|
+
border-bottom-right-radius: 0;
|
|
822
|
+
}
|
|
823
|
+
.flowdown details > summary + * {
|
|
824
|
+
margin-top: 0;
|
|
825
|
+
}
|
|
826
|
+
.flowdown details > :last-child:not(summary) {
|
|
827
|
+
margin-bottom: 0;
|
|
828
|
+
}
|
|
829
|
+
/* Opening is a short fade down from the title, not a pop. */
|
|
830
|
+
@keyframes fd-unfold {
|
|
831
|
+
from {
|
|
832
|
+
opacity: 0;
|
|
833
|
+
transform: translateY(-0.2rem);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
.flowdown details[open] > :not(summary) {
|
|
837
|
+
animation: fd-unfold var(--fd-duration-slow) var(--fd-ease);
|
|
838
|
+
}
|
|
839
|
+
@media (prefers-reduced-motion: reduce) {
|
|
840
|
+
.flowdown details[open] > :not(summary) {
|
|
841
|
+
animation: none;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
/* ─── References (`> [!SOURCES]` over a list of links) ───
|
|
846
|
+
A numbered row per page: its title, the site quiet beside it, the author's note after. */
|
|
847
|
+
.flowdown ul.fd-sources,
|
|
848
|
+
.flowdown ol.fd-sources {
|
|
849
|
+
margin: 0.8rem 0;
|
|
850
|
+
padding: 0;
|
|
851
|
+
list-style: none;
|
|
852
|
+
counter-reset: fd-source;
|
|
853
|
+
}
|
|
854
|
+
.flowdown .fd-sources > li {
|
|
855
|
+
--fd-mark: 1.25rem;
|
|
856
|
+
position: relative;
|
|
857
|
+
margin: 0.45rem 0;
|
|
858
|
+
padding-left: 1.85rem;
|
|
859
|
+
counter-increment: fd-source;
|
|
860
|
+
}
|
|
861
|
+
/* The badge itself is the numbered mark the steps draw (above). */
|
|
862
|
+
.flowdown .fd-sources > li::before {
|
|
863
|
+
content: counter(fd-source);
|
|
864
|
+
}
|
|
865
|
+
.flowdown .fd-source > a {
|
|
866
|
+
text-decoration: none;
|
|
867
|
+
}
|
|
868
|
+
.flowdown .fd-source > a:hover .fd-source-title {
|
|
869
|
+
text-decoration: underline;
|
|
870
|
+
text-underline-offset: 0.15em;
|
|
871
|
+
}
|
|
872
|
+
.flowdown .fd-source-title {
|
|
873
|
+
font-weight: 500;
|
|
874
|
+
color: var(--fd-fg);
|
|
875
|
+
}
|
|
876
|
+
.flowdown .fd-source-host {
|
|
877
|
+
margin-left: 0.5rem;
|
|
878
|
+
font-size: 0.85em;
|
|
879
|
+
font-style: normal;
|
|
880
|
+
font-weight: 400;
|
|
881
|
+
color: var(--fd-fg-faint);
|
|
882
|
+
}
|
|
883
|
+
.flowdown .fd-source-note {
|
|
884
|
+
display: block;
|
|
885
|
+
font-size: 0.9em;
|
|
886
|
+
font-style: normal;
|
|
887
|
+
color: var(--fd-fg-soft);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/* ─── File tree (a ```tree fence) ───
|
|
891
|
+
Rows in a monospace column, indented by depth with a guide per level; a folder folds. */
|
|
892
|
+
.flowdown .fd-tree {
|
|
893
|
+
margin: 0.8rem 0;
|
|
894
|
+
font-family: var(--fd-font-mono);
|
|
895
|
+
font-size: 0.86em;
|
|
896
|
+
line-height: normal;
|
|
897
|
+
}
|
|
898
|
+
.flowdown .fd-tree-row {
|
|
899
|
+
display: flex;
|
|
900
|
+
align-items: center;
|
|
901
|
+
gap: 0.4rem;
|
|
902
|
+
min-width: 0;
|
|
903
|
+
border-radius: var(--fd-radius-small);
|
|
904
|
+
padding: 0.2rem 0.4rem 0.2rem calc(0.4rem + var(--fd-tree-depth, 0) * 1.1rem + 1.15rem);
|
|
905
|
+
background-image: repeating-linear-gradient(
|
|
906
|
+
to right,
|
|
907
|
+
transparent 0 0.775rem,
|
|
908
|
+
var(--fd-border-subtle) 0.775rem calc(0.775rem + 1px),
|
|
909
|
+
transparent calc(0.775rem + 1px) 1.1rem
|
|
910
|
+
);
|
|
911
|
+
background-size: calc(var(--fd-tree-depth, 0) * 1.1rem) 100%;
|
|
912
|
+
background-repeat: no-repeat;
|
|
913
|
+
color: var(--fd-fg-soft);
|
|
914
|
+
cursor: default;
|
|
915
|
+
}
|
|
916
|
+
.flowdown .fd-tree-row[data-folder] {
|
|
917
|
+
padding-left: calc(0.4rem + var(--fd-tree-depth, 0) * 1.1rem);
|
|
918
|
+
color: var(--fd-fg);
|
|
919
|
+
cursor: pointer;
|
|
920
|
+
}
|
|
921
|
+
.flowdown .fd-tree-row:hover {
|
|
922
|
+
background-color: var(--fd-veil);
|
|
923
|
+
}
|
|
924
|
+
.flowdown .fd-tree-row:focus-visible {
|
|
925
|
+
outline-offset: -2px;
|
|
926
|
+
}
|
|
927
|
+
.flowdown .fd-tree-chevron,
|
|
928
|
+
.flowdown .fd-tree-icon {
|
|
929
|
+
flex: none;
|
|
930
|
+
width: 0.95rem;
|
|
931
|
+
height: 0.95rem;
|
|
932
|
+
color: var(--fd-fg-faint);
|
|
933
|
+
}
|
|
934
|
+
.flowdown .fd-tree-chevron {
|
|
935
|
+
width: 0.75rem;
|
|
936
|
+
height: 0.75rem;
|
|
937
|
+
transition: transform var(--fd-duration) ease;
|
|
938
|
+
}
|
|
939
|
+
.flowdown .fd-tree-chevron[data-open] {
|
|
940
|
+
transform: rotate(90deg);
|
|
941
|
+
}
|
|
942
|
+
.flowdown .fd-tree-name {
|
|
943
|
+
overflow: hidden;
|
|
944
|
+
text-overflow: ellipsis;
|
|
945
|
+
white-space: nowrap;
|
|
946
|
+
}
|
|
947
|
+
.flowdown .fd-tree-comment {
|
|
948
|
+
overflow: hidden;
|
|
949
|
+
margin-left: 0.5rem;
|
|
950
|
+
text-overflow: ellipsis;
|
|
951
|
+
white-space: nowrap;
|
|
952
|
+
font-family: inherit;
|
|
953
|
+
color: var(--fd-fg-faint);
|
|
954
|
+
}
|
|
955
|
+
.flowdown .fd-tree-comment::before {
|
|
956
|
+
content: '# ';
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/* ─── Checklists (GFM `- [ ] item`) ───
|
|
960
|
+
The box is drawn here, not by the browser: a native one differs per platform, sits off the
|
|
961
|
+
line, and has no quiet state. It stands in the margin, centred on the first line. */
|
|
962
|
+
.flowdown ul.contains-task-list,
|
|
963
|
+
.flowdown ol.contains-task-list {
|
|
964
|
+
padding-left: 0;
|
|
965
|
+
list-style: none;
|
|
966
|
+
}
|
|
967
|
+
.flowdown li.task-list-item {
|
|
968
|
+
position: relative;
|
|
969
|
+
padding-left: 1.6rem;
|
|
970
|
+
}
|
|
971
|
+
.flowdown li.task-list-item input[type='checkbox'] {
|
|
972
|
+
/* Anchor to the first line without making loose paragraphs and nested lists flex columns. */
|
|
973
|
+
position: absolute;
|
|
974
|
+
left: 0;
|
|
975
|
+
top: calc((1lh - 1rem) / 2);
|
|
976
|
+
/* The row's font, so `lh` above is the row's line and not a form control's. */
|
|
977
|
+
font: inherit;
|
|
978
|
+
box-sizing: border-box;
|
|
979
|
+
width: 1rem;
|
|
980
|
+
height: 1rem;
|
|
981
|
+
margin: 0;
|
|
982
|
+
appearance: none;
|
|
983
|
+
border: 1.5px solid var(--fd-border-strong);
|
|
984
|
+
border-radius: 0.3rem;
|
|
985
|
+
background: transparent;
|
|
986
|
+
transition:
|
|
987
|
+
background-color var(--fd-duration) ease,
|
|
988
|
+
border-color var(--fd-duration) ease;
|
|
989
|
+
}
|
|
990
|
+
.flowdown li.task-list-item input[type='checkbox']:checked {
|
|
991
|
+
border-color: var(--fd-fg-soft);
|
|
992
|
+
background-color: var(--fd-fg-soft);
|
|
993
|
+
}
|
|
994
|
+
/* The tick: two sides of a turned box, in the ground's colour. */
|
|
995
|
+
.flowdown li.task-list-item input[type='checkbox']:checked::after {
|
|
996
|
+
content: '';
|
|
997
|
+
position: absolute;
|
|
998
|
+
left: 50%;
|
|
999
|
+
top: 46%;
|
|
1000
|
+
width: 0.25rem;
|
|
1001
|
+
height: 0.5rem;
|
|
1002
|
+
/* The opaque ground when the page's own is translucent (a glass panel). */
|
|
1003
|
+
border: solid var(--fd-bg-solid, var(--fd-bg));
|
|
1004
|
+
border-width: 0 1.75px 1.75px 0;
|
|
1005
|
+
transform: translate(-50%, -50%) rotate(45deg);
|
|
1006
|
+
}
|
|
1007
|
+
.flowdown li.task-list-item input[type='checkbox']:not(:disabled) {
|
|
1008
|
+
cursor: pointer;
|
|
1009
|
+
}
|
|
1010
|
+
.flowdown li.task-list-item input[type='checkbox']:not(:disabled):hover {
|
|
1011
|
+
border-color: var(--fd-fg-soft);
|
|
1012
|
+
}
|
|
1013
|
+
.flowdown li.task-list-item:has(> input:checked, > p:first-child > input:checked) {
|
|
1014
|
+
color: var(--fd-fg-faint);
|
|
1015
|
+
text-decoration: line-through;
|
|
1016
|
+
text-decoration-color: color-mix(in oklab, var(--fd-fg) 30%, transparent);
|
|
1017
|
+
}
|
|
1018
|
+
/* A nested list keeps its own text: only the done item is struck, not what is under it. */
|
|
1019
|
+
.flowdown li.task-list-item:has(> input:checked) > :is(ul, ol) {
|
|
1020
|
+
color: var(--fd-fg);
|
|
1021
|
+
text-decoration: none;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/* code.css */
|
|
1025
|
+
/* ─── Code blocks (fenced code, `CodeBlock`) ───
|
|
1026
|
+
A quiet panel: the language, a download and a copy button in a bar above the code, the code on
|
|
1027
|
+
the veil.
|
|
1028
|
+
No border, so a reply with several blocks does not read as a stack of boxes. */
|
|
1029
|
+
.flowdown .fd-code {
|
|
1030
|
+
margin: 0.8rem 0;
|
|
1031
|
+
border-radius: var(--fd-radius);
|
|
1032
|
+
background: var(--fd-code-bg);
|
|
1033
|
+
}
|
|
1034
|
+
.flowdown .fd-code-bar {
|
|
1035
|
+
display: flex;
|
|
1036
|
+
align-items: center;
|
|
1037
|
+
justify-content: space-between;
|
|
1038
|
+
gap: 0.5rem;
|
|
1039
|
+
min-height: 2rem;
|
|
1040
|
+
padding: 0.25rem 0.35rem 0 0.9rem;
|
|
1041
|
+
font-size: 0.78em;
|
|
1042
|
+
color: var(--fd-fg-faint);
|
|
1043
|
+
}
|
|
1044
|
+
.flowdown .fd-code-language {
|
|
1045
|
+
font-family: var(--fd-font-mono);
|
|
1046
|
+
text-transform: lowercase;
|
|
1047
|
+
}
|
|
1048
|
+
/* The file a fence names: first in the bar, the language pushed to the copy button's side. */
|
|
1049
|
+
.flowdown .fd-code-title {
|
|
1050
|
+
overflow: hidden;
|
|
1051
|
+
min-width: 0;
|
|
1052
|
+
margin-right: auto;
|
|
1053
|
+
text-overflow: ellipsis;
|
|
1054
|
+
white-space: nowrap;
|
|
1055
|
+
font-family: var(--fd-font-mono);
|
|
1056
|
+
color: var(--fd-fg-soft);
|
|
1057
|
+
}
|
|
1058
|
+
.flowdown .fd-code-title + .fd-code-language {
|
|
1059
|
+
flex: none;
|
|
1060
|
+
}
|
|
1061
|
+
.flowdown .fd-code-bar > .fd-code-language:first-child {
|
|
1062
|
+
margin-right: auto;
|
|
1063
|
+
}
|
|
1064
|
+
/* With no language or title before them, the buttons still sit at the end of the bar. */
|
|
1065
|
+
.flowdown .fd-code-bar > .fd-code-download:first-child {
|
|
1066
|
+
margin-left: auto;
|
|
1067
|
+
}
|
|
1068
|
+
.flowdown :is(.fd-code-copy, .fd-code-download) {
|
|
1069
|
+
display: inline-grid;
|
|
1070
|
+
flex: none;
|
|
1071
|
+
place-items: center;
|
|
1072
|
+
width: 1.75rem;
|
|
1073
|
+
height: 1.75rem;
|
|
1074
|
+
border: 0;
|
|
1075
|
+
border-radius: var(--fd-radius-small);
|
|
1076
|
+
background: none;
|
|
1077
|
+
color: var(--fd-fg-faint);
|
|
1078
|
+
cursor: pointer;
|
|
1079
|
+
transition:
|
|
1080
|
+
color var(--fd-duration) ease,
|
|
1081
|
+
background-color var(--fd-duration) ease;
|
|
1082
|
+
}
|
|
1083
|
+
.flowdown .fd-code-download + .fd-code-copy {
|
|
1084
|
+
margin-left: -0.3rem;
|
|
1085
|
+
}
|
|
1086
|
+
.flowdown :is(.fd-code-copy, .fd-code-download):hover {
|
|
1087
|
+
background: var(--fd-veil-strong);
|
|
1088
|
+
color: var(--fd-fg);
|
|
1089
|
+
}
|
|
1090
|
+
.flowdown .fd-code-copy[data-copied] {
|
|
1091
|
+
color: var(--fd-success);
|
|
1092
|
+
}
|
|
1093
|
+
.flowdown :is(.fd-code-copy, .fd-code-download) svg {
|
|
1094
|
+
width: 0.95rem;
|
|
1095
|
+
height: 0.95rem;
|
|
1096
|
+
}
|
|
1097
|
+
/* A finger needs a 44 px target; a mouse keeps the small buttons. */
|
|
1098
|
+
@media (pointer: coarse) {
|
|
1099
|
+
.flowdown :is(.fd-code-copy, .fd-code-download) {
|
|
1100
|
+
width: 44px;
|
|
1101
|
+
height: 44px;
|
|
1102
|
+
}
|
|
1103
|
+
.flowdown .fd-code-download + .fd-code-copy {
|
|
1104
|
+
margin-left: 0;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
.flowdown pre {
|
|
1108
|
+
margin: 0;
|
|
1109
|
+
overflow-x: auto;
|
|
1110
|
+
padding: 0.25rem 0.9rem 0.8rem;
|
|
1111
|
+
font-family: var(--fd-font-mono);
|
|
1112
|
+
font-size: 0.86em;
|
|
1113
|
+
line-height: 1.55;
|
|
1114
|
+
color: var(--fd-code-fg);
|
|
1115
|
+
tab-size: 2;
|
|
1116
|
+
}
|
|
1117
|
+
/* A <pre> outside a code block (a page's own, a diagram's source) takes the whole panel look. */
|
|
1118
|
+
.flowdown :not(.fd-code) > pre {
|
|
1119
|
+
margin: 0.8rem 0;
|
|
1120
|
+
border-radius: var(--fd-radius);
|
|
1121
|
+
background: var(--fd-code-bg);
|
|
1122
|
+
padding: 0.8rem 0.9rem;
|
|
1123
|
+
}
|
|
1124
|
+
.flowdown .fd-diagram > pre {
|
|
1125
|
+
margin: 0;
|
|
1126
|
+
}
|
|
1127
|
+
.flowdown pre code {
|
|
1128
|
+
font: inherit;
|
|
1129
|
+
white-space: pre;
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/* Highlighted code (`@localix-ai/flowdown/highlight`, or any highlighter that emits highlight.js classes). */
|
|
1133
|
+
.flowdown .hljs-comment,
|
|
1134
|
+
.flowdown .hljs-quote {
|
|
1135
|
+
color: var(--fd-code-comment);
|
|
1136
|
+
font-style: italic;
|
|
1137
|
+
}
|
|
1138
|
+
.flowdown :is(.hljs-keyword, .hljs-selector-tag, .hljs-doctag, .hljs-meta .hljs-keyword) {
|
|
1139
|
+
color: var(--fd-code-keyword);
|
|
1140
|
+
}
|
|
1141
|
+
.flowdown :is(.hljs-string, .hljs-regexp, .hljs-meta .hljs-string) {
|
|
1142
|
+
color: var(--fd-code-string);
|
|
1143
|
+
}
|
|
1144
|
+
.flowdown
|
|
1145
|
+
:is(
|
|
1146
|
+
.hljs-number,
|
|
1147
|
+
.hljs-literal,
|
|
1148
|
+
.hljs-variable,
|
|
1149
|
+
.hljs-template-variable,
|
|
1150
|
+
.hljs-attr,
|
|
1151
|
+
.hljs-attribute,
|
|
1152
|
+
.hljs-symbol,
|
|
1153
|
+
.hljs-bullet
|
|
1154
|
+
) {
|
|
1155
|
+
color: var(--fd-code-number);
|
|
1156
|
+
}
|
|
1157
|
+
.flowdown :is(.hljs-title, .hljs-title.function_, .hljs-section) {
|
|
1158
|
+
color: var(--fd-code-function);
|
|
1159
|
+
}
|
|
1160
|
+
.flowdown :is(.hljs-type, .hljs-built_in, .hljs-title.class_, .hljs-params, .hljs-meta) {
|
|
1161
|
+
color: var(--fd-code-type);
|
|
1162
|
+
}
|
|
1163
|
+
.flowdown :is(.hljs-tag, .hljs-name, .hljs-selector-id, .hljs-selector-class) {
|
|
1164
|
+
color: var(--fd-code-tag);
|
|
1165
|
+
}
|
|
1166
|
+
/* A diff: the added and the removed lines in the status hues, the hunk header quiet. */
|
|
1167
|
+
.flowdown .hljs-addition {
|
|
1168
|
+
color: var(--fd-success);
|
|
1169
|
+
}
|
|
1170
|
+
.flowdown .hljs-deletion {
|
|
1171
|
+
color: var(--fd-danger);
|
|
1172
|
+
}
|
|
1173
|
+
.flowdown .language-diff :is(.hljs-meta, .hljs-comment) {
|
|
1174
|
+
color: var(--fd-fg-faint);
|
|
1175
|
+
font-style: normal;
|
|
1176
|
+
}
|
|
1177
|
+
.flowdown .hljs-emphasis {
|
|
1178
|
+
font-style: italic;
|
|
1179
|
+
}
|
|
1180
|
+
.flowdown .hljs-strong {
|
|
1181
|
+
font-weight: 600;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/* ─── The caret after a streaming reply (`<Markdown streaming>`) ───
|
|
1185
|
+
On the last line, when the reply ends in text. It breathes rather than blinks: a hard
|
|
1186
|
+
blink at the end of moving text drew the eye away from the words. */
|
|
1187
|
+
@keyframes fd-caret {
|
|
1188
|
+
50% {
|
|
1189
|
+
opacity: 0.2;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
.flowdown[data-caret] > :last-child:is(p, h1, h2, h3, h4, h5, h6)::after,
|
|
1193
|
+
.flowdown[data-caret] > :last-child:is(ul, ol) > li:last-child::after,
|
|
1194
|
+
.flowdown[data-caret] > :last-child:is(blockquote, aside) p:last-child::after {
|
|
1195
|
+
content: '';
|
|
1196
|
+
display: inline-block;
|
|
1197
|
+
width: 0.5em;
|
|
1198
|
+
height: 1em;
|
|
1199
|
+
margin-left: 0.15em;
|
|
1200
|
+
border-radius: 1px;
|
|
1201
|
+
background: var(--fd-caret-color, currentColor);
|
|
1202
|
+
vertical-align: -0.15em;
|
|
1203
|
+
opacity: 0.55;
|
|
1204
|
+
animation: fd-caret 1s ease-in-out infinite;
|
|
1205
|
+
}
|
|
1206
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1207
|
+
.flowdown[data-caret] *::after {
|
|
1208
|
+
animation: none;
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
/* diagram.css */
|
|
1213
|
+
/* ─── A drawn diagram's toolbar and its enlarged viewer (`mermaid/diagram.tsx`, `viewer.tsx`) ───
|
|
1214
|
+
The toolbar sits over the diagram's top right corner and shows when the pointer is over the
|
|
1215
|
+
figure or the focus is in it; under a finger, where there is no hover, it always shows. */
|
|
1216
|
+
.flowdown .fd-diagram {
|
|
1217
|
+
position: relative;
|
|
1218
|
+
}
|
|
1219
|
+
.flowdown .fd-diagram-actions {
|
|
1220
|
+
position: absolute;
|
|
1221
|
+
top: 0.35rem;
|
|
1222
|
+
right: 0.35rem;
|
|
1223
|
+
z-index: 1;
|
|
1224
|
+
display: flex;
|
|
1225
|
+
gap: 0.125rem;
|
|
1226
|
+
border: 1px solid var(--fd-border-subtle);
|
|
1227
|
+
border-radius: var(--fd-radius-small);
|
|
1228
|
+
background: color-mix(in oklab, var(--fd-bg) 88%, transparent);
|
|
1229
|
+
padding: 0.125rem;
|
|
1230
|
+
opacity: 0;
|
|
1231
|
+
transition: opacity var(--fd-duration) ease;
|
|
1232
|
+
}
|
|
1233
|
+
.flowdown .fd-diagram:is(:hover, :focus-within) .fd-diagram-actions {
|
|
1234
|
+
opacity: 1;
|
|
1235
|
+
}
|
|
1236
|
+
.flowdown .fd-diagram-action {
|
|
1237
|
+
display: inline-grid;
|
|
1238
|
+
place-items: center;
|
|
1239
|
+
min-width: 1.75rem;
|
|
1240
|
+
height: 1.75rem;
|
|
1241
|
+
border: 0;
|
|
1242
|
+
border-radius: var(--fd-radius-small);
|
|
1243
|
+
background: none;
|
|
1244
|
+
padding: 0;
|
|
1245
|
+
font: inherit;
|
|
1246
|
+
color: var(--fd-fg-faint);
|
|
1247
|
+
cursor: pointer;
|
|
1248
|
+
transition:
|
|
1249
|
+
color var(--fd-duration) ease,
|
|
1250
|
+
background-color var(--fd-duration) ease;
|
|
1251
|
+
}
|
|
1252
|
+
.flowdown .fd-diagram-action:hover {
|
|
1253
|
+
background: var(--fd-veil-strong);
|
|
1254
|
+
color: var(--fd-fg);
|
|
1255
|
+
}
|
|
1256
|
+
.flowdown .fd-diagram-action[data-copied] {
|
|
1257
|
+
color: var(--fd-success);
|
|
1258
|
+
}
|
|
1259
|
+
.flowdown .fd-diagram-action svg {
|
|
1260
|
+
width: 0.95rem;
|
|
1261
|
+
height: 0.95rem;
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/* The viewer: a modal dialog over most of the window, the controls in a bar above the stage. */
|
|
1265
|
+
.flowdown .fd-diagram-viewer {
|
|
1266
|
+
box-sizing: border-box;
|
|
1267
|
+
width: min(80rem, calc(100vw - 2rem));
|
|
1268
|
+
max-width: none;
|
|
1269
|
+
height: min(60rem, calc(100dvh - 2rem));
|
|
1270
|
+
max-height: none;
|
|
1271
|
+
margin: auto;
|
|
1272
|
+
border: 1px solid var(--fd-border);
|
|
1273
|
+
border-radius: var(--fd-radius);
|
|
1274
|
+
background: var(--fd-bg);
|
|
1275
|
+
padding: 0;
|
|
1276
|
+
color: var(--fd-fg);
|
|
1277
|
+
overflow: hidden;
|
|
1278
|
+
}
|
|
1279
|
+
.flowdown .fd-diagram-viewer[open] {
|
|
1280
|
+
display: flex;
|
|
1281
|
+
flex-direction: column;
|
|
1282
|
+
}
|
|
1283
|
+
.flowdown .fd-diagram-viewer::backdrop {
|
|
1284
|
+
background: rgb(0 0 0 / 0.45);
|
|
1285
|
+
}
|
|
1286
|
+
.flowdown .fd-diagram-viewer-bar {
|
|
1287
|
+
display: flex;
|
|
1288
|
+
flex: none;
|
|
1289
|
+
align-items: center;
|
|
1290
|
+
gap: 0.125rem;
|
|
1291
|
+
border-bottom: 1px solid var(--fd-border-subtle);
|
|
1292
|
+
padding: 0.35rem;
|
|
1293
|
+
}
|
|
1294
|
+
.flowdown .fd-diagram-zoom {
|
|
1295
|
+
min-width: 3.5rem;
|
|
1296
|
+
font-size: 0.8em;
|
|
1297
|
+
font-variant-numeric: tabular-nums;
|
|
1298
|
+
}
|
|
1299
|
+
.flowdown .fd-diagram-close {
|
|
1300
|
+
margin-left: auto;
|
|
1301
|
+
}
|
|
1302
|
+
/* The stage takes every gesture itself: no browser pan or pinch-zoom of the page under it. */
|
|
1303
|
+
.flowdown .fd-diagram-stage {
|
|
1304
|
+
display: flex;
|
|
1305
|
+
flex: 1;
|
|
1306
|
+
align-items: center;
|
|
1307
|
+
justify-content: center;
|
|
1308
|
+
min-height: 0;
|
|
1309
|
+
overflow: hidden;
|
|
1310
|
+
cursor: grab;
|
|
1311
|
+
touch-action: none;
|
|
1312
|
+
user-select: none;
|
|
1313
|
+
}
|
|
1314
|
+
.flowdown .fd-diagram-stage[data-moving] {
|
|
1315
|
+
cursor: grabbing;
|
|
1316
|
+
}
|
|
1317
|
+
.flowdown .fd-diagram-stage:focus-visible {
|
|
1318
|
+
outline-offset: -2px;
|
|
1319
|
+
}
|
|
1320
|
+
.flowdown .fd-diagram-viewer-canvas {
|
|
1321
|
+
flex: none;
|
|
1322
|
+
transform-origin: center;
|
|
1323
|
+
transition: transform var(--fd-duration-slow) var(--fd-ease);
|
|
1324
|
+
}
|
|
1325
|
+
/* A drag, a pinch or the wheel follows the hand; only a button or a key glides. */
|
|
1326
|
+
.flowdown .fd-diagram-stage[data-moving] .fd-diagram-viewer-canvas {
|
|
1327
|
+
transition: none;
|
|
1328
|
+
}
|
|
1329
|
+
.flowdown .fd-diagram-viewer-canvas svg {
|
|
1330
|
+
display: block;
|
|
1331
|
+
width: 100%;
|
|
1332
|
+
/* Mermaid caps the picture's width in its own style attribute; here the canvas sizes it. */
|
|
1333
|
+
max-width: none !important;
|
|
1334
|
+
height: 100%;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
/* Under a finger, where there is no hover, the toolbar always shows and every control is a 44 px
|
|
1338
|
+
target. A phone's viewer is the whole screen. */
|
|
1339
|
+
@media (hover: none), (pointer: coarse) {
|
|
1340
|
+
.flowdown .fd-diagram-actions {
|
|
1341
|
+
opacity: 1;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
@media (pointer: coarse) {
|
|
1345
|
+
.flowdown .fd-diagram-action {
|
|
1346
|
+
min-width: 2.75rem;
|
|
1347
|
+
height: 2.75rem;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
@media (max-width: 40rem) {
|
|
1351
|
+
.flowdown .fd-diagram-viewer {
|
|
1352
|
+
width: 100vw;
|
|
1353
|
+
height: 100dvh;
|
|
1354
|
+
border: 0;
|
|
1355
|
+
border-radius: 0;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1359
|
+
.flowdown :is(.fd-diagram-actions, .fd-diagram-viewer-canvas) {
|
|
1360
|
+
transition: none;
|
|
1361
|
+
}
|
|
1362
|
+
}
|