@bitbaum/chatkit 0.14.0 → 0.14.2
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 +27 -0
- package/dist/audit.d.ts +31 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +54 -0
- package/dist/audit.js.map +1 -0
- package/dist/react/RichBlock.d.ts.map +1 -1
- package/dist/react/RichBlock.js +1 -1
- package/dist/react/RichBlock.js.map +1 -1
- package/package.json +5 -1
- package/styles.css +44 -7
package/README.md
CHANGED
|
@@ -151,6 +151,33 @@ answer's prose (or what you pass), only where one exists. A button that does
|
|
|
151
151
|
nothing is never shown. `ChatThread` renders it under every answer; pass
|
|
152
152
|
`speaker` and `share` through.
|
|
153
153
|
|
|
154
|
+
### Words are never cut (0.14.1)
|
|
155
|
+
|
|
156
|
+
A word may wrap onto the next line; it may never be cut in two. `.ck-md` sets
|
|
157
|
+
`overflow-wrap: anywhere` so a long URL cannot push the thread wider, but
|
|
158
|
+
`anywhere` also lowers a table cell's minimum width to one letter, and
|
|
159
|
+
Substrata's three-column answer at 390px read "Te / rm" and "Di / re / ct /
|
|
160
|
+
or / y" (2026-10-22). Tables now keep every word whole: columns share the width
|
|
161
|
+
by wrapping at spaces, and when even the words do not fit the table scrolls
|
|
162
|
+
sideways with a shadow on the edge that has more. The stack figure's tiles
|
|
163
|
+
wrap too: three across becomes two and one, or one under the other, rather
|
|
164
|
+
than cut "Manufacture".
|
|
165
|
+
|
|
166
|
+
`test/browser.mjs` measures it rather than reading the CSS: every word on the
|
|
167
|
+
page is laid out in a `Range` at 320, 390 and 1280px and must sit on one line
|
|
168
|
+
(a word beside a hyphen, slash or dot, and anything over 24 characters, is
|
|
169
|
+
exempt: a URL has to break somewhere). The demo thread carries the table from
|
|
170
|
+
the screenshot, so the check fails on the old stylesheet.
|
|
171
|
+
|
|
172
|
+
The check is exported so any product can run it against its own pages, from a
|
|
173
|
+
Playwright script (never from app code):
|
|
174
|
+
|
|
175
|
+
```js
|
|
176
|
+
import { BROKEN_WORDS_SOURCE } from "@bitbaum/chatkit/audit";
|
|
177
|
+
const broken = await page.evaluate(`(${BROKEN_WORDS_SOURCE})(document.body)`);
|
|
178
|
+
if (broken.length) throw new Error(`words cut across lines: ${broken}`);
|
|
179
|
+
```
|
|
180
|
+
|
|
154
181
|
### The feedback loop (0.14)
|
|
155
182
|
|
|
156
183
|
Two halves, one shape, so a bad answer is found by the product, not by the
|
package/dist/audit.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout audits for a real browser — the part no unit test can see.
|
|
3
|
+
*
|
|
4
|
+
* Import this from a Playwright script, never from app code. `findBrokenWords`
|
|
5
|
+
* runs INSIDE the page: it is self-contained on purpose (no imports, no
|
|
6
|
+
* closures), so its source can be handed to `page.evaluate`:
|
|
7
|
+
*
|
|
8
|
+
* import { BROKEN_WORDS_SOURCE } from "@bitbaum/chatkit/audit";
|
|
9
|
+
* const broken = await page.evaluate(`(${BROKEN_WORDS_SOURCE})(document.body)`);
|
|
10
|
+
* if (broken.length) throw new Error(`words cut across lines: ${broken}`);
|
|
11
|
+
*
|
|
12
|
+
* Why it exists: Substrata's answer table at 390px read "Te / rm" and
|
|
13
|
+
* "Di / re / ct / or / y" (2026-10-22). Reading the CSS finds none of it; only
|
|
14
|
+
* laying the words out does.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Every word under `root` that is drawn across two lines. A word may wrap onto
|
|
18
|
+
* the next line; it may never be cut in two. Measured, not inferred: each word
|
|
19
|
+
* is laid out in a `Range` and must sit on one line.
|
|
20
|
+
*
|
|
21
|
+
* Exempt, because a break there is legal: a word beside a hyphen, slash, dot,
|
|
22
|
+
* at-sign, colon or underscore, and anything over `maxWord` characters (a URL
|
|
23
|
+
* or an identifier has to break somewhere). Hidden text has no boxes and is
|
|
24
|
+
* skipped.
|
|
25
|
+
*/
|
|
26
|
+
export declare function findBrokenWords(root?: ParentNode, options?: {
|
|
27
|
+
maxWord?: number;
|
|
28
|
+
}): string[];
|
|
29
|
+
/** `findBrokenWords` as source text, for `page.evaluate`. */
|
|
30
|
+
export declare const BROKEN_WORDS_SOURCE: string;
|
|
31
|
+
//# sourceMappingURL=audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,IAAI,GAAE,UAAqB,EAC3B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GACjC,MAAM,EAAE,CA0BV;AAED,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,EAAE,MAAmC,CAAC"}
|
package/dist/audit.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout audits for a real browser — the part no unit test can see.
|
|
3
|
+
*
|
|
4
|
+
* Import this from a Playwright script, never from app code. `findBrokenWords`
|
|
5
|
+
* runs INSIDE the page: it is self-contained on purpose (no imports, no
|
|
6
|
+
* closures), so its source can be handed to `page.evaluate`:
|
|
7
|
+
*
|
|
8
|
+
* import { BROKEN_WORDS_SOURCE } from "@bitbaum/chatkit/audit";
|
|
9
|
+
* const broken = await page.evaluate(`(${BROKEN_WORDS_SOURCE})(document.body)`);
|
|
10
|
+
* if (broken.length) throw new Error(`words cut across lines: ${broken}`);
|
|
11
|
+
*
|
|
12
|
+
* Why it exists: Substrata's answer table at 390px read "Te / rm" and
|
|
13
|
+
* "Di / re / ct / or / y" (2026-10-22). Reading the CSS finds none of it; only
|
|
14
|
+
* laying the words out does.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Every word under `root` that is drawn across two lines. A word may wrap onto
|
|
18
|
+
* the next line; it may never be cut in two. Measured, not inferred: each word
|
|
19
|
+
* is laid out in a `Range` and must sit on one line.
|
|
20
|
+
*
|
|
21
|
+
* Exempt, because a break there is legal: a word beside a hyphen, slash, dot,
|
|
22
|
+
* at-sign, colon or underscore, and anything over `maxWord` characters (a URL
|
|
23
|
+
* or an identifier has to break somewhere). Hidden text has no boxes and is
|
|
24
|
+
* skipped.
|
|
25
|
+
*/
|
|
26
|
+
export function findBrokenWords(root = document, options = {}) {
|
|
27
|
+
const maxWord = options.maxWord ?? 24;
|
|
28
|
+
const found = [];
|
|
29
|
+
const near = /[-‐‑–—/_.@:]/;
|
|
30
|
+
const walker = document.createTreeWalker(root instanceof Document ? root.body : root, NodeFilter.SHOW_TEXT);
|
|
31
|
+
for (let n = walker.nextNode(); n; n = walker.nextNode()) {
|
|
32
|
+
const text = n.nodeValue ?? "";
|
|
33
|
+
const re = /[\p{L}\p{N}']+/gu;
|
|
34
|
+
for (let m = re.exec(text); m; m = re.exec(text)) {
|
|
35
|
+
const word = m[0];
|
|
36
|
+
if (word.length > maxWord)
|
|
37
|
+
continue;
|
|
38
|
+
if (near.test(text[m.index - 1] ?? "") || near.test(text[m.index + word.length] ?? ""))
|
|
39
|
+
continue;
|
|
40
|
+
const range = document.createRange();
|
|
41
|
+
range.setStart(n, m.index);
|
|
42
|
+
range.setEnd(n, m.index + word.length);
|
|
43
|
+
const tops = Array.from(range.getClientRects())
|
|
44
|
+
.filter((r) => r.width > 0)
|
|
45
|
+
.map((r) => Math.round(r.top));
|
|
46
|
+
if (tops.length > 1 && Math.max(...tops) - Math.min(...tops) > 6)
|
|
47
|
+
found.push(word);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return found;
|
|
51
|
+
}
|
|
52
|
+
/** `findBrokenWords` as source text, for `page.evaluate`. */
|
|
53
|
+
export const BROKEN_WORDS_SOURCE = findBrokenWords.toString();
|
|
54
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAmB,QAAQ,EAC3B,UAAgC,EAAE;IAElC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IACtC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,cAAc,CAAC;IAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,gBAAgB,CACtC,IAAI,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAE,IAAa,EACrD,UAAU,CAAC,SAAS,CACrB,CAAC;IACF,KAAK,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;QACzD,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,kBAAkB,CAAC;QAC9B,KAAK,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAClB,IAAI,IAAI,CAAC,MAAM,GAAG,OAAO;gBAAE,SAAS;YACpC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;gBACpF,SAAS;YACX,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;YACrC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;YAC3B,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;iBAC5C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;iBAC1B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACjC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,6DAA6D;AAC7D,MAAM,CAAC,MAAM,mBAAmB,GAAW,eAAe,CAAC,QAAQ,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichBlock.d.ts","sourceRoot":"","sources":["../../src/react/RichBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,+
|
|
1
|
+
{"version":3,"file":"RichBlock.d.ts","sourceRoot":"","sources":["../../src/react/RichBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,GACR,EAAE;IACD,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC,+BA+KA"}
|
package/dist/react/RichBlock.js
CHANGED
|
@@ -19,7 +19,7 @@ export function RichAnswerBlock({ block, onReply, }) {
|
|
|
19
19
|
if (block.type === "diagram")
|
|
20
20
|
return (_jsxs("figure", { className: "ck-rich ck-diagram", children: [_jsx("figcaption", { className: "ck-rich-title", children: block.title }), _jsx("ol", { className: "ck-diagram-nodes", children: block.nodes.map((n, i) => (_jsxs("li", { children: [_jsx("span", { className: "ck-diagram-number", "aria-hidden": true, children: i + 1 }), _jsxs("div", { children: [_jsx("strong", { children: n.label }), n.detail && _jsx("p", { children: n.detail })] })] }, n.id))) }), block.edges.length > 0 && (_jsx("ul", { className: "ck-diagram-edges", children: block.edges.map((e, i) => (_jsxs("li", { children: [_jsx("span", { children: block.nodes.find((n) => n.id === e.from).label }), _jsx("span", { className: "ck-diagram-arrow", "aria-hidden": true, children: "\u2192" }), _jsx("span", { children: block.nodes.find((n) => n.id === e.to).label }), e.label && _jsx("small", { children: e.label })] }, i))) }))] }));
|
|
21
21
|
if (block.type === "stack")
|
|
22
|
-
return (_jsxs("figure", { className: "ck-rich ck-stack", children: [_jsx("figcaption", { className: "ck-rich-title", children: block.title }), _jsx("div", { className: "ck-stack-layers", children: block.layers.map((layer, i) => (_jsxs("div", { className: "ck-stack-layer", children: [_jsx("div", { className: "ck-stack-row", style: {
|
|
22
|
+
return (_jsxs("figure", { className: "ck-rich ck-stack", children: [_jsx("figcaption", { className: "ck-rich-title", children: block.title }), _jsx("div", { className: "ck-stack-layers", children: block.layers.map((layer, i) => (_jsxs("div", { className: "ck-stack-layer", children: [_jsx("div", { className: "ck-stack-row", "data-n": layer.nodes.length, style: { "--ck-n": layer.nodes.length }, children: layer.nodes.map((n, j) => (_jsxs("div", { className: n.tone === "accent" ? "ck-stack-node ck-stack-accent" : "ck-stack-node", children: [n.icon && _jsx(StackIconSvg, { name: n.icon }), n.kicker && _jsx("span", { className: "ck-stack-kicker", children: n.kicker }), _jsx("strong", { className: "ck-stack-label", children: n.label }), n.detail && _jsx("span", { className: "ck-stack-detail", children: n.detail })] }, j))) }), i < block.layers.length - 1 && (_jsxs("div", { className: "ck-stack-link", children: [_jsx("span", { className: "ck-stack-arrow", "aria-hidden": true, children: layer.both ? "⇅" : "↓" }), layer.link && _jsx("span", { children: layer.link })] }))] }, i))) }), block.caption && _jsx("p", { className: "ck-stack-caption", children: block.caption })] }));
|
|
23
23
|
if (block.type === "callout")
|
|
24
24
|
return (_jsxs("aside", { className: "ck-rich ck-callout", children: [_jsx("strong", { className: "ck-rich-title", children: block.title }), _jsx("p", { children: block.body })] }));
|
|
25
25
|
return (_jsx("form", { className: "ck-rich ck-choice", onSubmit: (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RichBlock.js","sourceRoot":"","sources":["../../src/react/RichBlock.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,KAAK,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"RichBlock.js","sourceRoot":"","sources":["../../src/react/RichBlock.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bitbaum/chatkit",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.2",
|
|
4
4
|
"description": "One chat for every product: a composer with a microphone that always works, a thread that does not fight the reader, messages with copy and retry, and LLM markdown \u2014 the fleet's chat standard as a package.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Cato",
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
"types": "./dist/react/index.d.ts",
|
|
52
52
|
"default": "./dist/react/index.js"
|
|
53
53
|
},
|
|
54
|
+
"./audit": {
|
|
55
|
+
"types": "./dist/audit.d.ts",
|
|
56
|
+
"default": "./dist/audit.js"
|
|
57
|
+
},
|
|
54
58
|
"./attach": {
|
|
55
59
|
"types": "./dist/react/attach.d.ts",
|
|
56
60
|
"default": "./dist/react/attach.js"
|
package/styles.css
CHANGED
|
@@ -931,20 +931,48 @@
|
|
|
931
931
|
margin-top: 0.375em;
|
|
932
932
|
}
|
|
933
933
|
|
|
934
|
-
/* A table that scrolls sideways on a phone instead of breaking the page
|
|
934
|
+
/* A table that scrolls sideways on a phone instead of breaking the page, and
|
|
935
|
+
never breaks a word to fit. `.ck-md` sets overflow-wrap: anywhere so a long
|
|
936
|
+
URL cannot push the thread wider, but `anywhere` also lowers a cell's
|
|
937
|
+
minimum width to ONE LETTER, so a three-column answer squeezed its first
|
|
938
|
+
column into "Di / re / ct / or / y" (Substrata at 390px, 2026-10-22).
|
|
939
|
+
Inside a table a word is the smallest thing a column can be: columns share
|
|
940
|
+
the width by wrapping at spaces, and when even the words do not fit the
|
|
941
|
+
wrapper scrolls, with a shadow on the edge that has more. */
|
|
935
942
|
.ck-table-wrap {
|
|
936
943
|
max-width: 100%;
|
|
937
944
|
overflow-x: auto;
|
|
938
945
|
-webkit-overflow-scrolling: touch;
|
|
946
|
+
background:
|
|
947
|
+
linear-gradient(to right, var(--ck-bg) 30%, transparent) left center / 1.5rem 100% no-repeat
|
|
948
|
+
local,
|
|
949
|
+
linear-gradient(to left, var(--ck-bg) 30%, transparent) right center / 1.5rem 100% no-repeat
|
|
950
|
+
local,
|
|
951
|
+
radial-gradient(
|
|
952
|
+
farthest-side at 0 50%,
|
|
953
|
+
color-mix(in srgb, var(--ck-fg) 14%, transparent),
|
|
954
|
+
transparent
|
|
955
|
+
)
|
|
956
|
+
left center / 0.625rem 100% no-repeat scroll,
|
|
957
|
+
radial-gradient(
|
|
958
|
+
farthest-side at 100% 50%,
|
|
959
|
+
color-mix(in srgb, var(--ck-fg) 14%, transparent),
|
|
960
|
+
transparent
|
|
961
|
+
)
|
|
962
|
+
right center / 0.625rem 100% no-repeat scroll;
|
|
939
963
|
}
|
|
940
964
|
.ck-table {
|
|
941
965
|
width: 100%;
|
|
942
966
|
border-collapse: collapse;
|
|
943
967
|
font-size: 0.9375em;
|
|
944
968
|
line-height: 1.45;
|
|
969
|
+
overflow-wrap: normal;
|
|
970
|
+
word-break: normal;
|
|
971
|
+
hyphens: manual;
|
|
945
972
|
}
|
|
946
973
|
.ck-table th,
|
|
947
974
|
.ck-table td {
|
|
975
|
+
min-width: 4.5rem;
|
|
948
976
|
padding: 0.5em 0.75em 0.5em 0;
|
|
949
977
|
border-bottom: 1px solid var(--ck-line);
|
|
950
978
|
text-align: left;
|
|
@@ -1615,22 +1643,30 @@ a.ck-source-row:hover .ck-source-title {
|
|
|
1615
1643
|
display: flex;
|
|
1616
1644
|
flex-direction: column;
|
|
1617
1645
|
}
|
|
1646
|
+
/* Tiles share a row, and a row wraps rather than cut a word: each tile asks
|
|
1647
|
+
for its share of the width (--ck-n tiles) but never less than its longest
|
|
1648
|
+
word, so on a narrow screen "3 across" becomes "2 and 1" or one under the
|
|
1649
|
+
other. The old grid forced N equal columns and cut "Manufacture" into
|
|
1650
|
+
pieces at 320px (2026-10-22). */
|
|
1618
1651
|
.ck-stack-row {
|
|
1619
|
-
display:
|
|
1652
|
+
display: flex;
|
|
1653
|
+
flex-wrap: wrap;
|
|
1620
1654
|
gap: 0.625rem;
|
|
1621
1655
|
}
|
|
1622
1656
|
.ck-stack-node {
|
|
1623
1657
|
display: flex;
|
|
1658
|
+
flex: 1 1 calc((100% - (var(--ck-n, 1) - 1) * 0.625rem) / var(--ck-n, 1));
|
|
1624
1659
|
flex-direction: column;
|
|
1625
1660
|
align-items: center;
|
|
1626
1661
|
gap: 0.25rem;
|
|
1627
|
-
min-width:
|
|
1662
|
+
min-width: min-content;
|
|
1628
1663
|
padding: 1rem 0.75rem;
|
|
1629
1664
|
border: 1px solid var(--ck-line);
|
|
1630
1665
|
border-radius: calc(var(--ck-radius) * 0.75);
|
|
1631
1666
|
background: var(--ck-raised);
|
|
1632
1667
|
text-align: center;
|
|
1633
|
-
overflow-wrap:
|
|
1668
|
+
overflow-wrap: normal;
|
|
1669
|
+
word-break: normal;
|
|
1634
1670
|
}
|
|
1635
1671
|
.ck-stack-accent {
|
|
1636
1672
|
border-color: color-mix(in srgb, var(--ck-accent) 35%, var(--ck-line));
|
|
@@ -1656,13 +1692,13 @@ a.ck-source-row:hover .ck-source-title {
|
|
|
1656
1692
|
}
|
|
1657
1693
|
/* Tiles in a row share the width: tighter padding and smaller words, so
|
|
1658
1694
|
"Manufacture, move, inspect" fits three across on a 390px phone. */
|
|
1659
|
-
.ck-stack-row:not([
|
|
1695
|
+
.ck-stack-row:not([data-n="1"]) .ck-stack-node {
|
|
1660
1696
|
padding: 0.875rem 0.5rem;
|
|
1661
1697
|
}
|
|
1662
|
-
.ck-stack-row:not([
|
|
1698
|
+
.ck-stack-row:not([data-n="1"]) .ck-stack-label {
|
|
1663
1699
|
font-size: 1em;
|
|
1664
1700
|
}
|
|
1665
|
-
.ck-stack-row:not([
|
|
1701
|
+
.ck-stack-row:not([data-n="1"]) .ck-stack-detail {
|
|
1666
1702
|
font-size: 0.8125em;
|
|
1667
1703
|
}
|
|
1668
1704
|
.ck-stack-detail {
|
|
@@ -1761,6 +1797,7 @@ a.ck-source-row:hover .ck-source-title {
|
|
|
1761
1797
|
list-style: none;
|
|
1762
1798
|
}
|
|
1763
1799
|
details.ck-thinking > summary {
|
|
1800
|
+
min-height: var(--ck-target);
|
|
1764
1801
|
cursor: pointer;
|
|
1765
1802
|
}
|
|
1766
1803
|
details.ck-thinking > summary::-webkit-details-marker {
|