@dataimago/css-neutral 0.1.0-alpha.16 → 0.1.0-alpha.18

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/README.md CHANGED
@@ -6,6 +6,7 @@ Neutral-identity compiled CSS + Tailwind preset — paired with `@dataimago/toke
6
6
  - `dist/tokens.css` — CSS custom properties (copied from `@dataimago/tokens-neutral`)
7
7
  - `dist/tokens.scss` — same, as SCSS
8
8
  - `dist/tailwind-preset.js` — Tailwind preset (Noto Sans throughout; neutral palette: ink/stone/paper/functional only)
9
+ - `dist/js/figure-viewer.js` — the figure viewer script (export `./js/*`), without any styles. It builds a `div.di-figure-modal[role=dialog]` holding `.di-figure-modal-content`, `.di-figure-modal-bar`, `.di-figure-modal-esc`, `.di-figure-modal-close`, `.di-figure-modal-image` (plus `--vector` for SVG sources) and `.di-figure-modal-caption`, and toggles `is-open` and `hidden` on the dialog. Mark images with `.di-figure-box`. The presentation is yours: the neutral package ships no component stylesheet, so style those classes (the dialog is hidden by the script itself).
9
10
 
10
11
  **Does NOT ship** a compiled `dataimago.css` (component stylesheet). The house package's compiled CSS embeds dataimago-specific component styling (forest interactive primary, copper editorial framing, accent moral-weight beats); shipping that under a "neutral" name would be dishonest. Neutral consumers use tokens + Tailwind preset and author their own component stylesheets.
11
12
 
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/dataviz/dataimago-dataviz.css · sha256:0baea043cae14943ea11a8646b02b79aa64e955af258f93926376e61d2bc66a2 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/dataviz/dataimago-dataviz.css · sha256:0baea043cae14943ea11a8646b02b79aa64e955af258f93926376e61d2bc66a2 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  /* dataimago data-viz palette (Okabe-Ito). Categorical colour is never the only channel. */
3
3
  :root, [data-bs-theme="light"], body.quarto-light {
4
4
  --color-dataviz-okabe-ito-orange: #E69F00;
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "_meta": {
3
3
  "package": "@dataimago/css-neutral",
4
- "version": "0.1.0-alpha.16",
4
+ "version": "0.1.0-alpha.18",
5
5
  "path": "dist/dataviz/dataimago-dataviz.json",
6
6
  "sha256": "d7ac5f1127a41714ad85fc5d0fca58e6cacd200518fb7772b1c4b4247bbdd647",
7
7
  "note": "generated from tokens; do not edit",
8
- "restore": "npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync"
8
+ "restore": "npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync"
9
9
  },
10
10
  "okabe-ito": {
11
11
  "orange": "#E69F00",
@@ -1,4 +1,4 @@
1
- % @dataimago/css-neutral@0.1.0-alpha.16 dist/dataviz/dataimago-dataviz.tex · sha256:309fb3ff4fad3ad7890c1e873e2c61dacb7bb91056755c990c7fa60023260fb5 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync
1
+ % @dataimago/css-neutral@0.1.0-alpha.18 dist/dataviz/dataimago-dataviz.tex · sha256:309fb3ff4fad3ad7890c1e873e2c61dacb7bb91056755c990c7fa60023260fb5 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
2
  % dataimago data-viz palette (Okabe-Ito), light mode, for PSTricks and TikZ. Requires xcolor.
3
3
  \definecolor{di-dataviz-okabe-ito-orange}{HTML}{E69F00}
4
4
  \definecolor{di-dataviz-okabe-ito-sky-blue}{HTML}{56B4E9}
@@ -1,4 +1,4 @@
1
- # @dataimago/css-neutral@0.1.0-alpha.16 dist/dataviz/dataimago_dataviz.R · sha256:eb8234c65a2952a999a403b96a0dc26f039bc998f56c3f87be57836ae7959bbd · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync
1
+ # @dataimago/css-neutral@0.1.0-alpha.18 dist/dataviz/dataimago_dataviz.R · sha256:eb8234c65a2952a999a403b96a0dc26f039bc998f56c3f87be57836ae7959bbd · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
2
  # dataimago data-viz palette (Okabe-Ito). Categorical colour is never the only channel:
3
3
  # pair it with marker shape, line type or a label.
4
4
 
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/cyrillic/fonts.css · sha256:6f4e34aeea25946f7a3234e48fd5f79f57aba44e459267d455a4eac8ab4b9fd7 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/cyrillic/fonts.css · sha256:6f4e34aeea25946f7a3234e48fd5f79f57aba44e459267d455a4eac8ab4b9fd7 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/cyrillic-ext/fonts.css · sha256:e7a7948d9128600befa05a0b472d66d46999d0be9ce1f50bf9730de9c28938aa · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/cyrillic-ext/fonts.css · sha256:e7a7948d9128600befa05a0b472d66d46999d0be9ce1f50bf9730de9c28938aa · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/greek/fonts.css · sha256:a79d666643da90c852dfcde96c8d5cd5237a4cf4f0d3d5edc16f971c3a52b704 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/greek/fonts.css · sha256:a79d666643da90c852dfcde96c8d5cd5237a4cf4f0d3d5edc16f971c3a52b704 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/greek-ext/fonts.css · sha256:4483a2b37ff134bda65fabfc9b0c5f91387b10f1e1ffd931d34a93e4be348e02 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/greek-ext/fonts.css · sha256:4483a2b37ff134bda65fabfc9b0c5f91387b10f1e1ffd931d34a93e4be348e02 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/lang.css · sha256:f6c5232530e667d9e66b6cd7e7dbd4f6132ed96fc4439fdeff814c69727a9281 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/lang.css · sha256:f6c5232530e667d9e66b6cd7e7dbd4f6132ed96fc4439fdeff814c69727a9281 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  /* House layer: rebind the display variables on the named elements only. */
3
3
  :is(h1, h2, h3, h4, h5, h6, .title, .subtitle, .navbar-nav .nav-link, .navbar-nav .dropdown-item, .di-callout-title, .theorem-title, .proof-title, .definition-title, .proposition-title):is(:lang(el), :lang(ru), :lang(uk), :lang(bg), :lang(sr), :lang(mk), :lang(be), :lang(kk)) {
4
4
  --font-family-display: "Noto Sans", system-ui, sans-serif;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/latin/fonts.css · sha256:673b070de2c959ab604549b301fb2a291a77e1057139142e0cdb3b92c65fa809 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/latin/fonts.css · sha256:673b070de2c959ab604549b301fb2a291a77e1057139142e0cdb3b92c65fa809 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/latin-ext/fonts.css · sha256:fe0f2f5c6f7e5e64400c2ef348fc688dd0e062f453e7d022626188ead0b2a5f7 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/latin-ext/fonts.css · sha256:fe0f2f5c6f7e5e64400c2ef348fc688dd0e062f453e7d022626188ead0b2a5f7 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/math/fonts.css · sha256:26c69cfaa369141dfd31754602675b9459c5b56e30fd33e72eb34ec846534320 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/math/fonts.css · sha256:26c69cfaa369141dfd31754602675b9459c5b56e30fd33e72eb34ec846534320 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans Math";
4
4
  font-style: normal;
@@ -1,4 +1,4 @@
1
- /* @dataimago/css-neutral@0.1.0-alpha.16 dist/fonts/vietnamese/fonts.css · sha256:2776442fa59632e6c126ca0b00c5e5db10be26cb091c8fc3cb9891f31301fbed · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync */
1
+ /* @dataimago/css-neutral@0.1.0-alpha.18 dist/fonts/vietnamese/fonts.css · sha256:2776442fa59632e6c126ca0b00c5e5db10be26cb091c8fc3cb9891f31301fbed · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync */
2
2
  @font-face {
3
3
  font-family: "Noto Sans";
4
4
  font-style: normal;
@@ -0,0 +1,446 @@
1
+ // @dataimago/css-neutral@0.1.0-alpha.18 dist/js/figure-viewer.js · sha256:650db5390b3cbe889213e02efad264ed6b33042d6f9da1b476ec19f7d5b8e7e4 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
+ /**
3
+ * dataimago figure viewer: click (or Enter/Space) an image marked `.di-figure-box` to see it enlarged
4
+ * in a dialog, with its figcaption (math, emphasis and links intact).
5
+ *
6
+ * A classic script with no dependencies and no global API. It binds once, by event delegation, so
7
+ * including it twice is harmless. Presentation lives in figure-modal.scss.
8
+ *
9
+ * Triggers: `img.di-figure-box`, or an `img` inside an element with that class, unless the image sits
10
+ * in a link (an `a[href]` that is not Quarto's `a.lightbox`). Each trigger is made keyboard-operable.
11
+ *
12
+ * Ported from LIwLD's figure-modal.js (SGPc, after #244). Three gaps there are closed here:
13
+ * 1. A caption link to another page, a missing id or a malformed fragment closes the viewer and
14
+ * then navigates itself, instead of relying on a detached anchor.
15
+ * 2. A ResizeObserver keeps the caption's "scrollable region" semantics current while it is open.
16
+ * 3. openModal takes the trigger and stores it as the opener, not document.activeElement.
17
+ */
18
+ (function () {
19
+ 'use strict';
20
+
21
+ // Imported during server rendering (Next.js) there is no document: do nothing.
22
+ if (typeof document === 'undefined') return;
23
+
24
+ var root = document.documentElement;
25
+ if (root.dataset.diFigureViewer === 'bound') return;
26
+ root.dataset.diFigureViewer = 'bound';
27
+
28
+ var TRIGGER = 'img.di-figure-box, .di-figure-box img';
29
+ var CAPTION_ID = 'di-figure-modal-caption';
30
+ var CLOSE_GLYPH = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" ' +
31
+ 'stroke-width="1.5" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M3.5 3.5 12.5 12.5M12.5 3.5 3.5 12.5"/></svg>';
32
+
33
+ var modal = null;
34
+ var modalImg = null;
35
+ var modalCaption = null;
36
+ var closeBtn = null;
37
+ var resizeObserver = null;
38
+
39
+ var named = typeof WeakSet === 'function' ? new WeakSet() : null; // triggers whose aria-label is ours
40
+ var pendingSpace = null; // the trigger a Space keydown landed on; opens on its keyup
41
+ var decorateQueued = false;
42
+
43
+ var opener = null; // the trigger that opened the viewer; takes focus back on close
44
+ var scrollPosition = 0; // where the page was, restored on close
45
+ var scrollLeft = 0;
46
+ var inerted = []; // page content made inert while open
47
+ var savedBody = null; // the body's inline styles before the viewer touched them
48
+ var sidebarSaved = null;
49
+
50
+ // ── Triggers ───────────────────────────────────────────────────────────────
51
+
52
+ /** The trigger image for a node, or null. Images in a link (other than a.lightbox) are left alone. */
53
+ function triggerFor(node) {
54
+ var img = node && node.closest ? node.closest('img') : null;
55
+ if (!img || !img.matches(TRIGGER)) return null;
56
+ var link = img.closest('a[href]');
57
+ if (link && !link.classList.contains('lightbox')) return null;
58
+ return img;
59
+ }
60
+
61
+ /** The accessible name for a trigger: its alt text, else its figure's caption, else none. */
62
+ function describe(img) {
63
+ var text = (img.getAttribute('alt') || '').trim();
64
+ if (!text) {
65
+ var figure = img.closest('figure');
66
+ var caption = figure ? figure.querySelector('figcaption') : null;
67
+ text = caption ? caption.textContent.replace(/\s+/g, ' ').trim() : '';
68
+ if (text.length > 120) text = text.slice(0, 120).replace(/\s+$/, '') + '…';
69
+ }
70
+ return text ? 'Enlarge figure: ' + text : 'Enlarge figure';
71
+ }
72
+
73
+ /** Make a trigger keyboard-operable and named. An aria-label the author wrote is left alone. */
74
+ function decorate(img) {
75
+ // Quarto's lightbox wrapper (an author forced `lightbox: true`): make the image the only control. The
76
+ // anchor loses its href (kept in data-di-href), so it is no longer a link or a tab stop and nothing nests.
77
+ var wrapper = img.closest('a.lightbox');
78
+ if (wrapper && wrapper.hasAttribute('href')) {
79
+ wrapper.setAttribute('data-di-href', wrapper.getAttribute('href'));
80
+ wrapper.removeAttribute('href');
81
+ }
82
+ if (!img.hasAttribute('tabindex')) img.setAttribute('tabindex', '0');
83
+ if (!img.hasAttribute('role')) img.setAttribute('role', 'button');
84
+ if (img.hasAttribute('aria-label') && !(named && named.has(img))) return;
85
+ img.setAttribute('aria-label', describe(img));
86
+ if (named) named.add(img);
87
+ }
88
+
89
+ function decorateAll() {
90
+ document.querySelectorAll(TRIGGER).forEach(function (img) {
91
+ if (triggerFor(img)) decorate(img);
92
+ });
93
+ }
94
+
95
+ /** Triggers rendered after load (client navigation, React) get decorated too, once per frame. */
96
+ function observeLateTriggers() {
97
+ if (typeof MutationObserver !== 'function' || !document.body) return;
98
+ new MutationObserver(function (records) {
99
+ var outside = records.some(function (r) { return !(modal && modal.contains(r.target)) && !(r.addedNodes.length === 1 && r.addedNodes[0] === modal); });
100
+ if (!outside || decorateQueued) return;
101
+ decorateQueued = true;
102
+ requestAnimationFrame(function () {
103
+ decorateQueued = false;
104
+ decorateAll();
105
+ });
106
+ }).observe(document.body, { childList: true, subtree: true });
107
+ }
108
+
109
+ // ── The dialog ─────────────────────────────────────────────────────────────
110
+
111
+ function createModal() {
112
+ modal = document.createElement('div');
113
+ modal.className = 'di-figure-modal';
114
+ modal.hidden = true; // hidden by the module itself, so a page without the stylesheet works
115
+ modal.setAttribute('role', 'dialog');
116
+ modal.setAttribute('aria-modal', 'true');
117
+ modal.setAttribute('aria-label', 'Figure');
118
+ modal.setAttribute('aria-describedby', CAPTION_ID);
119
+ modal.innerHTML =
120
+ '<div class="di-figure-modal-content">' +
121
+ '<div class="di-figure-modal-bar">' +
122
+ '<kbd class="di-figure-modal-esc" aria-hidden="true">Esc</kbd>' +
123
+ '<button class="di-figure-modal-close" type="button" aria-label="Close figure">' + CLOSE_GLYPH + '</button>' +
124
+ '</div>' +
125
+ '<img class="di-figure-modal-image" alt="">' +
126
+ '<div class="di-figure-modal-caption" id="' + CAPTION_ID + '"></div>' +
127
+ '</div>';
128
+ document.body.appendChild(modal);
129
+ modalImg = modal.querySelector('.di-figure-modal-image');
130
+ modalCaption = modal.querySelector('.di-figure-modal-caption');
131
+ closeBtn = modal.querySelector('.di-figure-modal-close');
132
+ modalImg.addEventListener('load', sizeImage);
133
+
134
+ closeBtn.addEventListener('click', function (e) {
135
+ e.preventDefault();
136
+ e.stopPropagation();
137
+ closeModal();
138
+ });
139
+ modalCaption.addEventListener('click', onCaptionClick);
140
+ modal.addEventListener('keydown', onModalKeydown);
141
+ // A click on the backdrop itself (not the content) closes.
142
+ modal.addEventListener('click', function (e) {
143
+ if (e.target === modal) closeModal();
144
+ });
145
+ }
146
+
147
+ /**
148
+ * A vector source scales to fill the box the CSS caps allow, so it needs its aspect ratio; a raster
149
+ * keeps its natural size (never upscaled). Runs when the enlarged image has loaded.
150
+ */
151
+ function sizeImage() {
152
+ if (!isOpen() || !opener || !modalImg.classList.contains('is-vector-source')) return;
153
+ var w = modalImg.naturalWidth || opener.naturalWidth || opener.clientWidth;
154
+ var h = modalImg.naturalHeight || opener.naturalHeight || opener.clientHeight;
155
+ if (!w || !h) return;
156
+ modalImg.style.setProperty('--di-figure-ratio', String(w / h));
157
+ modalImg.classList.add('di-figure-modal-image--vector');
158
+ }
159
+
160
+ function isVectorSource(src) {
161
+ if (/^data:image\/svg\+xml/i.test(src)) return true;
162
+ try {
163
+ return /\.svg$/i.test(new URL(src, location.href).pathname);
164
+ } catch (err) {
165
+ return false;
166
+ }
167
+ }
168
+
169
+ function isOpen() {
170
+ return Boolean(modal && modal.classList.contains('is-open'));
171
+ }
172
+
173
+ /**
174
+ * A caption taller than its box scrolls, so it becomes a named, focusable region (arrow keys scroll
175
+ * it; a screen reader still reads the text inside). Recomputed whenever the caption is resized.
176
+ */
177
+ function syncCaptionRegion() {
178
+ if (!isOpen() || modalCaption.hidden) return;
179
+ if (modalCaption.scrollHeight > modalCaption.clientHeight) {
180
+ modalCaption.setAttribute('role', 'region');
181
+ modalCaption.setAttribute('tabindex', '0');
182
+ modalCaption.setAttribute('aria-label', 'Figure caption');
183
+ } else {
184
+ clearCaptionRegion();
185
+ }
186
+ }
187
+
188
+ function clearCaptionRegion() {
189
+ modalCaption.removeAttribute('role');
190
+ modalCaption.removeAttribute('tabindex');
191
+ modalCaption.removeAttribute('aria-label');
192
+ }
193
+
194
+ /** Fill the caption from a copy of the figcaption's HTML (ids stripped); hide the box when empty. */
195
+ function setCaption(figcaption) {
196
+ modalCaption.replaceChildren();
197
+ clearCaptionRegion();
198
+ if (figcaption) {
199
+ var copy = figcaption.cloneNode(true);
200
+ copy.querySelectorAll('[id]').forEach(function (el) { el.removeAttribute('id'); });
201
+ modalCaption.append.apply(modalCaption, copy.childNodes);
202
+ }
203
+ var empty = !modalCaption.textContent.trim() && !modalCaption.querySelector('img, svg, math');
204
+ modalCaption.hidden = empty;
205
+ if (empty) modal.removeAttribute('aria-describedby');
206
+ else modal.setAttribute('aria-describedby', CAPTION_ID);
207
+ }
208
+
209
+ /** @param {HTMLImageElement} trigger the image that was clicked or keyboard-activated */
210
+ function openModal(trigger) {
211
+ if (!modal) createModal();
212
+ if (isOpen()) return;
213
+ opener = trigger;
214
+ scrollPosition = window.pageYOffset || document.documentElement.scrollTop;
215
+ scrollLeft = window.pageXOffset || document.documentElement.scrollLeft || 0;
216
+
217
+ var source = trigger.currentSrc || trigger.src;
218
+ modalImg.classList.remove('di-figure-modal-image--vector');
219
+ modalImg.style.removeProperty('--di-figure-ratio');
220
+ modalImg.classList.toggle('is-vector-source', isVectorSource(source));
221
+ modalImg.src = source;
222
+ modalImg.alt = trigger.getAttribute('alt') || '';
223
+ var figure = trigger.closest('figure');
224
+ setCaption(figure ? figure.querySelector('figcaption') : null);
225
+ modal.hidden = false;
226
+ modal.classList.add('is-open');
227
+
228
+ // Pin the body where it is. Its own inline styles are remembered and put back on close; the
229
+ // scrollbar's width is added as padding so the page doesn't shift sideways when it goes.
230
+ var body = document.body;
231
+ var scrollbar = window.innerWidth - document.documentElement.clientWidth;
232
+ var padding = parseFloat(getComputedStyle(body).paddingRight) || 0;
233
+ savedBody = {};
234
+ ['overflow', 'position', 'top', 'left', 'right', 'paddingRight'].forEach(function (p) { savedBody[p] = body.style[p]; });
235
+ body.style.overflow = 'hidden';
236
+ body.style.position = 'fixed';
237
+ body.style.top = '-' + scrollPosition + 'px';
238
+ body.style.left = '0';
239
+ body.style.right = '0';
240
+ if (scrollbar > 0) body.style.paddingRight = (padding + scrollbar) + 'px';
241
+
242
+ // Quarto's TOC sidebar sits outside the pinned flow: keep it where it is.
243
+ var sidebar = document.querySelector('#quarto-sidebar-toc-left');
244
+ if (sidebar) {
245
+ sidebarSaved = { position: sidebar.style.position, top: sidebar.style.top };
246
+ sidebar.style.position = 'fixed';
247
+ sidebar.style.top = '0';
248
+ }
249
+
250
+ // Everything outside the dialog is inert while it is open.
251
+ inerted = Array.prototype.filter.call(body.children, function (el) { return el !== modal && !el.inert; });
252
+ inerted.forEach(function (el) { el.inert = true; });
253
+
254
+ syncCaptionRegion();
255
+ if (typeof ResizeObserver === 'function') {
256
+ resizeObserver = new ResizeObserver(syncCaptionRegion);
257
+ resizeObserver.observe(modalCaption);
258
+ }
259
+ closeBtn.focus();
260
+ }
261
+
262
+ /**
263
+ * Run a scroll without animation. `behavior: 'instant'` is not portable (older WebKit throws or treats it
264
+ * as `auto`), and the page may set `scroll-behavior: smooth` on html or body (Bootstrap does), so both are
265
+ * set to `auto` for the call and put back after.
266
+ */
267
+ function scrollInstantly(fn) {
268
+ var targets = [document.documentElement, document.body];
269
+ var saved = targets.map(function (el) { return el.style.scrollBehavior; });
270
+ targets.forEach(function (el) { el.style.scrollBehavior = 'auto'; });
271
+ try {
272
+ fn();
273
+ } finally {
274
+ targets.forEach(function (el, i) { el.style.scrollBehavior = saved[i]; });
275
+ }
276
+ }
277
+
278
+ /**
279
+ * @param {{returnFocus?: boolean}} [options] returnFocus false (a caption link to this page) keeps
280
+ * the caption and leaves focus for the caller to move to the link's target.
281
+ */
282
+ function closeModal(options) {
283
+ if (!isOpen()) return;
284
+ var returnFocus = !options || options.returnFocus !== false;
285
+ modal.classList.remove('is-open');
286
+ modal.hidden = true;
287
+ if (resizeObserver) {
288
+ resizeObserver.disconnect();
289
+ resizeObserver = null;
290
+ }
291
+ clearCaptionRegion();
292
+ inerted.forEach(function (el) { el.inert = false; });
293
+ inerted = [];
294
+
295
+ var body = document.body;
296
+ Object.keys(savedBody).forEach(function (p) { body.style[p] = savedBody[p]; });
297
+ savedBody = null;
298
+ var sidebar = document.querySelector('#quarto-sidebar-toc-left');
299
+ if (sidebar && sidebarSaved) {
300
+ sidebar.style.position = sidebarSaved.position;
301
+ sidebar.style.top = sidebarSaved.top;
302
+ }
303
+ sidebarSaved = null;
304
+
305
+ // Back to the reading position in the same frame the body is unpinned, without animation. A scroll
306
+ // that fails must not stop the cleanup below.
307
+ try {
308
+ scrollInstantly(function () { window.scrollTo(scrollLeft, scrollPosition); });
309
+ } catch (err) { /* the page keeps its own position */ }
310
+
311
+ modalImg.removeAttribute('src');
312
+ var back = opener;
313
+ opener = null;
314
+ if (!returnFocus) return;
315
+ modalCaption.replaceChildren();
316
+ if (back && document.contains(back)) back.focus({ preventScroll: true });
317
+ }
318
+
319
+ // ── Caption links ──────────────────────────────────────────────────────────
320
+
321
+ function onCaptionClick(e) {
322
+ var link = e.target.closest('a[href]');
323
+ if (!link) return;
324
+ var target = link.getAttribute('target');
325
+ // A modified click or a link with its own target keeps the browser default; the viewer stays open.
326
+ if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || (target && target !== '_self')) return;
327
+
328
+ // Resolve an in-page target before acting on the click; a malformed fragment cannot resolve.
329
+ var dest = null;
330
+ var samePage = link.origin === location.origin && link.pathname === location.pathname &&
331
+ link.search === location.search && link.hash;
332
+ if (samePage) {
333
+ try {
334
+ dest = document.getElementById(decodeURIComponent(link.hash.slice(1)));
335
+ } catch (err) {
336
+ dest = null;
337
+ }
338
+ }
339
+ e.preventDefault();
340
+ if (!dest) {
341
+ // Another page, a missing id or a malformed fragment: close at the figure, then navigate.
342
+ var href = link.href;
343
+ closeModal();
344
+ location.href = href;
345
+ return;
346
+ }
347
+
348
+ // In-page: back at the reading position first. After two frames, once that offset is the page's
349
+ // own, write the history entry there (Back returns to the figure), then go to the target.
350
+ var hash = link.hash;
351
+ var href2 = link.href;
352
+ closeModal({ returnFocus: false });
353
+ requestAnimationFrame(function () {
354
+ requestAnimationFrame(function () {
355
+ if (location.hash !== hash) {
356
+ try {
357
+ history.pushState(null, '', hash);
358
+ } catch (err) {
359
+ modalCaption.replaceChildren();
360
+ window.location.href = href2;
361
+ return;
362
+ }
363
+ }
364
+ try {
365
+ scrollInstantly(function () { dest.scrollIntoView({ block: 'start' }); });
366
+ } catch (err) { /* focus below still moves to the target */ }
367
+ if (!dest.matches('a[href], button, input, select, textarea, [tabindex]')) dest.setAttribute('tabindex', '-1');
368
+ dest.focus({ preventScroll: true });
369
+ modalCaption.replaceChildren();
370
+ });
371
+ });
372
+ }
373
+
374
+ // ── Keyboard ───────────────────────────────────────────────────────────────
375
+
376
+ /** Focusable elements in the dialog, in order: close button, the caption region, caption links. */
377
+ function dialogFocusables() {
378
+ var region = modalCaption.hasAttribute('tabindex') ? [modalCaption] : [];
379
+ return [closeBtn].concat(region, Array.prototype.slice.call(modalCaption.querySelectorAll('a[href]')));
380
+ }
381
+
382
+ /** Tab and Shift+Tab wrap inside the dialog (the page behind it is inert). */
383
+ function onModalKeydown(e) {
384
+ if (e.key !== 'Tab' || !isOpen()) return;
385
+ var items = dialogFocusables();
386
+ var first = items[0];
387
+ var last = items[items.length - 1];
388
+ if (e.shiftKey && document.activeElement === first) {
389
+ e.preventDefault();
390
+ last.focus();
391
+ } else if (!e.shiftKey && document.activeElement === last) {
392
+ e.preventDefault();
393
+ first.focus();
394
+ }
395
+ }
396
+
397
+ // ── Delegated events ───────────────────────────────────────────────────────
398
+
399
+ // Capture phase, so Quarto's lightbox (GLightbox, bound to the a.lightbox wrapper) never sees the
400
+ // click when an author forced `lightbox: true`: one click, one viewer.
401
+ document.addEventListener('click', function (e) {
402
+ if (e.button !== 0 || isOpen()) return;
403
+ var img = triggerFor(e.target);
404
+ if (!img) {
405
+ var forced = e.target.closest ? e.target.closest('a.lightbox') : null;
406
+ var inner = forced && forced.querySelector(TRIGGER);
407
+ img = inner ? triggerFor(inner) : null;
408
+ if (!img) return;
409
+ }
410
+ e.preventDefault();
411
+ e.stopPropagation();
412
+ decorate(img);
413
+ openModal(img);
414
+ }, true);
415
+
416
+ document.addEventListener('keydown', function (e) {
417
+ if (isOpen()) {
418
+ if (e.key === 'Escape') closeModal();
419
+ return;
420
+ }
421
+ if (e.key !== 'Enter' && e.key !== ' ') return;
422
+ var img = triggerFor(e.target);
423
+ if (!img || e.target !== img) return;
424
+ e.preventDefault();
425
+ // Enter opens on keydown. Space opens on keyup, on the same trigger: opening on keydown moves focus
426
+ // to the close button, and Firefox then fires a click on that button at the Space keyup.
427
+ if (e.key === ' ') pendingSpace = e.repeat ? pendingSpace : img;
428
+ else openModal(img);
429
+ });
430
+
431
+ document.addEventListener('keyup', function (e) {
432
+ if (e.key !== ' ') return;
433
+ var img = pendingSpace;
434
+ pendingSpace = null;
435
+ if (!img || isOpen() || e.target !== img) return;
436
+ e.preventDefault();
437
+ openModal(img);
438
+ });
439
+
440
+ function start() {
441
+ decorateAll();
442
+ observeLateTriggers();
443
+ }
444
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
445
+ else start();
446
+ })();
@@ -1,4 +1,4 @@
1
- % @dataimago/css-neutral@0.1.0-alpha.16 dist/latex/dataimago-tokens.sty · sha256:e34341231dbc2dbf187ed75537c4047dbae0fc32625486b8e8ef3dfc1d19a168 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync
1
+ % @dataimago/css-neutral@0.1.0-alpha.18 dist/latex/dataimago-tokens.sty · sha256:64920a90a7cf390f8c556c02cbef14a2fb4da51cd9fdb235c0d67ccf95870f65 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
2
  \NeedsTeXFormat{LaTeX2e}
3
3
  \ProvidesPackage{dataimago-tokens}[dataimago design tokens, light mode]
4
4
  \RequirePackage{xcolor}
@@ -30,30 +30,38 @@
30
30
  \definecolor{di-palette-paper-300}{HTML}{F5E8CF}
31
31
  \definecolor{di-palette-paper-400}{HTML}{EDD9B3}
32
32
  \definecolor{di-palette-paper-500}{HTML}{E0C088}
33
- \definecolor{di-functional-success}{HTML}{27AE60}
34
- \definecolor{di-functional-warning}{HTML}{F39C12}
35
- \definecolor{di-functional-error}{HTML}{E74C3C}
36
- \definecolor{di-functional-info}{HTML}{3498DB}
33
+ \definecolor{di-functional-success}{HTML}{009E73}
34
+ \definecolor{di-functional-warning}{HTML}{E69F00}
35
+ \definecolor{di-functional-error}{HTML}{EF5350}
36
+ \definecolor{di-functional-info}{HTML}{D6D3D1}
37
37
  \definecolor{di-surface-page}{HTML}{EDEDEB}
38
38
  \definecolor{di-surface-page-scrolled}{HTML}{EDEDEB}
39
39
  \definecolor{di-surface-elevated}{HTML}{F7F7F6}
40
- \definecolor{di-surface-sunken}{HTML}{FAF2E3}
40
+ \definecolor{di-surface-sunken}{HTML}{F7F7F6}
41
41
  \definecolor{di-surface-navbar}{HTML}{EDEDEB}
42
42
  \definecolor{di-surface-navbar-scrolled}{HTML}{EDEDEB}
43
- \definecolor{di-surface-code}{HTML}{FAF2E3}
43
+ \definecolor{di-surface-code}{HTML}{F7F7F6}
44
+ \definecolor{di-surface-scrim}{HTML}{353531}
45
+ \definecolor{di-surface-scrim-solid}{HTML}{252522}
44
46
  \definecolor{di-border-subtle}{HTML}{888785}
45
47
  \definecolor{di-border-moderate}{HTML}{666563}
46
48
  \definecolor{di-border-strong}{HTML}{444342}
47
49
  \definecolor{di-border-card}{HTML}{666563}
48
50
  \definecolor{di-border-code}{HTML}{D6D3D1}
51
+ \definecolor{di-border-on-scrim-focus}{HTML}{F7F7F6}
49
52
  \definecolor{di-content-primary}{HTML}{14140F}
50
53
  \definecolor{di-content-secondary}{HTML}{424240}
51
54
  \definecolor{di-content-muted}{HTML}{5E5E5C}
52
55
  \definecolor{di-content-inverse}{HTML}{FDF9F2}
56
+ \definecolor{di-content-on-scrim}{HTML}{F7F7F6}
53
57
  \definecolor{di-interactive-primary}{HTML}{292524}
54
58
  \definecolor{di-interactive-hover}{HTML}{1C1917}
55
59
  \definecolor{di-interactive-accent}{HTML}{292524}
56
60
  \definecolor{di-interactive-focus}{HTML}{292524}
61
+ \definecolor{di-state-success}{HTML}{007A58}
62
+ \definecolor{di-state-warning}{HTML}{906306}
63
+ \definecolor{di-state-error}{HTML}{A4262C}
64
+ \definecolor{di-state-info}{HTML}{292524}
57
65
  \definecolor{di-dataviz-okabe-ito-orange}{HTML}{E69F00}
58
66
  \definecolor{di-dataviz-okabe-ito-sky-blue}{HTML}{56B4E9}
59
67
  \definecolor{di-dataviz-okabe-ito-bluish-green}{HTML}{009E73}
package/dist/outputs.json CHANGED
@@ -1,59 +1,60 @@
1
1
  {
2
2
  "package": "@dataimago/css-neutral",
3
- "version": "0.1.0-alpha.16",
3
+ "version": "0.1.0-alpha.18",
4
4
  "files": {
5
- "dataviz/dataimago-dataviz.css": "ba2c26c26d38174df111c569a6379f77578edad5470ba2abc0e745f6c7800485",
6
- "dataviz/dataimago-dataviz.json": "7dcb85fc688ba350b55c04593903310957605af0c7ff4899c1ccc9c4717f19a6",
7
- "dataviz/dataimago-dataviz.tex": "ffc66b45f6cf71c9d1546b64e5ec3b801af275bf0fdc23f8c36e6ab56d31f88a",
8
- "dataviz/dataimago_dataviz.R": "88cfb443c99dc118dfe72bdd1397a2e92bbd23c780812d2cfa0878bd7215164c",
5
+ "dataviz/dataimago-dataviz.css": "3442e00c96de1a376a277fc05c93fe8c310a51fede262099f5f4307c28583646",
6
+ "dataviz/dataimago-dataviz.json": "1fda85572862195fa25e5671d329c25e9b3ca1d322fd5a76111b21e579f459f8",
7
+ "dataviz/dataimago-dataviz.tex": "05c69d0d3cc3fbd9f484f01938b26a4a6c449651d8f65cac694f88179a37d668",
8
+ "dataviz/dataimago_dataviz.R": "8885b43cee3fa797c4777579cf4caad7110b42c28513f2db315f51bdb9d05983",
9
9
  "fonts/cyrillic-ext/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
10
10
  "fonts/cyrillic-ext/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
11
- "fonts/cyrillic-ext/fonts.css": "53ec8ddf0a38c3d19f7d4ca8214d12c4f1008b45996676771e4c942bd3d226f3",
11
+ "fonts/cyrillic-ext/fonts.css": "3f8b517a626428003412041d415a6106e1d40c3c85ea0b9c0dce365b41b0d446",
12
12
  "fonts/cyrillic-ext/noto-sans-italic.woff2": "e43ef19dd130cf6564cc06d68a8567a8f323047584f81e251a46e2b15a2f1d49",
13
13
  "fonts/cyrillic-ext/noto-sans-mono.woff2": "4f62d4266b525554838d2e19d581710ee0f4963612310c8552c6f15e21ff309a",
14
14
  "fonts/cyrillic-ext/noto-sans.woff2": "b6a3b92bc2e7ff8d0692c2ad266f06e40e2b1ec388f3e90234af957a3272316a",
15
15
  "fonts/cyrillic/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
16
16
  "fonts/cyrillic/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
17
- "fonts/cyrillic/fonts.css": "07b0046514cd3e30aa241a37f019546182298abc3cb9fb2dbb40f97e221376fb",
17
+ "fonts/cyrillic/fonts.css": "2205468d983ec115f7197d5e21a6d17a167a4b6cb122fb885430aed9ef2c52e4",
18
18
  "fonts/cyrillic/noto-sans-italic.woff2": "ef6d4e10370334dc2f19230350c6008b528998abc474deb908d3ed4ae9d951c2",
19
19
  "fonts/cyrillic/noto-sans-mono.woff2": "e5b0c11fb6cc4c39dd406d17b7a1afe512264f27d58ec5b21e05c72f9347c43e",
20
20
  "fonts/cyrillic/noto-sans.woff2": "ee4d2c2b38b5ba72dadb0fb56ce6e152d6fcb39ee49955245e80c7b4a9d42a6e",
21
21
  "fonts/greek-ext/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
22
22
  "fonts/greek-ext/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
23
- "fonts/greek-ext/fonts.css": "e6ab10fcd70df58251cd9da1a4d938a8a57d2bf96849e30f43043c6ba926ff67",
23
+ "fonts/greek-ext/fonts.css": "3d42d3c7254af3db886f9926eff575b46ec67ad5c945939182762a6d945208e9",
24
24
  "fonts/greek-ext/noto-sans-italic.woff2": "efbc584896c29627152d47b5b8975d72d7e1b9dfda4ef0e0a79d61cea84a99b8",
25
25
  "fonts/greek-ext/noto-sans-mono.woff2": "59d4726f29ea68cc31bae66f8f5d936c26b9f6e2e4f75a8640cb4a9934ff6d98",
26
26
  "fonts/greek-ext/noto-sans.woff2": "eff6e032b0aebb4f6220f50b6afb13fcea3b68a0beb31f1796447854baab667e",
27
27
  "fonts/greek/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
28
28
  "fonts/greek/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
29
- "fonts/greek/fonts.css": "41e10b8d16790cd763b6bc728c3f720fac52c1b2ced8c583a7adb2af5f8d03b5",
29
+ "fonts/greek/fonts.css": "906cb62ca2d41d34131eab48f2f25c9a11b4c4333b03c77dd440500ab788f2d7",
30
30
  "fonts/greek/noto-sans-italic.woff2": "b786720515691eaac7642f6e0e7824359511770d37594067bcf9c06db7c100ce",
31
31
  "fonts/greek/noto-sans-mono.woff2": "b73c27885be7a02aea7dbfc6ed91e9c8791ff7f455bc24344aadd4a492465950",
32
32
  "fonts/greek/noto-sans.woff2": "5236e246865e7a26bb8839ba1350d43db176c2e8e8fd986da8dd30b8623d9be0",
33
- "fonts/lang.css": "ab836d70dd3d995a0e5d9f332771a1c87514ad83437e9c8657c9b8cbb298ca40",
33
+ "fonts/lang.css": "cc8202de6b4e691fefdc8ea62f2685a0271f04d818ccb0c2663d15fe8f0dd805",
34
34
  "fonts/latin-ext/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
35
35
  "fonts/latin-ext/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
36
- "fonts/latin-ext/fonts.css": "469fedf4cfb9a4f0ddc524241da9519eb18076627068e731149cf94d134d2bdc",
36
+ "fonts/latin-ext/fonts.css": "1d0005a213ec771ab46a149f28b24e1f57d8aff0b24e80f831455f2a38ef3db4",
37
37
  "fonts/latin-ext/noto-sans-italic.woff2": "73d821b043f17020a0332cbc56a31bea59d8346a53c03777f66889a0ad718997",
38
38
  "fonts/latin-ext/noto-sans-mono.woff2": "3f87ba62a12d4659b5bd91aa6cc12c5f111377152e8ed4010251af7dedea4e06",
39
39
  "fonts/latin-ext/noto-sans.woff2": "25713d5d56b03ad45105b83b51a62e119122d7949df1769d34fad9ed1993d9d5",
40
40
  "fonts/latin/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
41
41
  "fonts/latin/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
42
- "fonts/latin/fonts.css": "a69185b46ddf1c34a73e1b0b1467bf21ddb3a4ed70d194931c847d815a9072f1",
42
+ "fonts/latin/fonts.css": "d0076f473d52014ac91910e3280a4eba4e93eddddf9d670c2fdf0d80c90b5850",
43
43
  "fonts/latin/noto-sans-italic.woff2": "ad80ce4e76242569275e70e68331b798255afb91ed358238d9125039dd75c23b",
44
44
  "fonts/latin/noto-sans-mono.woff2": "11e93a684ed911abe586152bbceaadbf42e757d44d756eec7f445aa28fec6eba",
45
45
  "fonts/latin/noto-sans.woff2": "039e8aa65c7d0b18d5685136302b207c0c8a6f180ca610bcd07a24425ecca296",
46
46
  "fonts/math/OFL-NotoSansMath.txt": "c9c63b8ed6cf76b2ce0c58b241acfc1195c2c928334c989c7047cbdac58773d9",
47
- "fonts/math/fonts.css": "0b6abe2febc5a763312f3af81647bbc95da18725faf472f4e265678b00ed1660",
47
+ "fonts/math/fonts.css": "e011a5dfa3e235151fa87f50cfa9bd1b3e2c886f76a3f471ae77e8d695056b9b",
48
48
  "fonts/math/noto-sans-math.woff2": "30f85f333343fc8a5fb4d93c4b66886544cd6fbe338bda0109ebed23df254df0",
49
49
  "fonts/vietnamese/OFL-NotoSans.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
50
50
  "fonts/vietnamese/OFL-NotoSansMono.txt": "cee9892f9f0cc8fe882c9e9537ee6a89621d86ee7ceaf70b02e2b2b1c25c061a",
51
- "fonts/vietnamese/fonts.css": "0566c53a9d2dfcd4b1427ebe0cb6f5600a912aa30e16ff348decb759e71105b8",
51
+ "fonts/vietnamese/fonts.css": "8976d34ca9e54df221f0801feb9b1adb3c2802209a4602f5b6f6ebe7302f8402",
52
52
  "fonts/vietnamese/noto-sans-italic.woff2": "449fa7963dd8e53c7a1d47fe696464df59627bf7585eae4bc96a4cb72c98bd64",
53
53
  "fonts/vietnamese/noto-sans-mono.woff2": "4cf1643290fefa9d0b2f8a6a6df076d3ba226db90c1954c42e27735b3b6e8075",
54
54
  "fonts/vietnamese/noto-sans.woff2": "0d3eb41e600702e4415b8860cd248ce3bcb710b2d81e18517a02048836cdc88e",
55
- "latex/dataimago-tokens.sty": "87f261f40fa050a7bf007e6a4b27bf2972d51a77380d8aad329a669640e7e210",
56
- "quarto/neutral-dark.scss": "e82cbe5da19318123fc7ff7d1c6b55e69057fd1ecaa639cb88995f07c72c10f0",
57
- "quarto/neutral-light.scss": "56b2e17500ea6af72d9e0941e612295df6c28c4cbec819af5a99a6fe7975309f"
55
+ "js/figure-viewer.js": "6bfabc6eb153cd64096cf5882b958af6e75529551972d706aab090b4bc5c12b9",
56
+ "latex/dataimago-tokens.sty": "6892917358c4f6f4ea07e6e133325623f0bbdb6723e4685b2b1375c0f4f06750",
57
+ "quarto/neutral-dark.scss": "5a20cbb20c0bc1065d1468d5f93cf905ff3b5146bcb9990254285d927d019c8e",
58
+ "quarto/neutral-light.scss": "d2d42731655333fd6c2794d829e6fc30150c70b769d41908d3208a65f49dea4b"
58
59
  }
59
60
  }
@@ -1,5 +1,5 @@
1
- // @dataimago/css-neutral@0.1.0-alpha.16 dist/quarto/neutral-dark.scss · sha256:fdabc62c92636f8d9e82e8d4a175a8daeacfef310c1c0c05016831b7f6b18117 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync
2
- // neutral dark theme for Quarto 1.8 — generated from the design tokens (tools/formats/quarto.mjs).
1
+ // @dataimago/css-neutral@0.1.0-alpha.18 dist/quarto/neutral-dark.scss · sha256:11ff2e4e00df2500fbad8e8b9846bb74a8d8b5cdcac3dee1baa4255c08edbae0 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
+ // neutral dark theme for Quarto 1.11 — 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
 
5
5
  /*-- scss:defaults --*/
@@ -11,7 +11,19 @@ $link-color: #d6d3d1 !default;
11
11
  $link-hover-color: #a8a29e !default;
12
12
  $code-color: #d6d3d1 !default;
13
13
  $code-bg: #1c1917 !default;
14
+ $pre-color: #fdf9f2 !default;
14
15
  $border-color: #7d7b76 !default;
16
+ $primary: #d6d3d1 !default;
17
+ $secondary: #a8a29e !default;
18
+ $success: #009e73 !default;
19
+ $info: #d6d3d1 !default;
20
+ $warning: #e69f00 !default;
21
+ $danger: #ef5350 !default;
22
+ $callout-color-note: #d6d3d1 !default;
23
+ $callout-color-tip: #009e73 !default;
24
+ $callout-color-important: #ef5350 !default;
25
+ $callout-color-caution: #e69f00 !default;
26
+ $callout-color-warning: #e69f00 !default;
15
27
  $font-family-sans-serif: Noto Sans, Noto Sans Math, system-ui, sans-serif !default;
16
28
  $font-family-monospace: Noto Sans Mono, SF Mono, Monaco, Inconsolata, monospace !default;
17
29
  $headings-font-family: Noto Sans, Noto Sans Math, system-ui, sans-serif !default;
@@ -48,10 +60,10 @@ $web-font-path: false !default;
48
60
  --color-palette-paper-300: #f5e8cf;
49
61
  --color-palette-paper-400: #edd9b3;
50
62
  --color-palette-paper-500: #e0c088;
51
- --color-functional-success: #27AE60;
52
- --color-functional-warning: #F39C12;
53
- --color-functional-error: #E74C3C;
54
- --color-functional-info: #3498DB;
63
+ --color-functional-success: #009E73;
64
+ --color-functional-warning: #E69F00;
65
+ --color-functional-error: #ef5350;
66
+ --color-functional-info: #d6d3d1;
55
67
  --transition-quick: 0.15s ease;
56
68
  --transition-standard: 0.25s ease-in-out;
57
69
  --transition-smooth: 0.35s ease;
@@ -138,19 +150,27 @@ $web-font-path: false !default;
138
150
  --color-surface-navbar: #141410;
139
151
  --color-surface-navbar-scrolled: #141410;
140
152
  --color-surface-code: #1c1917;
153
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
154
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
141
155
  --color-border-subtle: rgba(253, 249, 242, 0.45);
142
156
  --color-border-moderate: rgba(253, 249, 242, 0.60);
143
157
  --color-border-strong: rgba(253, 249, 242, 0.75);
144
158
  --color-border-card: rgba(253, 249, 242, 0.60);
145
159
  --color-border-code: #292524;
160
+ --color-border-on-scrim-focus: #f7f7f6;
146
161
  --color-content-primary: #fdf9f2;
147
162
  --color-content-secondary: #a8a29e;
148
163
  --color-content-muted: #89827d;
149
164
  --color-content-inverse: #0c0a09;
165
+ --color-content-on-scrim: #f7f7f6;
150
166
  --color-interactive-primary: #d6d3d1;
151
167
  --color-interactive-hover: #a8a29e;
152
168
  --color-interactive-accent: #d6d3d1;
153
169
  --color-interactive-focus: #d6d3d1;
170
+ --color-state-success: #009E73;
171
+ --color-state-warning: #E69F00;
172
+ --color-state-error: #ef5350;
173
+ --color-state-info: #d6d3d1;
154
174
  --contrast-high: rgb(237, 237, 235);
155
175
  --contrast-readable: rgb(237, 237, 235);
156
176
  --contrast-medium: #83838f;
@@ -158,6 +178,8 @@ $web-font-path: false !default;
158
178
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
159
179
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
160
180
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
181
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
182
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
161
183
  --border-subtle: rgba(237, 237, 235, 0.47);
162
184
  --border-moderate: rgba(237, 237, 235, 0.63);
163
185
  --border-focus: #4FC3F7;
@@ -217,6 +239,22 @@ pre, div.sourceCode {
217
239
  border: 1px solid var(--color-border-code);
218
240
  }
219
241
 
242
+ // Unhighlighted blocks (fenced text, chunk output) take Bootstrap's pre colour, which Quarto compiles to #000:
243
+ // invisible on the dark card. A bare element selector, so the syntax-highlighting sheet still colours
244
+ // highlighted blocks (2026-11-03).
245
+ pre {
246
+ color: var(--color-content-primary);
247
+ }
248
+
249
+ // References run together when the CSL style asks for entry-spacing 0 (APA does): Pandoc writes the entries as
250
+ // bare divs and gives them an inline margin of entry-spacing em, which is 0 there. Half a line between them
251
+ // (line-height 1.5), as the PDF format does (LIwLD author review, 2026-11-03). Only for entry-spacing 0, on
252
+ // the bibliography's own entries: a style that asks for spacing keeps it, and Quarto's citation hover popups
253
+ // (also .csl-entry) are untouched.
254
+ div.csl-bib-body[data-entry-spacing="0"] > div.csl-entry {
255
+ margin-bottom: 0.75em;
256
+ }
257
+
220
258
  // Quarto themes its popups as [data-theme~="quarto"] at compile time ($body-bg);
221
259
  // match that specificity so the runtime token wins.
222
260
  .tippy-box, .tippy-box[data-theme~="quarto"] {
@@ -1,5 +1,5 @@
1
- // @dataimago/css-neutral@0.1.0-alpha.16 dist/quarto/neutral-light.scss · sha256:4be7386c294c85453ecf1a37ad3d29764aafc9a9b5774f41218f81357e810d35 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.16 dataimago-sync
2
- // neutral light theme for Quarto 1.8 — generated from the design tokens (tools/formats/quarto.mjs).
1
+ // @dataimago/css-neutral@0.1.0-alpha.18 dist/quarto/neutral-light.scss · sha256:ad4fcd4a9427ed7ce269d26392494cb840c0ef4903a63dd225e9446c79ed14d7 · generated from tokens; do not edit · restore: npx -p @dataimago/css-neutral@0.1.0-alpha.18 dataimago-sync
2
+ // neutral light theme for Quarto 1.11 — 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
 
5
5
  /*-- scss:defaults --*/
@@ -10,8 +10,20 @@ $navbar-bg: #ededeb !default;
10
10
  $link-color: #292524 !default;
11
11
  $link-hover-color: #1c1917 !default;
12
12
  $code-color: #292524 !default;
13
- $code-bg: #faf2e3 !default;
13
+ $code-bg: #f7f7f6 !default;
14
+ $pre-color: #14140f !default;
14
15
  $border-color: #888785 !default;
16
+ $primary: #292524 !default;
17
+ $secondary: #424240 !default;
18
+ $success: #007a58 !default;
19
+ $info: #292524 !default;
20
+ $warning: #906306 !default;
21
+ $danger: #a4262c !default;
22
+ $callout-color-note: #292524 !default;
23
+ $callout-color-tip: #007a58 !default;
24
+ $callout-color-important: #a4262c !default;
25
+ $callout-color-caution: #906306 !default;
26
+ $callout-color-warning: #906306 !default;
15
27
  $font-family-sans-serif: Noto Sans, Noto Sans Math, system-ui, sans-serif !default;
16
28
  $font-family-monospace: Noto Sans Mono, SF Mono, Monaco, Inconsolata, monospace !default;
17
29
  $headings-font-family: Noto Sans, Noto Sans Math, system-ui, sans-serif !default;
@@ -48,10 +60,10 @@ $web-font-path: false !default;
48
60
  --color-palette-paper-300: #f5e8cf;
49
61
  --color-palette-paper-400: #edd9b3;
50
62
  --color-palette-paper-500: #e0c088;
51
- --color-functional-success: #27AE60;
52
- --color-functional-warning: #F39C12;
53
- --color-functional-error: #E74C3C;
54
- --color-functional-info: #3498DB;
63
+ --color-functional-success: #009E73;
64
+ --color-functional-warning: #E69F00;
65
+ --color-functional-error: #ef5350;
66
+ --color-functional-info: #d6d3d1;
55
67
  --transition-quick: 0.15s ease;
56
68
  --transition-standard: 0.25s ease-in-out;
57
69
  --transition-smooth: 0.35s ease;
@@ -134,23 +146,31 @@ $web-font-path: false !default;
134
146
  --color-surface-page: #ededeb;
135
147
  --color-surface-page-scrolled: #ededeb;
136
148
  --color-surface-elevated: #f7f7f6;
137
- --color-surface-sunken: #faf2e3;
149
+ --color-surface-sunken: #f7f7f6;
138
150
  --color-surface-navbar: #ededeb;
139
151
  --color-surface-navbar-scrolled: #ededeb;
140
- --color-surface-code: #faf2e3;
152
+ --color-surface-code: #f7f7f6;
153
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
154
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
141
155
  --color-border-subtle: rgba(12, 10, 9, 0.45);
142
156
  --color-border-moderate: rgba(12, 10, 9, 0.60);
143
157
  --color-border-strong: rgba(12, 10, 9, 0.75);
144
158
  --color-border-card: rgba(12, 10, 9, 0.60);
145
159
  --color-border-code: #d6d3d1;
160
+ --color-border-on-scrim-focus: #f7f7f6;
146
161
  --color-content-primary: #14140f;
147
162
  --color-content-secondary: #424240;
148
163
  --color-content-muted: #5e5e5c;
149
164
  --color-content-inverse: #fdf9f2;
165
+ --color-content-on-scrim: #f7f7f6;
150
166
  --color-interactive-primary: #292524;
151
167
  --color-interactive-hover: #1c1917;
152
168
  --color-interactive-accent: #292524;
153
169
  --color-interactive-focus: #292524;
170
+ --color-state-success: #007a58;
171
+ --color-state-warning: #906306;
172
+ --color-state-error: #a4262c;
173
+ --color-state-info: #292524;
154
174
  --contrast-high: rgb(20, 20, 16);
155
175
  --contrast-readable: rgb(20, 20, 16);
156
176
  --contrast-medium: #7c7c7c;
@@ -158,6 +178,8 @@ $web-font-path: false !default;
158
178
  --shadow-subtle: 0 1px 2px 0 rgb(20 20 16 / 0.05);
159
179
  --shadow-moderate: 0 4px 6px -1px rgb(20 20 16 / 0.1);
160
180
  --shadow-prominent: 0 10px 15px -3px rgb(20 20 16 / 0.1);
181
+ --shadow-figure-plate-hover: 0 10px 15px -3px rgb(20 20 16 / 0.1);
182
+ --shadow-figure-plate-active: 0 4px 6px -1px rgb(20 20 16 / 0.1);
161
183
  --border-subtle: rgba(20, 20, 16, 0.47);
162
184
  --border-moderate: rgba(20, 20, 16, 0.63);
163
185
  --border-focus: #3498DB;
@@ -217,6 +239,22 @@ pre, div.sourceCode {
217
239
  border: 1px solid var(--color-border-code);
218
240
  }
219
241
 
242
+ // Unhighlighted blocks (fenced text, chunk output) take Bootstrap's pre colour, which Quarto compiles to #000:
243
+ // invisible on the dark card. A bare element selector, so the syntax-highlighting sheet still colours
244
+ // highlighted blocks (2026-11-03).
245
+ pre {
246
+ color: var(--color-content-primary);
247
+ }
248
+
249
+ // References run together when the CSL style asks for entry-spacing 0 (APA does): Pandoc writes the entries as
250
+ // bare divs and gives them an inline margin of entry-spacing em, which is 0 there. Half a line between them
251
+ // (line-height 1.5), as the PDF format does (LIwLD author review, 2026-11-03). Only for entry-spacing 0, on
252
+ // the bibliography's own entries: a style that asks for spacing keeps it, and Quarto's citation hover popups
253
+ // (also .csl-entry) are untouched.
254
+ div.csl-bib-body[data-entry-spacing="0"] > div.csl-entry {
255
+ margin-bottom: 0.75em;
256
+ }
257
+
220
258
  // Quarto themes its popups as [data-theme~="quarto"] at compile time ($body-bg);
221
259
  // match that specificity so the runtime token wins.
222
260
  .tippy-box, .tippy-box[data-theme~="quarto"] {
@@ -52,10 +52,10 @@ module.exports = {
52
52
  "500": "#e0c088"
53
53
  },
54
54
  "functional": {
55
- "success": "#27AE60",
56
- "warning": "#F39C12",
57
- "error": "#E74C3C",
58
- "info": "#3498DB"
55
+ "success": "#009E73",
56
+ "warning": "#E69F00",
57
+ "error": "#ef5350",
58
+ "info": "#d6d3d1"
59
59
  }
60
60
  },
61
61
  fontFamily: {
package/dist/tokens.css CHANGED
@@ -25,10 +25,10 @@
25
25
  --color-palette-paper-300: #f5e8cf;
26
26
  --color-palette-paper-400: #edd9b3;
27
27
  --color-palette-paper-500: #e0c088;
28
- --color-functional-success: #27AE60;
29
- --color-functional-warning: #F39C12;
30
- --color-functional-error: #E74C3C;
31
- --color-functional-info: #3498DB;
28
+ --color-functional-success: #009E73;
29
+ --color-functional-warning: #E69F00;
30
+ --color-functional-error: #ef5350;
31
+ --color-functional-info: #d6d3d1;
32
32
  --transition-quick: 0.15s ease;
33
33
  --transition-standard: 0.25s ease-in-out;
34
34
  --transition-smooth: 0.35s ease;
@@ -111,23 +111,31 @@
111
111
  --color-surface-page: #ededeb;
112
112
  --color-surface-page-scrolled: #ededeb;
113
113
  --color-surface-elevated: #f7f7f6;
114
- --color-surface-sunken: #faf2e3;
114
+ --color-surface-sunken: #f7f7f6;
115
115
  --color-surface-navbar: #ededeb;
116
116
  --color-surface-navbar-scrolled: #ededeb;
117
- --color-surface-code: #faf2e3;
117
+ --color-surface-code: #f7f7f6;
118
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
119
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
118
120
  --color-border-subtle: rgba(12, 10, 9, 0.45);
119
121
  --color-border-moderate: rgba(12, 10, 9, 0.60);
120
122
  --color-border-strong: rgba(12, 10, 9, 0.75);
121
123
  --color-border-card: rgba(12, 10, 9, 0.60);
122
124
  --color-border-code: #d6d3d1;
125
+ --color-border-on-scrim-focus: #f7f7f6;
123
126
  --color-content-primary: #14140f;
124
127
  --color-content-secondary: #424240;
125
128
  --color-content-muted: #5e5e5c;
126
129
  --color-content-inverse: #fdf9f2;
130
+ --color-content-on-scrim: #f7f7f6;
127
131
  --color-interactive-primary: #292524;
128
132
  --color-interactive-hover: #1c1917;
129
133
  --color-interactive-accent: #292524;
130
134
  --color-interactive-focus: #292524;
135
+ --color-state-success: #007a58;
136
+ --color-state-warning: #906306;
137
+ --color-state-error: #a4262c;
138
+ --color-state-info: #292524;
131
139
  --contrast-high: rgb(20, 20, 16);
132
140
  --contrast-readable: rgb(20, 20, 16);
133
141
  --contrast-medium: #7c7c7c;
@@ -135,6 +143,8 @@
135
143
  --shadow-subtle: 0 1px 2px 0 rgb(20 20 16 / 0.05);
136
144
  --shadow-moderate: 0 4px 6px -1px rgb(20 20 16 / 0.1);
137
145
  --shadow-prominent: 0 10px 15px -3px rgb(20 20 16 / 0.1);
146
+ --shadow-figure-plate-hover: 0 10px 15px -3px rgb(20 20 16 / 0.1);
147
+ --shadow-figure-plate-active: 0 4px 6px -1px rgb(20 20 16 / 0.1);
138
148
  --border-subtle: rgba(20, 20, 16, 0.47);
139
149
  --border-moderate: rgba(20, 20, 16, 0.63);
140
150
  --border-focus: #3498DB;
@@ -155,19 +165,27 @@
155
165
  --color-surface-navbar: #141410;
156
166
  --color-surface-navbar-scrolled: #141410;
157
167
  --color-surface-code: #1c1917;
168
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
169
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
158
170
  --color-border-subtle: rgba(253, 249, 242, 0.45);
159
171
  --color-border-moderate: rgba(253, 249, 242, 0.60);
160
172
  --color-border-strong: rgba(253, 249, 242, 0.75);
161
173
  --color-border-card: rgba(253, 249, 242, 0.60);
162
174
  --color-border-code: #292524;
175
+ --color-border-on-scrim-focus: #f7f7f6;
163
176
  --color-content-primary: #fdf9f2;
164
177
  --color-content-secondary: #a8a29e;
165
178
  --color-content-muted: #89827d;
166
179
  --color-content-inverse: #0c0a09;
180
+ --color-content-on-scrim: #f7f7f6;
167
181
  --color-interactive-primary: #d6d3d1;
168
182
  --color-interactive-hover: #a8a29e;
169
183
  --color-interactive-accent: #d6d3d1;
170
184
  --color-interactive-focus: #d6d3d1;
185
+ --color-state-success: #009E73;
186
+ --color-state-warning: #E69F00;
187
+ --color-state-error: #ef5350;
188
+ --color-state-info: #d6d3d1;
171
189
  --contrast-high: rgb(237, 237, 235);
172
190
  --contrast-readable: rgb(237, 237, 235);
173
191
  --contrast-medium: #83838f;
@@ -175,6 +193,8 @@
175
193
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
176
194
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
177
195
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
196
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
197
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
178
198
  --border-subtle: rgba(237, 237, 235, 0.47);
179
199
  --border-moderate: rgba(237, 237, 235, 0.63);
180
200
  --border-focus: #4FC3F7;
@@ -196,19 +216,27 @@
196
216
  --color-surface-navbar: #141410;
197
217
  --color-surface-navbar-scrolled: #141410;
198
218
  --color-surface-code: #1c1917;
219
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
220
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
199
221
  --color-border-subtle: rgba(253, 249, 242, 0.45);
200
222
  --color-border-moderate: rgba(253, 249, 242, 0.60);
201
223
  --color-border-strong: rgba(253, 249, 242, 0.75);
202
224
  --color-border-card: rgba(253, 249, 242, 0.60);
203
225
  --color-border-code: #292524;
226
+ --color-border-on-scrim-focus: #f7f7f6;
204
227
  --color-content-primary: #fdf9f2;
205
228
  --color-content-secondary: #a8a29e;
206
229
  --color-content-muted: #89827d;
207
230
  --color-content-inverse: #0c0a09;
231
+ --color-content-on-scrim: #f7f7f6;
208
232
  --color-interactive-primary: #d6d3d1;
209
233
  --color-interactive-hover: #a8a29e;
210
234
  --color-interactive-accent: #d6d3d1;
211
235
  --color-interactive-focus: #d6d3d1;
236
+ --color-state-success: #009E73;
237
+ --color-state-warning: #E69F00;
238
+ --color-state-error: #ef5350;
239
+ --color-state-info: #d6d3d1;
212
240
  --contrast-high: rgb(237, 237, 235);
213
241
  --contrast-readable: rgb(237, 237, 235);
214
242
  --contrast-medium: #83838f;
@@ -216,6 +244,8 @@
216
244
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
217
245
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
218
246
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
247
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
248
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
219
249
  --border-subtle: rgba(237, 237, 235, 0.47);
220
250
  --border-moderate: rgba(237, 237, 235, 0.63);
221
251
  --border-focus: #4FC3F7;
package/dist/tokens.scss CHANGED
@@ -25,10 +25,10 @@
25
25
  --color-palette-paper-300: #f5e8cf;
26
26
  --color-palette-paper-400: #edd9b3;
27
27
  --color-palette-paper-500: #e0c088;
28
- --color-functional-success: #27AE60;
29
- --color-functional-warning: #F39C12;
30
- --color-functional-error: #E74C3C;
31
- --color-functional-info: #3498DB;
28
+ --color-functional-success: #009E73;
29
+ --color-functional-warning: #E69F00;
30
+ --color-functional-error: #ef5350;
31
+ --color-functional-info: #d6d3d1;
32
32
  --transition-quick: 0.15s ease;
33
33
  --transition-standard: 0.25s ease-in-out;
34
34
  --transition-smooth: 0.35s ease;
@@ -111,23 +111,31 @@
111
111
  --color-surface-page: #ededeb;
112
112
  --color-surface-page-scrolled: #ededeb;
113
113
  --color-surface-elevated: #f7f7f6;
114
- --color-surface-sunken: #faf2e3;
114
+ --color-surface-sunken: #f7f7f6;
115
115
  --color-surface-navbar: #ededeb;
116
116
  --color-surface-navbar-scrolled: #ededeb;
117
- --color-surface-code: #faf2e3;
117
+ --color-surface-code: #f7f7f6;
118
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
119
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
118
120
  --color-border-subtle: rgba(12, 10, 9, 0.45);
119
121
  --color-border-moderate: rgba(12, 10, 9, 0.60);
120
122
  --color-border-strong: rgba(12, 10, 9, 0.75);
121
123
  --color-border-card: rgba(12, 10, 9, 0.60);
122
124
  --color-border-code: #d6d3d1;
125
+ --color-border-on-scrim-focus: #f7f7f6;
123
126
  --color-content-primary: #14140f;
124
127
  --color-content-secondary: #424240;
125
128
  --color-content-muted: #5e5e5c;
126
129
  --color-content-inverse: #fdf9f2;
130
+ --color-content-on-scrim: #f7f7f6;
127
131
  --color-interactive-primary: #292524;
128
132
  --color-interactive-hover: #1c1917;
129
133
  --color-interactive-accent: #292524;
130
134
  --color-interactive-focus: #292524;
135
+ --color-state-success: #007a58;
136
+ --color-state-warning: #906306;
137
+ --color-state-error: #a4262c;
138
+ --color-state-info: #292524;
131
139
  --contrast-high: rgb(20, 20, 16);
132
140
  --contrast-readable: rgb(20, 20, 16);
133
141
  --contrast-medium: #7c7c7c;
@@ -135,6 +143,8 @@
135
143
  --shadow-subtle: 0 1px 2px 0 rgb(20 20 16 / 0.05);
136
144
  --shadow-moderate: 0 4px 6px -1px rgb(20 20 16 / 0.1);
137
145
  --shadow-prominent: 0 10px 15px -3px rgb(20 20 16 / 0.1);
146
+ --shadow-figure-plate-hover: 0 10px 15px -3px rgb(20 20 16 / 0.1);
147
+ --shadow-figure-plate-active: 0 4px 6px -1px rgb(20 20 16 / 0.1);
138
148
  --border-subtle: rgba(20, 20, 16, 0.47);
139
149
  --border-moderate: rgba(20, 20, 16, 0.63);
140
150
  --border-focus: #3498DB;
@@ -155,19 +165,27 @@
155
165
  --color-surface-navbar: #141410;
156
166
  --color-surface-navbar-scrolled: #141410;
157
167
  --color-surface-code: #1c1917;
168
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
169
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
158
170
  --color-border-subtle: rgba(253, 249, 242, 0.45);
159
171
  --color-border-moderate: rgba(253, 249, 242, 0.60);
160
172
  --color-border-strong: rgba(253, 249, 242, 0.75);
161
173
  --color-border-card: rgba(253, 249, 242, 0.60);
162
174
  --color-border-code: #292524;
175
+ --color-border-on-scrim-focus: #f7f7f6;
163
176
  --color-content-primary: #fdf9f2;
164
177
  --color-content-secondary: #a8a29e;
165
178
  --color-content-muted: #89827d;
166
179
  --color-content-inverse: #0c0a09;
180
+ --color-content-on-scrim: #f7f7f6;
167
181
  --color-interactive-primary: #d6d3d1;
168
182
  --color-interactive-hover: #a8a29e;
169
183
  --color-interactive-accent: #d6d3d1;
170
184
  --color-interactive-focus: #d6d3d1;
185
+ --color-state-success: #009E73;
186
+ --color-state-warning: #E69F00;
187
+ --color-state-error: #ef5350;
188
+ --color-state-info: #d6d3d1;
171
189
  --contrast-high: rgb(237, 237, 235);
172
190
  --contrast-readable: rgb(237, 237, 235);
173
191
  --contrast-medium: #83838f;
@@ -175,6 +193,8 @@
175
193
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
176
194
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
177
195
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
196
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
197
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
178
198
  --border-subtle: rgba(237, 237, 235, 0.47);
179
199
  --border-moderate: rgba(237, 237, 235, 0.63);
180
200
  --border-focus: #4FC3F7;
@@ -196,19 +216,27 @@
196
216
  --color-surface-navbar: #141410;
197
217
  --color-surface-navbar-scrolled: #141410;
198
218
  --color-surface-code: #1c1917;
219
+ --color-surface-scrim: rgba(20, 20, 16, 0.85);
220
+ --color-surface-scrim-solid: rgba(20, 20, 16, 0.92);
199
221
  --color-border-subtle: rgba(253, 249, 242, 0.45);
200
222
  --color-border-moderate: rgba(253, 249, 242, 0.60);
201
223
  --color-border-strong: rgba(253, 249, 242, 0.75);
202
224
  --color-border-card: rgba(253, 249, 242, 0.60);
203
225
  --color-border-code: #292524;
226
+ --color-border-on-scrim-focus: #f7f7f6;
204
227
  --color-content-primary: #fdf9f2;
205
228
  --color-content-secondary: #a8a29e;
206
229
  --color-content-muted: #89827d;
207
230
  --color-content-inverse: #0c0a09;
231
+ --color-content-on-scrim: #f7f7f6;
208
232
  --color-interactive-primary: #d6d3d1;
209
233
  --color-interactive-hover: #a8a29e;
210
234
  --color-interactive-accent: #d6d3d1;
211
235
  --color-interactive-focus: #d6d3d1;
236
+ --color-state-success: #009E73;
237
+ --color-state-warning: #E69F00;
238
+ --color-state-error: #ef5350;
239
+ --color-state-info: #d6d3d1;
212
240
  --contrast-high: rgb(237, 237, 235);
213
241
  --contrast-readable: rgb(237, 237, 235);
214
242
  --contrast-medium: #83838f;
@@ -216,6 +244,8 @@
216
244
  --shadow-subtle: 0 1px 2px 0 rgb(237 237 235 / 0.03);
217
245
  --shadow-moderate: 0 4px 6px -1px rgb(237 237 235 / 0.05);
218
246
  --shadow-prominent: 0 10px 15px -3px rgb(237 237 235 / 0.4);
247
+ --shadow-figure-plate-hover: 0 4px 12px rgb(0 0 0 / 0.5);
248
+ --shadow-figure-plate-active: 0 2px 8px rgb(0 0 0 / 0.35);
219
249
  --border-subtle: rgba(237, 237, 235, 0.47);
220
250
  --border-moderate: rgba(237, 237, 235, 0.63);
221
251
  --border-focus: #4FC3F7;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataimago/css-neutral",
3
- "version": "0.1.0-alpha.16",
3
+ "version": "0.1.0-alpha.18",
4
4
  "description": "Neutral-identity compiled CSS + Tailwind preset — paired with @dataimago/tokens-neutral. Sensible defaults for externally-owned consumers (Level-3 user apps, third-party Level-2 hubs); Noto Sans throughout, neutral palette.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,6 +20,7 @@
20
20
  "./quarto/*": "./dist/quarto/*",
21
21
  "./latex/*": "./dist/latex/*",
22
22
  "./dataviz/*": "./dist/dataviz/*",
23
+ "./js/*": "./dist/js/*",
23
24
  "./fonts/*": "./dist/fonts/*",
24
25
  "./outputs.json": "./dist/outputs.json",
25
26
  "./package.json": "./package.json"
@@ -32,7 +33,7 @@
32
33
  "README.md"
33
34
  ],
34
35
  "dependencies": {
35
- "@dataimago/tokens-neutral": "^0.1.0-alpha.16"
36
+ "@dataimago/tokens-neutral": "^0.1.0-alpha.18"
36
37
  },
37
38
  "keywords": [
38
39
  "css",