@dataimago/css 0.1.0-alpha.22 → 0.1.0-alpha.24

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.
Files changed (56) hide show
  1. package/README.md +70 -0
  2. package/dist/bin/dataimago-sync.mjs +19 -1
  3. package/dist/dataviz/dataimago-dataviz.css +1 -1
  4. package/dist/dataviz/dataimago-dataviz.json +2 -2
  5. package/dist/dataviz/dataimago-dataviz.tex +1 -1
  6. package/dist/dataviz/dataimago_dataviz.R +1 -1
  7. package/dist/figures/dataimago-figure.sty +1 -1
  8. package/dist/figures/dataimago-tokens.sty +1 -1
  9. package/dist/fonts/cyrillic/fonts.css +1 -1
  10. package/dist/fonts/cyrillic-ext/fonts.css +1 -1
  11. package/dist/fonts/greek/fonts.css +1 -1
  12. package/dist/fonts/greek-ext/fonts.css +1 -1
  13. package/dist/fonts/josefin/fonts.css +1 -1
  14. package/dist/fonts/lang.css +1 -1
  15. package/dist/fonts/latin/fonts.css +1 -1
  16. package/dist/fonts/latin-ext/fonts.css +1 -1
  17. package/dist/fonts/math/fonts.css +1 -1
  18. package/dist/fonts/pkg/fonts.css +1 -1
  19. package/dist/fonts/vietnamese/fonts.css +1 -1
  20. package/dist/latex/dataimago-tokens.sty +1 -1
  21. package/dist/latex/dataimago.sty +1 -1
  22. package/dist/outputs.json +53 -44
  23. package/dist/quarto/_extensions/dataimago/monograph/_extension.yml +1 -1
  24. package/dist/quarto/_extensions/dataimago/monograph/dataimago-base.sty +1 -1
  25. package/dist/quarto/_extensions/dataimago/monograph/dataimago-monograph.sty +1 -1
  26. package/dist/quarto/_extensions/dataimago/monograph/dataimago-tokens.sty +1 -1
  27. package/dist/quarto/_extensions/dataimago/monograph/filters/figure-plate.lua +1 -1
  28. package/dist/quarto/_extensions/dataimago/monograph/filters/matter.lua +1 -1
  29. package/dist/quarto/_extensions/dataimago/monograph/filters/pkg-name.lua +1 -1
  30. package/dist/quarto/_extensions/dataimago/monograph/partials/before-body.tex +1 -1
  31. package/dist/quarto/_extensions/dataimago/monograph/partials/title.tex +1 -1
  32. package/dist/quarto/_extensions/dataimago/pkgsite/_extension.yml +28 -0
  33. package/dist/quarto/_extensions/dataimago/pkgsite/components.scss +243 -0
  34. package/dist/quarto/_extensions/dataimago/pkgsite/dataimago-dark.scss +344 -0
  35. package/dist/quarto/_extensions/dataimago/pkgsite/dataimago-light.scss +338 -0
  36. package/dist/quarto/_extensions/dataimago/pkgsite/filters/landing.lua +251 -0
  37. package/dist/quarto/_extensions/dataimago/pkgsite/filters/provenance.lua +212 -0
  38. package/dist/quarto/_extensions/dataimago/pkgsite/hero-fallback.svg +53 -0
  39. package/dist/quarto/_extensions/dataimago/pkgsite/pkgsite-hero.js +99 -0
  40. package/dist/quarto/_extensions/dataimago/pkgsite/pkgsite.scss +281 -0
  41. package/dist/quarto/components.scss +1 -1
  42. package/dist/quarto/dataimago-dark.scss +1 -1
  43. package/dist/quarto/dataimago-light.scss +1 -1
  44. package/dist/templates/KNOWLEDGE-explorer.md +1 -1
  45. package/dist/templates/KNOWLEDGE-framework.md +1 -1
  46. package/dist/templates/KNOWLEDGE-research.md +1 -1
  47. package/dist/templates/quarto_website/README.md +4 -2
  48. package/dist/templates/quarto_website/_quarto.yml.template +1 -1
  49. package/dist/templates/quarto_website/about.qmd.template +1 -1
  50. package/dist/templates/quarto_website/assets/css/lang.css +1 -1
  51. package/dist/templates/quarto_website/assets/js/custom-anchors.js +1 -1
  52. package/dist/templates/quarto_website/assets/js/logo-switch.js +1 -1
  53. package/dist/templates/quarto_website/assets/js/scroll.js +1 -1
  54. package/dist/templates/quarto_website/ethics.qmd.template +1 -1
  55. package/dist/templates/quarto_website/index.qmd.template +1 -1
  56. package/package.json +1 -1
@@ -0,0 +1,212 @@
1
+ -- @dataimago/css@0.1.0-alpha.24 dist/quarto/_extensions/dataimago/pkgsite/filters/provenance.lua · sha256:68e33df59cd4c88e1d4bd51bdd3ec45bfa62f64a1b27c8ed305cb59d4e49853b · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
+ -- provenance.lua: the AI-composed label. Pandoc 3 Lua filter for Quarto >= 1.8.
3
+ --
4
+ -- A page whose front matter carries `knowledge:` gets a div.di-provenance before its first block; a page
5
+ -- without the key is returned unchanged. The label is how a reader knows the page was drafted by a model and
6
+ -- whether the maintainer has approved it, so the strings are fixed:
7
+ -- draft: AI-composed draft: not yet approved by the maintainer
8
+ -- approved: AI-composed · drafted by {composer} from source {sha7} · {edited and }approved by {who}, {date} · How this page was made
9
+ -- stale: appends " · written against {sha7}; the code has changed since" to whichever label is shown
10
+ --
11
+ -- Rules:
12
+ -- * Every interpolated value is a Pandoc Str, so the HTML writer escapes it.
13
+ -- * source_sha must match ^[0-9a-f]{7,40}$ (shown as its first 7 characters) or the render fails: a malformed
14
+ -- sha is never printed. source_url is linked only if it matches ^https?://; otherwise the sha is unlinked.
15
+ -- * `about` is site-root relative; the href is prefixed with "../" once per directory the page sits below the
16
+ -- project root, and a .qmd extension becomes .html. Absolute paths and URL schemes are not linked.
17
+ -- * status: approved without composer, approved_by or approved_on fails the render: Phase D writes this block, so
18
+ -- a gap is a generator bug, and a silent downgrade to "draft" would hide it. approved_on must be a real
19
+ -- YYYY-MM-DD date; edited_by_author and stale must be YAML booleans (not "true", "yes" or 1).
20
+ -- * Every failure names the page.
21
+
22
+ local stringify = pandoc.utils.stringify
23
+
24
+ local function text(v)
25
+ if v == nil then return '' end
26
+ local t = pandoc.utils.type(v)
27
+ if t == 'string' then return v end
28
+ if t == 'boolean' or t == 'number' then return tostring(v) end
29
+ if t == 'Inlines' then
30
+ local out = {}
31
+ for _, el in ipairs(v) do
32
+ if el.t == 'Str' then out[#out + 1] = el.text
33
+ elseif el.t == 'Space' or el.t == 'SoftBreak' then out[#out + 1] = ' '
34
+ elseif el.t == 'RawInline' or el.t == 'Code' then out[#out + 1] = el.text
35
+ else out[#out + 1] = stringify(el) end
36
+ end
37
+ return table.concat(out)
38
+ end
39
+ return stringify(v)
40
+ end
41
+
42
+ local function trim(s) return (s:gsub('^%s+', ''):gsub('%s+$', '')) end
43
+
44
+ local function page_name()
45
+ local input = quarto and quarto.doc and quarto.doc.input_file
46
+ if not input then
47
+ local inputs = PANDOC_STATE and PANDOC_STATE.input_files
48
+ input = inputs and inputs[1]
49
+ end
50
+ if not input then return '(unknown page)' end
51
+ local root = quarto and quarto.project and quarto.project.directory
52
+ if root then
53
+ root = root:gsub('/+$', '')
54
+ if input:sub(1, #root + 1) == root .. '/' then return input:sub(#root + 2) end
55
+ end
56
+ return input
57
+ end
58
+
59
+ local function warn(msg)
60
+ io.stderr:write('provenance.lua: WARNING: ' .. page_name() .. ': ' .. msg .. '\n')
61
+ end
62
+
63
+ -- Quarto's Lua environment logs error() and carries on, which would publish a page with no label (or the
64
+ -- wrong one). Exiting non-zero is what actually refuses the render.
65
+ local function fail(msg)
66
+ io.stderr:write('ERROR: provenance.lua: ' .. page_name() .. ': ' .. msg .. '\n')
67
+ os.exit(1)
68
+ end
69
+
70
+ -- plain text -> Str/Space inlines (Pandoc escapes them on output); leading and trailing spaces are kept
71
+ local function words(s)
72
+ local out = pandoc.Inlines({})
73
+ for space, w in s:gmatch('(%s*)(%S+)') do
74
+ if space ~= '' then out:insert(pandoc.Space()) end
75
+ out:insert(pandoc.Str(w))
76
+ end
77
+ if s:match('%s$') then out:insert(pandoc.Space()) end
78
+ return out
79
+ end
80
+
81
+ local function append(dst, src)
82
+ for _, el in ipairs(src) do dst:insert(el) end
83
+ end
84
+
85
+ local function dirname(p) return (p:match('^(.*)/[^/]*$')) or '' end
86
+
87
+ -- how many directories below the project root this page is
88
+ local function depth()
89
+ local input = quarto and quarto.doc and quarto.doc.input_file
90
+ if not input then
91
+ local inputs = PANDOC_STATE and PANDOC_STATE.input_files
92
+ input = inputs and inputs[1]
93
+ end
94
+ local root = quarto and quarto.project and quarto.project.directory
95
+ if not input or not root then return 0 end
96
+ root = root:gsub('/+$', '')
97
+ local rel
98
+ if input:sub(1, #root + 1) == root .. '/' then rel = input:sub(#root + 2) else return 0 end
99
+ local dir = dirname(rel)
100
+ if dir == '' then return 0 end
101
+ local n = 0
102
+ for _ in dir:gmatch('[^/]+') do n = n + 1 end
103
+ return n
104
+ end
105
+
106
+ local function about_href(about)
107
+ about = trim(about)
108
+ if about == '' then return nil end
109
+ if about:sub(1, 1) == '/' or about:match('^%a[%w+.%-]*:') then
110
+ warn('knowledge.about must be a site-relative path; "' .. about .. '" is not linked')
111
+ return nil
112
+ end
113
+ for seg in about:gmatch('[^/]+') do
114
+ if seg == '..' then
115
+ warn('knowledge.about must not contain a ".." segment; "' .. about .. '" is not linked')
116
+ return nil
117
+ end
118
+ end
119
+ -- Quarto does not rewrite links inside a filter-built block, so point at the rendered page
120
+ about = about:gsub('%.qmd$', '.html')
121
+ about = about:gsub('%.qmd([#?])', '.html%1', 1)
122
+ return string.rep('../', depth()) .. about
123
+ end
124
+
125
+ local function sha7(sha)
126
+ sha = trim(sha)
127
+ if not (sha:match('^[0-9a-f]+$') and #sha >= 7 and #sha <= 40) then
128
+ fail('knowledge.source_sha must be 7 to 40 lowercase hex characters; refusing to print it')
129
+ end
130
+ return sha:sub(1, 7)
131
+ end
132
+
133
+ -- absent -> false; a YAML boolean -> itself; anything else (including the strings "true", "yes", "1") fails
134
+ local function bool(k, key)
135
+ local v = k[key]
136
+ if v == nil then return false end
137
+ if type(v) == 'boolean' then return v end
138
+ fail('knowledge.' .. key .. ' must be a boolean (true or false), not "' .. text(v) .. '"')
139
+ end
140
+
141
+ local function valid_date(s)
142
+ local y, m, d = s:match('^(%d%d%d%d)-(%d%d)-(%d%d)$')
143
+ if not y then return false end
144
+ y, m, d = tonumber(y), tonumber(m), tonumber(d)
145
+ if m < 1 or m > 12 or d < 1 then return false end
146
+ local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
147
+ if (y % 4 == 0 and y % 100 ~= 0) or y % 400 == 0 then days[2] = 29 end
148
+ return d <= days[m]
149
+ end
150
+
151
+ function Pandoc(doc)
152
+ local k = doc.meta.knowledge
153
+ if k == nil then return nil end
154
+ if pandoc.utils.type(k) ~= 'table' and pandoc.utils.type(k) ~= 'Map' then
155
+ fail('knowledge: must be a mapping')
156
+ end
157
+ local function get(key) return trim(text(k[key])) end
158
+
159
+ local status = get('status')
160
+ if status ~= 'draft' and status ~= 'approved' then
161
+ fail('knowledge.status must be "draft" or "approved"')
162
+ end
163
+ local stale = bool(k, 'stale')
164
+ local sha_raw = get('source_sha')
165
+ local short
166
+ if sha_raw ~= '' then short = sha7(sha_raw) end
167
+ if (status == 'approved' or stale) and not short then
168
+ fail('knowledge.source_sha is required for an approved or stale page')
169
+ end
170
+
171
+ local approved = status == 'approved'
172
+ local edited = bool(k, 'edited_by_author')
173
+ if approved then
174
+ for _, key in ipairs({ 'composer', 'approved_by', 'approved_on' }) do
175
+ if get(key) == '' then fail('knowledge.status is approved but knowledge.' .. key .. ' is missing') end
176
+ end
177
+ if not valid_date(get('approved_on')) then
178
+ fail('knowledge.approved_on must be a real date written YYYY-MM-DD, not "' .. get('approved_on') .. '"')
179
+ end
180
+ end
181
+
182
+ local inl = pandoc.Inlines({})
183
+ if not approved then
184
+ append(inl, words('AI-composed draft: not yet approved by the maintainer'))
185
+ else
186
+ append(inl, words('AI-composed · drafted by ' .. get('composer') .. ' from source'))
187
+ inl:insert(pandoc.Space())
188
+ local url = get('source_url')
189
+ if url:match('^https?://') then
190
+ inl:insert(pandoc.Link({ pandoc.Str(short) }, url))
191
+ else
192
+ inl:insert(pandoc.Str(short))
193
+ end
194
+ local who = edited and 'edited and approved by ' or 'approved by '
195
+ append(inl, words(' · ' .. who .. get('approved_by') .. ', ' .. get('approved_on')))
196
+ local href = about_href(get('about'))
197
+ if href then
198
+ append(inl, words(' ·'))
199
+ inl:insert(pandoc.Space())
200
+ inl:insert(pandoc.Link(words('How this page was made'), href))
201
+ end
202
+ end
203
+ if stale then
204
+ append(inl, words(' · written against ' .. short .. '; the code has changed since'))
205
+ end
206
+
207
+ local classes = { 'di-provenance', approved and 'di-provenance-approved' or 'di-provenance-draft' }
208
+ if stale then classes[#classes + 1] = 'di-provenance-stale' end
209
+ local div = pandoc.Div({ pandoc.Para(inl) }, pandoc.Attr('', classes, { { 'role', 'note' } }))
210
+ doc.blocks:insert(1, div)
211
+ return doc
212
+ end
@@ -0,0 +1,53 @@
1
+ <!-- @dataimago/css@0.1.0-alpha.24 dist/quarto/_extensions/dataimago/pkgsite/hero-fallback.svg · sha256:60a284fe66f799d46a383ddaba18712ac896aa05cece9b77d28f56e0767309f3 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync -->
2
+ <svg class="di-hero-fallback" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800" preserveAspectRatio="xMidYMid meet" focusable="false">
3
+ <style>
4
+ .di-hero-fallback { display: block; width: 100%; height: 100%; }
5
+ .di-hero-fallback .axis { stroke: var(--color-border-moderate, #8a8a85); stroke-width: 2; fill: none; stroke-linecap: round; }
6
+ .di-hero-fallback .grid { stroke: var(--color-border-subtle, #c9c9c4); stroke-width: 1; fill: none; }
7
+ .di-hero-fallback .curve { fill: none; stroke-width: 5; stroke-linecap: round; }
8
+ .di-hero-fallback .c1 { stroke: var(--color-interactive-primary, #1d3b2f); }
9
+ .di-hero-fallback .c2 { stroke: var(--color-dataviz-categorical-1, #0072b2); }
10
+ .di-hero-fallback .c3 { stroke: var(--color-dataviz-categorical-2, #d55e00); }
11
+ .di-hero-fallback .c4 { stroke: var(--color-dataviz-categorical-3, #009e73); }
12
+ .di-hero-fallback .c5 { stroke: var(--color-dataviz-categorical-5, #0072b2); }
13
+ .di-hero-fallback .c6 { stroke: var(--color-interactive-accent, #b45f06); }
14
+ .di-hero-fallback .c7 { stroke: var(--color-content-secondary, #5b5b57); stroke-width: 3; }
15
+ .di-hero-fallback .dot { stroke: none; }
16
+ .di-hero-fallback .d1 { fill: var(--color-interactive-primary, #1d3b2f); }
17
+ .di-hero-fallback .d3 { fill: var(--color-dataviz-categorical-2, #d55e00); }
18
+ .di-hero-fallback .d5 { fill: var(--color-dataviz-categorical-5, #0072b2); }
19
+ @media (prefers-reduced-motion: no-preference) {
20
+ .di-hero-fallback .curve {
21
+ stroke-dasharray: 1;
22
+ stroke-dashoffset: 1;
23
+ animation-name: di-hero-draw;
24
+ animation-duration: 2400ms;
25
+ animation-timing-function: ease-in-out;
26
+ animation-iteration-count: 3;
27
+ animation-fill-mode: both;
28
+ }
29
+ .di-hero-fallback .c2 { animation-delay: 120ms; }
30
+ .di-hero-fallback .c3 { animation-delay: 240ms; }
31
+ .di-hero-fallback .c4 { animation-delay: 360ms; }
32
+ .di-hero-fallback .c5 { animation-delay: 480ms; }
33
+ .di-hero-fallback .c6 { animation-delay: 600ms; }
34
+ .di-hero-fallback .c7 { animation-delay: 720ms; }
35
+ @keyframes di-hero-draw {
36
+ from { stroke-dashoffset: 1; }
37
+ to { stroke-dashoffset: 0; }
38
+ }
39
+ }
40
+ </style>
41
+ <path class="grid" d="M80 560H720M80 400H720M80 240H720M80 80H720"/>
42
+ <path class="axis" d="M80 80V720H720"/>
43
+ <path class="curve c7" pathLength="1" d="M80 720C240 716 400 690 720 640"/>
44
+ <path class="curve c6" pathLength="1" d="M80 720C230 700 400 640 720 520"/>
45
+ <path class="curve c5" pathLength="1" d="M80 720C220 690 400 590 720 410"/>
46
+ <path class="curve c4" pathLength="1" d="M80 720C210 670 390 540 720 310"/>
47
+ <path class="curve c3" pathLength="1" d="M80 720C190 640 370 470 720 210"/>
48
+ <path class="curve c2" pathLength="1" d="M80 720C170 600 340 400 720 140"/>
49
+ <path class="curve c1" pathLength="1" d="M80 720C150 560 300 330 720 90"/>
50
+ <circle class="dot d1" cx="720" cy="90" r="9"/>
51
+ <circle class="dot d3" cx="720" cy="210" r="7"/>
52
+ <circle class="dot d5" cx="720" cy="410" r="7"/>
53
+ </svg>
@@ -0,0 +1,99 @@
1
+ // @dataimago/css@0.1.0-alpha.24 dist/quarto/_extensions/dataimago/pkgsite/pkgsite-hero.js · sha256:372b3ff2e24a7f3ce0973f50abc31b491465ba0e973b6cf6f917ea41dd21ea5c · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
+ /**
3
+ * pkgsite hero loader (spec "Hero inputs"). Loaded only for `hero.kind: js`.
4
+ *
5
+ * The module at `data-hero-src` is imported only when motion is allowed. Its default export is
6
+ * `mount(el, { signal }) -> { pause(), play(), destroy() }`; a result without pause and play is refused
7
+ * (motion-lint cannot see JS, so the contract is enforced here, at runtime). The poster stays visible until a
8
+ * mount succeeds, and on any failure, so the page never breaks. The module and the poster must come from the
9
+ * site's own origin (a data: poster in a raster type is the one exception).
10
+ */
11
+
12
+ const REDUCED = '(prefers-reduced-motion: reduce)';
13
+
14
+ const RASTER_DATA = /^data:image\/(png|jpeg|gif|webp)[;,]/i;
15
+
16
+ export function initHeroes({
17
+ document: doc = globalThis.document,
18
+ window: win = globalThis.window,
19
+ importFn = (href) => import(href),
20
+ console: log = globalThis.console,
21
+ } = {}) {
22
+ const none = { destroy() {}, ready: Promise.resolve() };
23
+ if (!doc || !win) return none;
24
+ if (win.matchMedia?.(REDUCED).matches) return none;
25
+ const mounts = [...doc.querySelectorAll('.di-hero-mount')].filter((el) => el.dataset.heroSrc);
26
+ if (mounts.length === 0) return none;
27
+
28
+ const ac = new AbortController();
29
+ const box = doc.getElementById('di-hero-pause');
30
+ const live = [];
31
+ let warned = false;
32
+ const warn = (msg, err) => {
33
+ if (warned) return;
34
+ warned = true;
35
+ log.warn(`pkgsite-hero: ${msg}`, err ?? '');
36
+ };
37
+ // Same scheme and origin as the page. blob:https://site/x reports the page's origin, so the scheme is compared
38
+ // too; data: and javascript: have origin "null", and a "null" page origin (file:) matches nothing.
39
+ const sameOrigin = (src) => {
40
+ try {
41
+ const u = new URL(src, doc.baseURI);
42
+ const b = new URL(doc.baseURI);
43
+ return b.origin !== 'null' && u.origin === b.origin && u.protocol === b.protocol;
44
+ } catch { return false; }
45
+ };
46
+
47
+ const set = (h, paused) => {
48
+ if (h.paused === paused) return;
49
+ try {
50
+ if (paused) h.api.pause(); else h.api.play();
51
+ } catch (err) {
52
+ return warn(`${h.el.dataset.heroSrc} threw from ${paused ? 'pause' : 'play'}`, err);
53
+ }
54
+ h.paused = paused;
55
+ h.el.dataset.heroState = paused ? 'paused' : 'playing';
56
+ };
57
+ const wanted = () => Boolean(box?.checked) || doc.visibilityState === 'hidden';
58
+ const sync = () => { const p = wanted(); for (const h of live) set(h, p); };
59
+ box?.addEventListener('change', sync, { signal: ac.signal });
60
+ doc.addEventListener('visibilitychange', sync, { signal: ac.signal });
61
+
62
+ const ready = Promise.all(mounts.map(async (el) => {
63
+ const src = el.dataset.heroSrc;
64
+ const poster = el.querySelector('img');
65
+ const ps = el.dataset.heroPoster;
66
+ if (poster && ps && !RASTER_DATA.test(ps) && !sameOrigin(ps)) {
67
+ poster.removeAttribute('src');
68
+ warn(`poster ${ps} is not from this site; dropped`);
69
+ }
70
+ if (!sameOrigin(src)) return warn(`${src} is not from this site; keeping the poster`);
71
+ let api;
72
+ try {
73
+ const mod = await importFn(new URL(src, doc.baseURI).href);
74
+ api = await mod.default(el, { signal: ac.signal });
75
+ } catch (err) {
76
+ return warn(`could not load ${src}; keeping the poster`, err);
77
+ }
78
+ if (!api || typeof api.pause !== 'function' || typeof api.play !== 'function') {
79
+ try { api?.destroy?.(); } catch { /* the poster stays either way */ }
80
+ return warn(`${src} must return { pause, play, destroy }; keeping the poster`);
81
+ }
82
+ if (ac.signal.aborted) { try { api.destroy?.(); } catch { /* gone */ } return; }
83
+ const h = { el, api, paused: false };
84
+ el.dataset.heroState = 'playing';
85
+ live.push(h);
86
+ if (poster) poster.hidden = true;
87
+ if (wanted()) set(h, true);
88
+ }));
89
+
90
+ return {
91
+ ready,
92
+ destroy() {
93
+ ac.abort();
94
+ for (const h of live) { try { h.api.destroy?.(); } catch { /* already gone */ } }
95
+ },
96
+ };
97
+ }
98
+
99
+ if (typeof document !== 'undefined') initHeroes();
@@ -0,0 +1,281 @@
1
+ // @dataimago/css@0.1.0-alpha.24 dist/quarto/_extensions/dataimago/pkgsite/pkgsite.scss · sha256:18ca9b65e75a0517b19dc60ed34ea90637f34369373950da1a19ebe7444fe2be · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
+ /*-- scss:rules --*/
3
+ // Package-site layer on the dataimago tokens. Colours come only from the token custom
4
+ // properties, so the light/dark pair switches at runtime. Josefin Sans carries headings and
5
+ // labels; Noto Sans, Noto Sans Mono and Noto Sans Math carry everything else.
6
+
7
+ code, kbd, pre, samp, .sourceCode { font-family: var(--font-family-mono); }
8
+ .math.inline, .math.display { font-family: var(--font-family-math); }
9
+
10
+ // ── Navbar: the page's own navbar; pinned or hiding, the landing hero sits at top: 0 ──
11
+ .navbar {
12
+ border-bottom: 1px solid var(--color-border-subtle);
13
+ .navbar-title, .navbar-nav .nav-link {
14
+ font-family: var(--font-family-display);
15
+ letter-spacing: 0.02em;
16
+ }
17
+ .navbar-title { font-weight: var(--font-weight-normal); }
18
+ .navbar-brand-logo img { height: 2.4rem; width: auto; }
19
+ .pkg-version {
20
+ font-family: var(--font-family-sans);
21
+ font-size: 0.72rem;
22
+ color: var(--color-content-secondary);
23
+ margin-left: 0.4rem;
24
+ }
25
+ }
26
+
27
+ h1, h2, h3, h4, .title {
28
+ font-family: var(--font-family-display);
29
+ font-feature-settings: var(--font-feature-settings-display);
30
+ }
31
+ h1.title, .quarto-title h1 { font-weight: var(--font-weight-normal); letter-spacing: -0.01em; }
32
+
33
+ // ── Kicker labels ──
34
+ .kicker {
35
+ font-family: var(--font-family-display);
36
+ font-size: 0.8rem;
37
+ font-weight: var(--font-weight-semibold);
38
+ letter-spacing: 0.14em;
39
+ text-transform: uppercase;
40
+ color: var(--color-content-secondary);
41
+ border-top: 2px solid var(--color-interactive-primary);
42
+ padding-top: var(--spacing-sm);
43
+ margin: var(--spacing-3xl) 0 var(--spacing-lg);
44
+ }
45
+
46
+ .pkg-badges {
47
+ display: flex;
48
+ flex-wrap: wrap;
49
+ gap: var(--spacing-xs);
50
+ margin: var(--spacing-sm) 0;
51
+ padding: 0;
52
+ list-style: none;
53
+ img { height: 20px; width: auto; }
54
+ }
55
+
56
+ // ── Pill links ──
57
+ .pill-links {
58
+ display: flex;
59
+ flex-wrap: wrap;
60
+ gap: var(--spacing-sm);
61
+ padding: 0;
62
+ margin: var(--spacing-md) 0;
63
+ list-style: none;
64
+ }
65
+ main.content .pill-links a {
66
+ display: inline-flex;
67
+ align-items: center;
68
+ padding: 0.35rem 0.9rem;
69
+ border: 1px solid var(--color-border-moderate);
70
+ border-radius: var(--radius-full);
71
+ color: var(--color-content-primary);
72
+ text-decoration: none !important;
73
+ font-size: 0.92rem;
74
+ transition: background-color var(--transition-quick), border-color var(--transition-quick);
75
+ &:hover { background-color: var(--navigation-hover-background); border-color: var(--color-interactive-primary); }
76
+ &:focus-visible { outline: 2px solid var(--color-interactive-focus); outline-offset: 2px; }
77
+ }
78
+
79
+ // ── Reference index ──
80
+ .reference-index {
81
+ dl { display: grid; grid-template-columns: minmax(10rem, 18rem) 1fr; gap: var(--spacing-sm) var(--spacing-lg); }
82
+ dt { font-family: var(--font-family-mono); font-size: 0.92rem; }
83
+ dd { margin: 0; color: var(--color-content-secondary); }
84
+ }
85
+ @media (max-width: 575.98px) { .reference-index dl { grid-template-columns: 1fr; } }
86
+
87
+ // ── Reference pages and articles ──
88
+ main.content {
89
+ pre { border: 1px solid var(--color-border-subtle); border-radius: var(--radius-md); padding: var(--spacing-md); }
90
+ table { width: 100%; }
91
+ h2 { font-size: 1.5rem; margin-top: var(--spacing-2xl); }
92
+ }
93
+
94
+ // ── Footer: the Center is credited here ──
95
+ .nav-footer {
96
+ border-top: 1px solid var(--color-border-subtle);
97
+ font-size: 0.9rem;
98
+ color: var(--color-content-secondary);
99
+ a { color: inherit; text-decoration: underline; text-underline-offset: 0.15em; }
100
+ }
101
+
102
+ main.content dl:not(.quarto-listing-category) {
103
+ dt { font-family: var(--font-family-mono); font-size: 0.92rem; margin-top: var(--spacing-md); }
104
+ dd { margin-left: var(--spacing-lg); }
105
+ }
106
+
107
+ main.content .reference-index dl dt { margin-top: 0; }
108
+ main.content .reference-index dl dd { margin-left: 0; }
109
+
110
+ // ═══ The landing stage (landing.lua) ═══
111
+ // DOM order: pause control, intro, overview, hero, cards. Small screens keep that order as one column with the
112
+ // hero between intro and overview. On a large screen with motion allowed, the hero is pinned left (7fr), the
113
+ // intro and overview scroll beside it (3fr), and the cards panel wipes over it. No JavaScript.
114
+
115
+ .di-hero-pause-input {
116
+ position: absolute;
117
+ width: 1px;
118
+ height: 1px;
119
+ margin: -1px;
120
+ padding: 0;
121
+ overflow: hidden;
122
+ clip: rect(0 0 0 0);
123
+ white-space: nowrap;
124
+ border: 0;
125
+ }
126
+ .di-hero-pause { margin: var(--spacing-md) 0 0; }
127
+ .di-hero-pause-label {
128
+ display: inline-flex;
129
+ align-items: center;
130
+ box-sizing: border-box;
131
+ min-height: 44px;
132
+ padding: 0.25rem 1.1rem;
133
+ border: 1px solid var(--color-border-moderate);
134
+ border-radius: var(--radius-full);
135
+ background: var(--color-surface-elevated);
136
+ color: var(--color-content-primary);
137
+ font-family: var(--font-family-display);
138
+ font-size: 0.9rem;
139
+ letter-spacing: 0.04em;
140
+ cursor: pointer;
141
+ transition: border-color 120ms ease, background-color 120ms ease;
142
+ &:hover { border-color: var(--color-interactive-primary); }
143
+ .di-pause-off { display: none; }
144
+ }
145
+ .di-hero-pause-input:focus-visible ~ .di-landing .di-hero-pause-label { outline: 2px solid var(--color-interactive-focus); outline-offset: 2px; }
146
+ .di-hero-pause-input:checked ~ .di-landing .di-hero-pause-label {
147
+ .di-pause-on { display: none; }
148
+ .di-pause-off { display: inline; }
149
+ }
150
+ @media (prefers-reduced-motion: reduce) { .di-hero-pause { display: none; } }
151
+
152
+ #di-hero-pause:checked ~ .di-landing .di-landing-hero * { animation-play-state: paused; }
153
+
154
+ /* The landing filter sets toc: false; this is the belt for a TOC or margin column that still appears. */
155
+ body:has(.di-landing) #TOC,
156
+ body:has(.di-landing) #quarto-margin-sidebar { display: none; }
157
+
158
+ .di-landing {
159
+ display: flex;
160
+ flex-direction: column;
161
+ gap: var(--spacing-xl);
162
+ margin: 0;
163
+ }
164
+ .di-landing-intro { order: 1; padding: var(--spacing-2xl) var(--spacing-lg) 0; }
165
+ .di-landing-hero { order: 2; max-height: 50vh; overflow: hidden; }
166
+ .di-landing-overview { order: 3; padding-inline: var(--spacing-lg); }
167
+ .di-landing-cards { order: 4; }
168
+
169
+ .di-landing-hero svg, .di-landing-hero img { display: block; width: 100%; height: 100%; max-height: 50vh; object-fit: contain; }
170
+ .di-hero-mount { width: 100%; height: 100%; }
171
+
172
+ .di-landing-intro {
173
+ h1.di-landing-name {
174
+ font-family: var(--font-family-display);
175
+ font-weight: var(--font-weight-normal);
176
+ font-size: clamp(2.4rem, 5vw, 3.6rem);
177
+ line-height: var(--font-lineHeight-tight);
178
+ margin: 0;
179
+ }
180
+ .di-landing-title {
181
+ color: var(--color-content-secondary);
182
+ font-size: 1.1rem;
183
+ margin: var(--spacing-xs) 0 var(--spacing-md);
184
+ max-width: 42rem;
185
+ }
186
+ .di-landing-version { font-size: 0.75rem; color: var(--color-content-secondary); margin: 0; }
187
+ }
188
+
189
+ .di-landing-cards {
190
+ display: grid;
191
+ grid-template-columns: 1fr;
192
+ gap: var(--spacing-md);
193
+ padding: var(--spacing-xl) var(--spacing-lg);
194
+ background: var(--color-surface-page);
195
+ }
196
+ @media (min-width: 640px) { .di-landing-cards { grid-template-columns: repeat(2, 1fr); } }
197
+
198
+ a.di-card {
199
+ display: flex;
200
+ flex-direction: column;
201
+ gap: var(--spacing-xs);
202
+ padding: var(--spacing-lg);
203
+ border: 1px solid var(--color-border-card);
204
+ border-radius: var(--radius-md);
205
+ background: var(--color-surface-elevated);
206
+ color: var(--color-content-primary);
207
+ text-decoration: none !important;
208
+ transition: border-color 120ms ease, background-color 120ms ease;
209
+ &:hover { border-color: var(--color-interactive-primary); background-color: var(--navigation-hover-background); }
210
+ &:focus-visible { outline: 2px solid var(--color-interactive-focus); outline-offset: 2px; }
211
+ .di-card-title { font-family: var(--font-family-display); font-size: 1.15rem; font-weight: var(--font-weight-semibold); }
212
+ .di-card-desc { color: var(--color-content-secondary); font-size: 0.92rem; }
213
+ }
214
+
215
+ // A pinned navbar is fixed over the page, so the pinned hero starts below it. Quarto's headroom script puts a
216
+ // headroom--* class on the header (a hiding navbar); a pinned navbar never gets one, so CSS alone tells them
217
+ // apart. On a landing page the navbar is given a floor of 4rem (Quarto's own body padding-top is 64px) so the
218
+ // offset is exact; every other page keeps Quarto's natural navbar height.
219
+
220
+ // The wipe: only with motion allowed and room for a pinned stage.
221
+ @media (prefers-reduced-motion: no-preference) and (min-width: 1024px) and (min-height: 780px) {
222
+ .di-landing {
223
+ display: grid;
224
+ grid-template-columns: 7fr 3fr;
225
+ grid-template-rows: auto auto auto;
226
+ gap: 0;
227
+ }
228
+ .di-landing-hero {
229
+ grid-column: 1;
230
+ grid-row: 1 / 4;
231
+ position: sticky;
232
+ top: 0;
233
+ height: 100dvh;
234
+ max-height: none;
235
+ align-self: start;
236
+ }
237
+ body:has(.di-landing) #quarto-header .navbar { min-height: 4rem; }
238
+ // Pinned navbar: start below it (a new custom property would extend the frozen CSS-variable contract).
239
+ body.nav-fixed:has(#quarto-header:not([class*="headroom--"])) .di-landing-hero {
240
+ top: 4rem;
241
+ height: calc(100dvh - 4rem);
242
+ }
243
+ .di-landing-hero svg, .di-landing-hero img { max-height: none; }
244
+ .di-landing-intro {
245
+ grid-column: 2;
246
+ grid-row: 1;
247
+ min-height: 100dvh;
248
+ padding: 0 var(--spacing-xl);
249
+ display: flex;
250
+ flex-direction: column;
251
+ justify-content: center;
252
+ }
253
+ .di-landing-overview { grid-column: 2; grid-row: 2; padding: var(--spacing-xl); }
254
+ .di-landing-cards {
255
+ grid-column: 1 / -1;
256
+ grid-row: 3;
257
+ position: relative;
258
+ z-index: 1;
259
+ min-height: 100dvh;
260
+ align-content: center;
261
+ padding: var(--spacing-3xl) var(--spacing-xl);
262
+ background: var(--color-surface-page);
263
+ box-shadow: var(--shadow-prominent);
264
+ }
265
+ }
266
+
267
+ // AI-composed label (provenance.lua): quiet surface, secondary text, a left rule. The draft rule is stronger and
268
+ // uses the accent token. Pairs: content-secondary on surface-elevated is a contrast-check role in both modes;
269
+ // the rule is non-text and clears 3:1 against that surface (interactive-accent, light and dark).
270
+ .di-provenance {
271
+ margin: 0 0 var(--spacing-lg);
272
+ padding: var(--spacing-sm) var(--spacing-md);
273
+ border-left: 3px solid var(--color-border-moderate);
274
+ background: var(--color-surface-elevated);
275
+ color: var(--color-content-secondary);
276
+ font-size: 0.875rem;
277
+ line-height: 1.5;
278
+ p { margin: 0; }
279
+ a { color: inherit; text-decoration: underline; }
280
+ &.di-provenance-draft { border-left-width: 6px; border-left-color: var(--color-interactive-accent); }
281
+ }
@@ -1,4 +1,4 @@
1
- // @dataimago/css@0.1.0-alpha.22 dist/quarto/components.scss · sha256:a2b35c50f5dc36aa4cf337e7ff5ea4ec758890c6910776f5a3e1deb31ad44dd4 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.22 dataimago-sync
1
+ // @dataimago/css@0.1.0-alpha.24 dist/quarto/components.scss · sha256:a2b35c50f5dc36aa4cf337e7ff5ea4ec758890c6910776f5a3e1deb31ad44dd4 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
2
  /*-- scss:rules --*/
3
3
  // dataimago components (.di-*) — generated from src/styles/components/.
4
4
  .di-figure-box {
@@ -1,4 +1,4 @@
1
- // @dataimago/css@0.1.0-alpha.22 dist/quarto/dataimago-dark.scss · sha256:f857888d73961ee714eea97a162915d1f3c28fa740fc88bf3a68e8728594d274 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.22 dataimago-sync
1
+ // @dataimago/css@0.1.0-alpha.24 dist/quarto/dataimago-dark.scss · sha256:f857888d73961ee714eea97a162915d1f3c28fa740fc88bf3a68e8728594d274 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
2
  // dataimago dark theme for Quarto 1.8 — generated from the design tokens (tools/formats/quarto.mjs).
3
3
  // Bootstrap Sass variables are compile-time sRGB; runtime colours come from the custom properties below.
4
4
 
@@ -1,4 +1,4 @@
1
- // @dataimago/css@0.1.0-alpha.22 dist/quarto/dataimago-light.scss · sha256:e456b3e8cfaa03df7fe5ac29bb6e8288454ee5daab29ff6470c45a12ff8d3f32 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.22 dataimago-sync
1
+ // @dataimago/css@0.1.0-alpha.24 dist/quarto/dataimago-light.scss · sha256:e456b3e8cfaa03df7fe5ac29bb6e8288454ee5daab29ff6470c45a12ff8d3f32 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync
2
2
  // dataimago light theme for Quarto 1.8 — generated from the design tokens (tools/formats/quarto.mjs).
3
3
  // Bootstrap Sass variables are compile-time sRGB; runtime colours come from the custom properties below.
4
4
 
@@ -1,4 +1,4 @@
1
- <!-- @dataimago/css@0.1.0-alpha.22 dist/templates/KNOWLEDGE-explorer.md · sha256:907c08638ed56813d453227759e29de08350465885d11f0efe94ec7ba8c42a50 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.22 dataimago-sync -->
1
+ <!-- @dataimago/css@0.1.0-alpha.24 dist/templates/KNOWLEDGE-explorer.md · sha256:907c08638ed56813d453227759e29de08350465885d11f0efe94ec7ba8c42a50 · generated from tokens; do not edit · restore: npx -p @dataimago/css@0.1.0-alpha.24 dataimago-sync -->
2
2
  # {{PROJECT_NAME}} — Knowledge Base Operating Manual
3
3
 
4
4
  **Domain:** {{DOMAIN_NAME}}