anentrypoint-design 0.0.477 → 0.0.480
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 +101 -0
- package/chat.css +4 -4
- package/colors_and_type.css +33 -3
- package/community.css +22 -8
- package/dist/247420.css +324 -49
- package/dist/247420.js +123 -55
- package/dist/index.html +109 -32
- package/package.json +1 -1
- package/src/community-app.js +4 -2
- package/src/components/community/navigation.js +2 -2
- package/src/components/community/presence.js +10 -4
- package/src/components/community/views.js +8 -2
- package/src/components/content/avatar.js +30 -0
- package/src/components/content/hero.js +9 -2
- package/src/components/content.js +2 -2
- package/src/components/freddie/pages-missing.js +1 -1
- package/src/components/overlay-primitives/emoji-picker.js +15 -3
- package/src/components/shell/app-shell.js +15 -4
- package/src/components/shell/workspace-shell.js +1 -1
- package/src/components/theme-toggle.js +8 -3
- package/src/copy-code.js +103 -0
- package/src/css/app-shell/base.css +18 -0
- package/src/css/app-shell/catalog-theme.css +20 -2
- package/src/css/app-shell/chat-polish.css +12 -0
- package/src/css/app-shell/collab.css +5 -0
- package/src/css/app-shell/data-density.css +4 -0
- package/src/css/app-shell/files.css +7 -1
- package/src/css/app-shell/hero-content.css +14 -1
- package/src/css/app-shell/kits-appended.css +13 -0
- package/src/css/app-shell/loading-alerts.css +14 -12
- package/src/css/app-shell/otp-input.css +2 -2
- package/src/css/app-shell/panel-row.css +15 -0
- package/src/css/app-shell/plugins-config.css +3 -0
- package/src/css/app-shell/primitives.css +13 -4
- package/src/css/app-shell/responsive.css +13 -0
- package/src/css/app-shell/responsive2-workspace.css +4 -1
- package/src/css/app-shell/row-print.css +34 -0
- package/src/css/app-shell/states-interactions.css +62 -4
- package/src/css/app-shell/topbar.css +1 -0
- package/src/kits/os/app-panes.css +3 -2
- package/src/kits/os/icons.js +16 -0
- package/src/kits/os/shell-geometry.js +2 -2
- package/src/kits/os/shell.js +24 -3
- package/src/kits/os/theme.css +272 -78
- package/src/kits/os/wm.css +19 -6
- package/src/kits/os/wm.js +38 -1
- package/src/kits/spoint/host-join-lobby.css +3 -3
- package/src/page-html/client-script.js +96 -28
- package/src/page-html.js +3 -2
- package/src/theme.js +6 -2
- package/src/web-components/ds-chat.js +9 -0
- package/src/web-components/freddie-chat.js +2 -2
- package/types/components.d.ts +6 -0
|
@@ -67,11 +67,16 @@ export function ThemeToggle({ compact = false, onChange } = {}) {
|
|
|
67
67
|
el.setAttribute('title', titleFor(now));
|
|
68
68
|
const lab = el.querySelector('.ds-theme-toggle-label');
|
|
69
69
|
if (lab) lab.textContent = labelFor(now);
|
|
70
|
+
const disc = el.querySelector('.ds-theme-disc');
|
|
71
|
+
if (disc) disc.setAttribute('data-mode', now);
|
|
70
72
|
})
|
|
71
73
|
},
|
|
72
|
-
// CSS-drawn
|
|
73
|
-
//
|
|
74
|
-
|
|
74
|
+
// CSS-drawn disc so the control still reads as the theme switch when
|
|
75
|
+
// the label is hidden (icon-only rail strip). data-mode selects a
|
|
76
|
+
// per-mode fill (solid light / solid dark / half-and-half for auto)
|
|
77
|
+
// so the icon itself — not just the title tooltip — shows current
|
|
78
|
+
// state at a glance.
|
|
79
|
+
h('span', { class: 'ds-theme-disc', 'data-mode': current, 'aria-hidden': 'true' }),
|
|
75
80
|
h('span', { class: 'ds-theme-toggle-label' }, labelFor(current)));
|
|
76
81
|
}
|
|
77
82
|
|
package/src/copy-code.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// copy-code.js -- vanilla-JS "copy" button injector for <pre><code> blocks.
|
|
2
|
+
//
|
|
3
|
+
// Standalone module, no dependencies, no framework assumptions: include it
|
|
4
|
+
// with a plain <script src="…/copy-code.js"></script> (or type="module") on
|
|
5
|
+
// any page rendering doc/code blocks and it wires itself up on
|
|
6
|
+
// DOMContentLoaded, finding every `pre > code` element and injecting a small
|
|
7
|
+
// button that copies the block's text to the clipboard.
|
|
8
|
+
//
|
|
9
|
+
// Self-invoking so a page can include it more than once without double-
|
|
10
|
+
// registering handlers or double-injecting buttons (guarded per-element via
|
|
11
|
+
// a data attribute).
|
|
12
|
+
(function () {
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const COPY_LABEL = 'copy';
|
|
16
|
+
const COPIED_LABEL = 'copied';
|
|
17
|
+
const FAILED_LABEL = 'copy failed';
|
|
18
|
+
const RESET_MS = 1500;
|
|
19
|
+
const MARK_ATTR = 'data-copy-code-wired';
|
|
20
|
+
|
|
21
|
+
function copyText(text) {
|
|
22
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
23
|
+
return navigator.clipboard.writeText(text);
|
|
24
|
+
}
|
|
25
|
+
// Fallback for non-secure contexts / browsers without navigator.clipboard.
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
try {
|
|
28
|
+
const ta = document.createElement('textarea');
|
|
29
|
+
ta.value = text;
|
|
30
|
+
ta.style.position = 'fixed';
|
|
31
|
+
ta.style.opacity = '0';
|
|
32
|
+
document.body.appendChild(ta);
|
|
33
|
+
ta.focus();
|
|
34
|
+
ta.select();
|
|
35
|
+
const ok = document.execCommand('copy');
|
|
36
|
+
document.body.removeChild(ta);
|
|
37
|
+
ok ? resolve() : reject(new Error('execCommand copy failed'));
|
|
38
|
+
} catch (err) {
|
|
39
|
+
reject(err);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function makeButton(codeEl) {
|
|
45
|
+
const btn = document.createElement('button');
|
|
46
|
+
btn.type = 'button';
|
|
47
|
+
btn.className = 'copy-code-btn';
|
|
48
|
+
btn.textContent = COPY_LABEL;
|
|
49
|
+
btn.setAttribute('aria-label', 'copy code to clipboard');
|
|
50
|
+
|
|
51
|
+
let resetTimer = null;
|
|
52
|
+
btn.addEventListener('click', () => {
|
|
53
|
+
copyText(codeEl.textContent || '').then(
|
|
54
|
+
() => setLabel(true),
|
|
55
|
+
() => setLabel(false)
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
function setLabel(ok) {
|
|
60
|
+
btn.textContent = ok ? COPIED_LABEL : FAILED_LABEL;
|
|
61
|
+
clearTimeout(resetTimer);
|
|
62
|
+
resetTimer = setTimeout(() => { btn.textContent = COPY_LABEL; }, RESET_MS);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return btn;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function wireBlock(codeEl) {
|
|
69
|
+
const pre = codeEl.parentElement;
|
|
70
|
+
if (!pre || pre.tagName !== 'PRE') return;
|
|
71
|
+
if (pre.hasAttribute(MARK_ATTR)) return;
|
|
72
|
+
pre.setAttribute(MARK_ATTR, '1');
|
|
73
|
+
// Position context for an absolutely-positioned button; harmless no-op
|
|
74
|
+
// if the page's own CSS already sets a position on <pre>.
|
|
75
|
+
if (!pre.style.position) pre.style.position = 'relative';
|
|
76
|
+
pre.appendChild(makeButton(codeEl));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function wireAll(root) {
|
|
80
|
+
(root || document).querySelectorAll('pre > code').forEach(wireBlock);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (document.readyState === 'loading') {
|
|
84
|
+
document.addEventListener('DOMContentLoaded', () => wireAll(document));
|
|
85
|
+
} else {
|
|
86
|
+
wireAll(document);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Minimal default styling, injected once, so the button is usable even on
|
|
90
|
+
// pages with no bespoke .copy-code-btn rule of their own. A page that wants
|
|
91
|
+
// its own look can simply define .copy-code-btn in its own stylesheet --
|
|
92
|
+
// this only runs if that class isn't already styled to be visible.
|
|
93
|
+
if (!document.getElementById('copy-code-btn-style')) {
|
|
94
|
+
const style = document.createElement('style');
|
|
95
|
+
style.id = 'copy-code-btn-style';
|
|
96
|
+
style.textContent =
|
|
97
|
+
'.copy-code-btn{position:absolute;top:.5em;right:.5em;font:inherit;' +
|
|
98
|
+
'font-size:.75em;line-height:1;padding:.35em .6em;border:1px solid currentColor;' +
|
|
99
|
+
'border-radius:4px;background:transparent;color:inherit;cursor:pointer;opacity:.6}' +
|
|
100
|
+
'.copy-code-btn:hover{opacity:1}';
|
|
101
|
+
document.head.appendChild(style);
|
|
102
|
+
}
|
|
103
|
+
})();
|
|
@@ -75,6 +75,24 @@ body {
|
|
|
75
75
|
scrollbar-width: thin;
|
|
76
76
|
scrollbar-color: var(--bg-3) transparent;
|
|
77
77
|
}
|
|
78
|
+
/* Firefox gets themed scrollbars via scrollbar-width/-color above; Chrome,
|
|
79
|
+
Safari, and Edge need the ::-webkit-scrollbar family too, or every
|
|
80
|
+
scrollable node in the app shell falls back to the raw OS scrollbar and
|
|
81
|
+
clashes with the dark UI. Same selector scope, same --bg-3 token. */
|
|
82
|
+
.app::-webkit-scrollbar, .ds-stage::-webkit-scrollbar,
|
|
83
|
+
.app *::-webkit-scrollbar, .ds-stage *::-webkit-scrollbar {
|
|
84
|
+
width: 8px;
|
|
85
|
+
height: 8px;
|
|
86
|
+
}
|
|
87
|
+
.app::-webkit-scrollbar-track, .ds-stage::-webkit-scrollbar-track,
|
|
88
|
+
.app *::-webkit-scrollbar-track, .ds-stage *::-webkit-scrollbar-track {
|
|
89
|
+
background: transparent;
|
|
90
|
+
}
|
|
91
|
+
.app::-webkit-scrollbar-thumb, .ds-stage::-webkit-scrollbar-thumb,
|
|
92
|
+
.app *::-webkit-scrollbar-thumb, .ds-stage *::-webkit-scrollbar-thumb {
|
|
93
|
+
background: var(--bg-3);
|
|
94
|
+
border-radius: var(--r-pill, 999px);
|
|
95
|
+
}
|
|
78
96
|
|
|
79
97
|
h1, .t-h1 { font-family: var(--ff-display); font-size: var(--fs-h1); line-height: var(--lh-snug); letter-spacing: var(--tr-tight); font-weight: 600; margin: 0; }
|
|
80
98
|
h2, .t-h2 { font-family: var(--ff-display); font-size: var(--fs-h2); line-height: var(--lh-snug); letter-spacing: var(--tr-tight); font-weight: 600; margin: 0; }
|
|
@@ -41,6 +41,12 @@
|
|
|
41
41
|
.ds-demo-label { font-size: var(--fs-xs); font-weight: 500; margin: 0 0 var(--space-1); }
|
|
42
42
|
.ds-demo-desc { font-size: var(--fs-tiny); color: var(--fg-3); margin: 0 0 var(--space-2); }
|
|
43
43
|
|
|
44
|
+
/* Per-preview backlink to the full token map/doc — names which token
|
|
45
|
+
families the specimen above it demonstrates, then links out to the
|
|
46
|
+
generated theme-map for the resolved values. */
|
|
47
|
+
.tokens-backlink { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); margin-top: 2px; }
|
|
48
|
+
.tokens-backlink a { color: inherit; }
|
|
49
|
+
|
|
44
50
|
@media (max-width: 768px) {
|
|
45
51
|
.ds-catalog { flex-direction: column; }
|
|
46
52
|
.ds-catalog-side { width: 100%; height: auto; position: static; border-right: 0; border-bottom: var(--bw-hair) solid var(--rule); }
|
|
@@ -137,11 +143,23 @@
|
|
|
137
143
|
font-family: var(--ff-mono); font-size: var(--fs-xs);
|
|
138
144
|
display: inline-flex; align-items: center; gap: 6px;
|
|
139
145
|
}
|
|
140
|
-
/* CSS-drawn
|
|
141
|
-
legible when its text label is hidden (icon-only rail strip).
|
|
146
|
+
/* CSS-drawn disc mark on the compact theme toggle: keeps the control
|
|
147
|
+
legible when its text label is hidden (icon-only rail strip). Per-mode
|
|
148
|
+
fill gives the icon itself a distinct look for auto/light/dark, so state
|
|
149
|
+
reads without relying on the title tooltip alone. */
|
|
142
150
|
.ds-theme-disc {
|
|
143
151
|
flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%;
|
|
144
152
|
border: var(--bw-hair) solid var(--fg-3);
|
|
153
|
+
/* auto: half-and-half, matches default (no data-mode) for safety */
|
|
154
|
+
background: linear-gradient(90deg, var(--fg-3) 0 50%, transparent 50% 100%);
|
|
155
|
+
}
|
|
156
|
+
.ds-theme-disc[data-mode="auto"] {
|
|
145
157
|
background: linear-gradient(90deg, var(--fg-3) 0 50%, transparent 50% 100%);
|
|
146
158
|
}
|
|
159
|
+
.ds-theme-disc[data-mode="paper"] {
|
|
160
|
+
background: var(--bg); border-color: var(--fg-3);
|
|
161
|
+
}
|
|
162
|
+
.ds-theme-disc[data-mode="ink"] {
|
|
163
|
+
background: var(--fg-3); border-color: var(--fg-3);
|
|
164
|
+
}
|
|
147
165
|
|
|
@@ -69,6 +69,18 @@
|
|
|
69
69
|
background: color-mix(in oklab, var(--mascot) 26%, var(--bg-2));
|
|
70
70
|
color: var(--mascot-deep);
|
|
71
71
|
}
|
|
72
|
+
/* Plain assistant turns ('them', no aicat persona) previously fell through to
|
|
73
|
+
the bare .chat-avatar gray disc with no role identity at all — 'you' and
|
|
74
|
+
'aicat' both got a tinted background + ring, the default assistant got
|
|
75
|
+
nothing. Give it the same tinted-background treatment via --color-success
|
|
76
|
+
(the conventional assistant/bot association, distinct from the accent hue
|
|
77
|
+
'you' owns and the mascot hue 'aicat' owns) plus a thin identity ring so
|
|
78
|
+
role is readable from the avatar alone, not just bubble position/color. */
|
|
79
|
+
.chat-msg.them:not(.aicat) .chat-avatar {
|
|
80
|
+
background: color-mix(in oklab, var(--color-success) 20%, var(--bg-3));
|
|
81
|
+
color: color-mix(in oklab, var(--color-success) 65%, var(--fg));
|
|
82
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-success) 35%, transparent);
|
|
83
|
+
}
|
|
72
84
|
|
|
73
85
|
.chat-stack {
|
|
74
86
|
display: flex; flex-direction: column; gap: var(--space-1);
|
|
@@ -79,6 +79,11 @@
|
|
|
79
79
|
border-radius: var(--r-pill);
|
|
80
80
|
background: var(--bg-2);
|
|
81
81
|
}
|
|
82
|
+
/* .ds-collab-chip-avatar (24px identity circle) and .ds-collab-chip-status
|
|
83
|
+
(8px status dot) below are both circular via border-radius: 50% but are
|
|
84
|
+
intentionally distinct: different sizes, different content (initial vs.
|
|
85
|
+
plain fill), different positioning role (layout box vs. absolute badge).
|
|
86
|
+
Not extracting a shared class -- there's nothing substantive to share. */
|
|
82
87
|
.ds-collab-chip-avatar {
|
|
83
88
|
position: relative;
|
|
84
89
|
width: 24px;
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
|
|
15
15
|
/* PhaseWalk */
|
|
16
16
|
.ds-phasewalk { display: inline-flex; gap: var(--space-hair); vertical-align: middle; }
|
|
17
|
+
/* NOTE: a second toggle-switch-shaped implementation exists in
|
|
18
|
+
plugins-config.css:91 (.ds-plugins-toggle) at a different scale (40x22 vs
|
|
19
|
+
this 18x10) — consider consolidating into a shared .ds-switch primitive
|
|
20
|
+
with a size modifier. */
|
|
17
21
|
.ds-phasewalk-seg {
|
|
18
22
|
width: 18px; height: 10px; border-radius: var(--r-hair);
|
|
19
23
|
background: var(--bg-3); position: relative;
|
|
@@ -263,6 +263,12 @@
|
|
|
263
263
|
display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
|
|
264
264
|
gap: var(--space-3); align-items: start;
|
|
265
265
|
}
|
|
266
|
+
/* Mobile fallback: auto-fill can still pack 2 cramped columns down to ~320px
|
|
267
|
+
viewports; force a single column below the shared mobile breakpoint
|
|
268
|
+
(docs/responsive.md) so thumbnails and file rails always read as a list. */
|
|
269
|
+
@media (max-width: 480px) {
|
|
270
|
+
.ds-file-grid-thumb { grid-template-columns: 1fr; }
|
|
271
|
+
}
|
|
266
272
|
.ds-file-cell {
|
|
267
273
|
position: relative;
|
|
268
274
|
background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
@@ -729,7 +735,7 @@
|
|
|
729
735
|
.ds-preview-code::-webkit-scrollbar,
|
|
730
736
|
.ds-preview-text::-webkit-scrollbar,
|
|
731
737
|
.ds-preview-body::-webkit-scrollbar,
|
|
732
|
-
.ds-modal-body::-webkit-scrollbar { width:
|
|
738
|
+
.ds-modal-body::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
733
739
|
.ds-preview-code::-webkit-scrollbar-thumb,
|
|
734
740
|
.ds-preview-text::-webkit-scrollbar-thumb {
|
|
735
741
|
background: color-mix(in oklab, var(--paper) 28%, transparent);
|
|
@@ -88,6 +88,18 @@
|
|
|
88
88
|
display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
|
|
89
89
|
justify-content: flex-start; margin-top: var(--space-hair, 4px);
|
|
90
90
|
}
|
|
91
|
+
/* Hero CTA labels are content-driven (e.g. "GitHub", proper nouns from
|
|
92
|
+
home.yaml) and the site's voice is deliberately all-lowercase everywhere
|
|
93
|
+
else. Force the rendered case here rather than hand-lowercasing every
|
|
94
|
+
proper-noun label at the content layer, so a future CTA label doesn't
|
|
95
|
+
silently reintroduce Title Case. */
|
|
96
|
+
.ds-hero-actions .btn { text-transform: lowercase; }
|
|
97
|
+
/* Filter input above the homepage's "ui kits" panel — reuses the same
|
|
98
|
+
.input token the search kit's own topbar query box uses, just placed
|
|
99
|
+
inline above the panel instead of in a topbar slot. */
|
|
100
|
+
.ds-kits-panel-wrap { display: flex; flex-direction: column; gap: var(--space-2, 10px); }
|
|
101
|
+
.ds-kits-filter { display: flex; }
|
|
102
|
+
.ds-kits-filter-input { width: 100%; max-width: 32ch; }
|
|
91
103
|
/* Below this width the aside card's own internal rhythm (stat rows still
|
|
92
104
|
stacked vertically at full width) is already correct for a narrow column —
|
|
93
105
|
no separate breakpoint override needed now that .ds-hero is always a
|
|
@@ -167,6 +179,7 @@
|
|
|
167
179
|
white-space: nowrap; will-change: transform;
|
|
168
180
|
animation: ds-marquee-run 28s linear infinite;
|
|
169
181
|
}
|
|
182
|
+
.ds-marquee-run { display: inline-flex; align-items: center; gap: var(--space-5); }
|
|
170
183
|
.ds-marquee-item { display: inline-flex; align-items: center; gap: var(--space-5); }
|
|
171
184
|
.ds-marquee-sep { color: var(--accent-ink); }
|
|
172
185
|
.ds-marquee:hover .ds-marquee-track,
|
|
@@ -487,7 +500,7 @@ table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
|
487
500
|
Form
|
|
488
501
|
============================================================ */
|
|
489
502
|
.row-form {
|
|
490
|
-
display: grid; gap:
|
|
503
|
+
display: grid; gap: var(--space-2-75);
|
|
491
504
|
padding: var(--space-5);
|
|
492
505
|
background: var(--bg-2);
|
|
493
506
|
border-radius: var(--r-3);
|
|
@@ -451,6 +451,11 @@
|
|
|
451
451
|
.ds-btn-row-tight { gap: var(--space-1-75, 6px); }
|
|
452
452
|
.ds-key-input { flex: 1 1 160px; min-width: 0; font-family: var(--ff-mono); }
|
|
453
453
|
.ds-toggle-btn { min-width: 78px; }
|
|
454
|
+
/* Side-by-side checked/unchecked reference pair (settings kit theme panel) --
|
|
455
|
+
documents the visual difference between states in one static, non-live
|
|
456
|
+
spot rather than requiring a viewer to toggle a real control back and
|
|
457
|
+
forth to compare. */
|
|
458
|
+
.ds-toggle-state-sample { display: flex; align-items: center; gap: var(--space-1-5, 6px); }
|
|
454
459
|
.ds-toggle-label { margin-left: var(--space-2, 8px); color: inherit; opacity: 0.7; }
|
|
455
460
|
.ds-btn-warn { color: var(--warn); }
|
|
456
461
|
/* Raw --mascot text measures 3.11:1 on paper (fails 4.5:1); --mascot-deep is
|
|
@@ -593,6 +598,14 @@
|
|
|
593
598
|
display: flex; flex-direction: column; gap: 0;
|
|
594
599
|
background: var(--ink); border-radius: var(--r-1);
|
|
595
600
|
font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.65;
|
|
601
|
+
/* Responsive strategy for long logs: cap the scrollback height and scroll
|
|
602
|
+
vertically rather than growing the page indefinitely; long command/output
|
|
603
|
+
lines wrap (see .cli .cmd's overflow-wrap: anywhere below) instead of
|
|
604
|
+
scrolling horizontally, so wrapping is the chosen default over
|
|
605
|
+
horizontal scroll for this kit. */
|
|
606
|
+
max-height: 60vh;
|
|
607
|
+
overflow-y: auto;
|
|
608
|
+
overflow-wrap: anywhere;
|
|
596
609
|
}
|
|
597
610
|
/* .cli is authored in hero-content.css as a STANDALONE hero code block --
|
|
598
611
|
20px/24px padding, --fs-lg type, --r-3 radius and its own --ink background
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
/* ============================================================
|
|
3
3
|
Spinner — animated loading indicator
|
|
4
4
|
============================================================ */
|
|
5
|
+
/* Dots spinner — use for small inline/compact loading states. */
|
|
5
6
|
.ds-spinner {
|
|
6
7
|
display: inline-flex;
|
|
7
|
-
gap:
|
|
8
|
+
gap: var(--space-1);
|
|
8
9
|
align-items: center;
|
|
9
10
|
height: 16px;
|
|
10
11
|
}
|
|
11
12
|
.ds-spinner span {
|
|
12
|
-
width:
|
|
13
|
-
height:
|
|
13
|
+
width: var(--space-1);
|
|
14
|
+
height: var(--space-1);
|
|
14
15
|
border-radius: 50%;
|
|
15
16
|
background: var(--accent);
|
|
16
17
|
}
|
|
@@ -21,17 +22,17 @@
|
|
|
21
22
|
.ds-spinner span:nth-child(3) { animation-delay: 0.36s; }
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
.ds-spinner-lg { height: 24px; gap:
|
|
25
|
-
.ds-spinner-lg span { width:
|
|
25
|
+
.ds-spinner-lg { height: 24px; gap: var(--space-1-75); }
|
|
26
|
+
.ds-spinner-lg span { width: var(--space-1-75); height: var(--space-1-75); }
|
|
26
27
|
|
|
27
|
-
.ds-spinner-sm { height: 12px; gap:
|
|
28
|
-
.ds-spinner-sm span { width:
|
|
28
|
+
.ds-spinner-sm { height: 12px; gap: var(--space-hair); }
|
|
29
|
+
.ds-spinner-sm span { width: var(--space-hair); height: var(--space-hair); }
|
|
29
30
|
|
|
30
31
|
.ds-spinner-xs { height: 8px; gap: 1px; }
|
|
31
32
|
.ds-spinner-xs span { width: 1.5px; height: 1.5px; }
|
|
32
33
|
|
|
33
|
-
.ds-spinner-xl { height: 32px; gap:
|
|
34
|
-
.ds-spinner-xl span { width:
|
|
34
|
+
.ds-spinner-xl { height: 32px; gap: var(--space-2); }
|
|
35
|
+
.ds-spinner-xl span { width: var(--space-2); height: var(--space-2); }
|
|
35
36
|
|
|
36
37
|
@keyframes ds-bounce {
|
|
37
38
|
0%, 80%, 100% { transform: translateY(0); }
|
|
@@ -81,7 +82,7 @@
|
|
|
81
82
|
flex-shrink: 0;
|
|
82
83
|
color: var(--alert-tone);
|
|
83
84
|
font-weight: 600;
|
|
84
|
-
min-width:
|
|
85
|
+
min-width: var(--space-3-5);
|
|
85
86
|
text-align: center;
|
|
86
87
|
}
|
|
87
88
|
|
|
@@ -110,11 +111,12 @@
|
|
|
110
111
|
cursor: pointer;
|
|
111
112
|
color: var(--fg-3);
|
|
112
113
|
padding: 0;
|
|
113
|
-
font-size:
|
|
114
|
+
font-size: var(--fs-xs);
|
|
114
115
|
line-height: 1;
|
|
115
|
-
min-width:
|
|
116
|
+
min-width: var(--space-3-5);
|
|
116
117
|
text-align: center;
|
|
117
118
|
transition: color var(--dur-snap) var(--ease);
|
|
118
119
|
}
|
|
119
120
|
.ds-alert-dismiss:hover { color: var(--fg); }
|
|
121
|
+
.ds-alert-dismiss:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
120
122
|
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
.ds-otp-box:focus-visible {
|
|
18
18
|
outline: none;
|
|
19
19
|
border-color: var(--accent);
|
|
20
|
-
box-shadow:
|
|
20
|
+
box-shadow: var(--focus-ring-inset);
|
|
21
21
|
}
|
|
22
22
|
.ds-otp-box-filled { border-color: var(--rule-strong); background: var(--bg-3); }
|
|
23
23
|
.ds-otp-box-error { border-color: var(--red); }
|
|
24
|
-
.ds-otp-box-error:focus-visible { box-shadow:
|
|
24
|
+
.ds-otp-box-error:focus-visible { box-shadow: var(--focus-ring-inset); }
|
|
25
25
|
.ds-otp-box:disabled { opacity: 0.5; cursor: default; }
|
|
26
26
|
|
|
27
27
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -73,6 +73,13 @@
|
|
|
73
73
|
margin: 0; font: inherit; font-size: inherit; font-weight: inherit;
|
|
74
74
|
letter-spacing: inherit; text-transform: inherit; color: inherit;
|
|
75
75
|
}
|
|
76
|
+
/* Category glyph beside a panel title (kits / previews / decks / docs on the
|
|
77
|
+
homepage) — same inline-svg vocabulary as icons.js, sized to sit on the
|
|
78
|
+
text baseline rather than dominating it. */
|
|
79
|
+
.ds-panel-title-glyph {
|
|
80
|
+
display: inline-flex; align-items: center; gap: var(--space-1-5, 6px);
|
|
81
|
+
}
|
|
82
|
+
.ds-panel-title-glyph .ds-icon { flex-shrink: 0; color: var(--fg-3); }
|
|
76
83
|
.panel-body { padding: var(--space-2) var(--space-3) var(--space-3); }
|
|
77
84
|
.panel-body > * { margin: 0; }
|
|
78
85
|
/* One-line explanatory caption under a panel's title — e.g. distinguishing
|
|
@@ -113,6 +120,14 @@
|
|
|
113
120
|
transition: background var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring);
|
|
114
121
|
}
|
|
115
122
|
.row + .row { margin-top: 2px; }
|
|
123
|
+
/* Mobile tap-target floor: at compact/comfortable density on a touch
|
|
124
|
+
viewport the padding-only row height can fall under the 44px effective
|
|
125
|
+
tap target (WCAG 2.5.5), especially at [data-density="compact"] (0.75x).
|
|
126
|
+
Force a min-height on narrow/coarse-pointer viewports only, so the dense
|
|
127
|
+
desktop mono/list layout (file-row, index-row) is untouched above 640px. */
|
|
128
|
+
@media (max-width: 640px), (pointer: coarse) {
|
|
129
|
+
.row, a.row, button.row, .row[role="button"] { min-height: 44px; }
|
|
130
|
+
}
|
|
116
131
|
/* Interactive rows (anchor/button wrappers) get a hairline lift on hover,
|
|
117
132
|
matching the btn/panel elevation language — non-interactive rows (plain
|
|
118
133
|
divs used as static list items) are unaffected since the selector needs a
|
|
@@ -87,6 +87,9 @@
|
|
|
87
87
|
}
|
|
88
88
|
.ds-plugins-version { font-size: var(--fs-micro); color: var(--fg-3); }
|
|
89
89
|
|
|
90
|
+
/* NOTE: a second toggle-switch implementation exists in data-density.css:18
|
|
91
|
+
(.ds-phasewalk-seg) at a different scale (18x10 vs this 40x22) — consider
|
|
92
|
+
consolidating into a shared .ds-switch primitive with a size modifier. */
|
|
90
93
|
.ds-plugins-toggle {
|
|
91
94
|
flex: 0 0 auto; width: 40px; height: 22px; border-radius: 11px; border: none; padding: 0;
|
|
92
95
|
background: var(--rule); position: relative; cursor: pointer;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
}
|
|
23
23
|
.btn-primary:hover { background: var(--fg); color: var(--green); transform: translateY(-1px); box-shadow: var(--shadow-2); }
|
|
24
24
|
.btn-ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 2px var(--fg); }
|
|
25
|
-
.btn-ghost:hover { background: var(--fg)
|
|
25
|
+
.btn-ghost:hover { background: color-mix(in oklab, var(--fg) 12%, transparent); transform: translateY(-1px); }
|
|
26
26
|
.btn:active, .btn-primary:active, .btn-ghost:active { transform: translateY(1px); box-shadow: none; }
|
|
27
27
|
.btn:focus-visible, .btn-primary:focus-visible, .btn-ghost:focus-visible, .ds-icon-btn:focus-visible {
|
|
28
28
|
outline: var(--focus-w) solid var(--focus-color);
|
|
@@ -54,7 +54,9 @@
|
|
|
54
54
|
border-radius: var(--r-1, 6px);
|
|
55
55
|
background: transparent; color: var(--fg);
|
|
56
56
|
width: 32px; height: 32px;
|
|
57
|
+
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
57
58
|
}
|
|
59
|
+
.ds-icon-btn:hover { background: var(--bg-2); }
|
|
58
60
|
.ds-icon-btn-xs { width: 22px; height: 22px; }
|
|
59
61
|
.ds-icon-btn-sm { width: 26px; height: 26px; }
|
|
60
62
|
.ds-icon-btn-base { width: 32px; height: 32px; }
|
|
@@ -64,7 +66,10 @@
|
|
|
64
66
|
.ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
|
|
65
67
|
.ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
|
|
66
68
|
.ds-icon-btn-primary:hover { background: var(--fg); color: var(--accent-ink); }
|
|
67
|
-
|
|
69
|
+
/* --ink, not --on-color: --on-color is a fixed #fff, which measures 3.07:1 on
|
|
70
|
+
--warn (#FF5A52) -- below the 4.5:1 AA floor. --ink measures 6.27:1. Same
|
|
71
|
+
fix as .btn-primary.danger in app-shell/files.css. */
|
|
72
|
+
.ds-icon-btn-danger { background: var(--warn); color: var(--ink); }
|
|
68
73
|
.ds-icon-btn-danger:hover { filter: brightness(0.92); }
|
|
69
74
|
.ds-icon-btn:active { transform: translateY(1px); }
|
|
70
75
|
.ds-icon-btn:disabled, .ds-icon-btn.is-disabled {
|
|
@@ -78,7 +83,7 @@
|
|
|
78
83
|
border-radius: var(--r-pill);
|
|
79
84
|
background: var(--bg-3); color: var(--fg-2);
|
|
80
85
|
}
|
|
81
|
-
.ds-badge.ds-badge--sm { min-width: 14px; height: 14px; padding: 0 var(--space-1); font-size:
|
|
86
|
+
.ds-badge.ds-badge--sm { min-width: 14px; height: 14px; padding: 0 var(--space-1); font-size: var(--fs-pico); }
|
|
82
87
|
.ds-badge.ds-badge--lg { min-width: 22px; height: 22px; padding: 0 var(--space-2); font-size: var(--fs-tiny); }
|
|
83
88
|
.ds-badge.tone-green, .ds-badge.tone-live, .ds-badge.tone-success {
|
|
84
89
|
background: var(--green-tint); color: var(--green-deep);
|
|
@@ -95,7 +100,7 @@
|
|
|
95
100
|
background: var(--sun); color: var(--ink);
|
|
96
101
|
}
|
|
97
102
|
.ds-badge.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
|
|
98
|
-
.ds-badge.tone-orange { background: color-mix(in oklab, var(--flame)
|
|
103
|
+
.ds-badge.tone-orange { background: color-mix(in oklab, var(--flame) 22%, var(--bg)); color: color-mix(in oklab, var(--flame) 65%, black); }
|
|
99
104
|
|
|
100
105
|
.chip {
|
|
101
106
|
display: inline-flex; align-items: center; gap: var(--space-1-75);
|
|
@@ -163,6 +168,10 @@
|
|
|
163
168
|
.ds-pill.tone-accent { background: var(--accent-tint); color: var(--accent-ink); }
|
|
164
169
|
.ds-pill.tone-muted { background: transparent; color: var(--fg-3); box-shadow: inset 0 0 0 1px var(--rule); }
|
|
165
170
|
|
|
171
|
+
/* .glyph-* sizes (14/18/22px) are for small inline text-adjacent glyphs
|
|
172
|
+
(single characters/icons sitting in a text flow), a different scale and
|
|
173
|
+
purpose than the .ds-icon-btn-* tap-target scale (22/26/32/40/48px) below --
|
|
174
|
+
the -sm/-lg naming overlap is coincidental, not a shared system. */
|
|
166
175
|
.glyph {
|
|
167
176
|
display: inline-flex; align-items: center; justify-content: center;
|
|
168
177
|
width: 18px; height: 18px;
|
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
Responsive Design — Mobile (480px), Tablet (1024px), Desktop (1440px+)
|
|
4
4
|
============================================================ */
|
|
5
5
|
|
|
6
|
+
/* Breakpoint reference (CSS custom properties can't be used in @media queries,
|
|
7
|
+
so these are documented here for consistency — always use these exact values):
|
|
8
|
+
- Mobile/tablet boundary: 768px (max-width) — used for compact nav/sidebar
|
|
9
|
+
collapse (catalog-theme.css, sidebar-misc.css). Note: kits-appended.css
|
|
10
|
+
uses 760px for the same kind of collapse in a few places — a near-miss
|
|
11
|
+
of this value, worth aligning to 768px when touched.
|
|
12
|
+
- Tablet/desktop boundary: 900px (max-width) / 901px (min-width) — used for
|
|
13
|
+
main layout reflow (hero-content.css, responsive2-workspace.css)
|
|
14
|
+
- Legacy tablet band: 481px–1024px (min-width 481px / max-width 1025px) —
|
|
15
|
+
used in this file (responsive.css) for a specific tablet treatment,
|
|
16
|
+
consider migrating to the 768/900 pair
|
|
17
|
+
*/
|
|
18
|
+
|
|
6
19
|
/* --------------------------------------------------------------------
|
|
7
20
|
Mobile Portrait Breakpoint (480px and below)
|
|
8
21
|
---------------------------------------------------------------------- */
|
|
@@ -281,7 +281,9 @@
|
|
|
281
281
|
.ws-rail-item:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
282
282
|
.ws-rail-item.active { background: var(--accent-tint); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
|
|
283
283
|
.ws-rail-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
|
|
284
|
-
|
|
284
|
+
/* Shape/color come from the shared .ds-badge component (see app-shell/primitives.css);
|
|
285
|
+
this class is now just the rail-item layout hook (spacing, collapsed-state targeting). */
|
|
286
|
+
.ws-rail-item-count { flex: none; margin-inline-start: var(--space-1); }
|
|
285
287
|
.ws-rail-item-flag { width: 6px; height: 6px; border-radius: 50%; flex: none; }
|
|
286
288
|
.ws-rail-item-flag.tone-flame { background: var(--flame); box-shadow: 0 0 0 2px color-mix(in oklab, var(--flame) 38%, transparent); }
|
|
287
289
|
.ws-rail-foot { margin-top: auto; padding-top: var(--space-2); border-top: var(--bw-hair) solid var(--bg-3); }
|
|
@@ -324,6 +326,7 @@
|
|
|
324
326
|
because the chat thread carries its own --measure gutter. */
|
|
325
327
|
.ws-main { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; padding: var(--space-4) var(--space-5); }
|
|
326
328
|
.ws-main.ws-main--flush { padding: 0; }
|
|
329
|
+
/* Non-interactive scroll region (content column), not a focusable control — outline intentionally suppressed. */
|
|
327
330
|
.ws-main:focus { outline: none; }
|
|
328
331
|
|
|
329
332
|
/* Right context pane */
|
|
@@ -71,5 +71,39 @@
|
|
|
71
71
|
.ds-live-log { height: auto; max-height: none; overflow: visible; }
|
|
72
72
|
.ds-stat, .kpi-card { border: 1px solid var(--rule); }
|
|
73
73
|
.ds-session-row { break-inside: avoid; }
|
|
74
|
+
|
|
75
|
+
/* Receipt table (Receipt() in src/components/content/panel.js, `.kv`) — the
|
|
76
|
+
project_page kit's "receipt" section, and any other kv-table consumer.
|
|
77
|
+
On screen it inherits panel/token colors that can render as near-white
|
|
78
|
+
text on a printer's assumed-white page background if the browser's
|
|
79
|
+
"background graphics" print option is off (the common default); force
|
|
80
|
+
the LIGHT-theme ink/paper tokens (real print-page colors, not a raw
|
|
81
|
+
literal — --ink/--paper are the same "true black text on true white
|
|
82
|
+
page" values the light theme already defines) and visible cell borders
|
|
83
|
+
so it stays legible without relying on background-graphics printing at
|
|
84
|
+
all. break-inside:avoid keeps a receipt from splitting a row across a
|
|
85
|
+
page boundary. */
|
|
86
|
+
.kv { border-collapse: collapse; width: 100%; color: var(--ink); background: var(--paper); }
|
|
87
|
+
.kv tr { break-inside: avoid; }
|
|
88
|
+
.kv td { border: 1px solid var(--paper-3); padding: 4px 8px; color: var(--ink); }
|
|
89
|
+
|
|
90
|
+
/* Any button/interactive-only affordance still present inside otherwise-
|
|
91
|
+
printable content (copy buttons, expand/collapse toggles, filter pills,
|
|
92
|
+
the receipt/doc section's own action row) is chrome, not content. */
|
|
93
|
+
.btn, .btn-primary, .btn-ghost, .row-act, .ds-filter-pills,
|
|
94
|
+
.app-search, input[type="search"] { display: none; }
|
|
95
|
+
|
|
96
|
+
/* Force real ink-on-paper for body copy: panel/fg tokens are tuned for
|
|
97
|
+
screen surfaces (including dark theme, where --panel-text can resolve
|
|
98
|
+
near-white) and a printer defaults to a white page regardless of
|
|
99
|
+
data-theme, so an unconverted dark-theme page would print near-invisible
|
|
100
|
+
text without this override. Same --ink/--paper light-theme pair as the
|
|
101
|
+
receipt table above, not a second raw literal. */
|
|
102
|
+
/* No !important: source order already wins here (this rule is the last
|
|
103
|
+
word inside its own @media print block, same as every other override in
|
|
104
|
+
this file), and an unconditional !important on `body` would beat even a
|
|
105
|
+
future print-specific consumer override with higher specificity. */
|
|
106
|
+
html body, .app-main, .page-body, .ds-lede { color: var(--ink); background: var(--paper); }
|
|
107
|
+
a { color: var(--ink); text-decoration: underline; }
|
|
74
108
|
}
|
|
75
109
|
|