agentgui 1.0.1117 → 1.0.1118
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/.gm/.embed-generation.code_chunks +1 -0
- package/.gm/.embed-generation.git_commit_vectors +1 -0
- package/.gm/.embed-generation.memories +1 -0
- package/.gm/.embed-generation.rssearch_vectors +1 -0
- package/.gm/prd.yml +15 -0
- package/AGENTS.md +1 -1
- package/lib/acp-sdk-manager.js +15 -2
- package/lib/claude-runner-agents.js +8 -1
- package/lib/http-handler.js +35 -566
- package/lib/http-routes/mutations.js +199 -0
- package/lib/http-routes/reads.js +212 -0
- package/lib/http-routes/shared.js +213 -0
- package/lib/ws-handlers/agents.js +137 -0
- package/lib/ws-handlers/chat.js +157 -0
- package/lib/ws-handlers/git.js +159 -0
- package/lib/ws-handlers/misc.js +36 -0
- package/lib/ws-handlers/shared.js +47 -0
- package/lib/ws-handlers/terminal-state.js +16 -0
- package/lib/ws-handlers-util.js +8 -526
- package/package.json +1 -1
- package/site/app/js/app.js +8 -103
- package/site/app/js/chat-persistence.js +123 -0
- package/site/app/vendor/anentrypoint-design/247420.css +1614 -488
- package/site/app/vendor/anentrypoint-design/247420.js +363 -77
- package/UX_OPTIMIZATION_SUMMARY.md +0 -238
- package/agentgui-after.png +0 -0
- package/agentgui-current.png +0 -0
- package/agentgui-final.png +0 -0
- package/agentgui-nobrand.png +0 -0
- package/agentgui-now.png +0 -0
- package/agentgui-v2.png +0 -0
- package/agentgui-v4.png +0 -0
- package/bash.exe.stackdump +0 -28
- package/design-reference.png +0 -0
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
--ink-2: #333338;
|
|
35
35
|
--ink-3: #525252; /* WCAG-verified 2026 restyle: npm run a11y caught 4.10:1 at #58585F against --paper-3 (#c6c5c5-equivalent surfaces); #525252 clears 4.54:1 there and 7.81:1 against pure paper */
|
|
36
36
|
--ink-3-dark: #4D4D52; /* dark theme bg-3 (tier-3 surface) */
|
|
37
|
-
--paper-3-dark: #
|
|
37
|
+
--paper-3-dark: #BEBEBE; /* dark theme fg-3 (tier-3 text); #9B9B9B cleared 4.52:1 against --ink-2 but --fg-3 also renders on --bg-3 (--ink-3-dark, #4D4D52, e.g. .chip.tone-dim), where it measured only 3.02:1. #BEBEBE clears 4.52:1 on --ink-3-dark, 6.76:1 on --ink-2, 9.36:1 on --ink. */
|
|
38
38
|
|
|
39
39
|
/* Lore palette. --acid was the prior electric-lime lead; RESTYLED to a
|
|
40
40
|
neutral near-black accent matching webjsx-toolkit's grayscale --primary
|
|
@@ -189,6 +189,16 @@
|
|
|
189
189
|
--ff-body: system-ui, sans-serif;
|
|
190
190
|
--ff-mono: ui-monospace, Menlo, Consolas, monospace;
|
|
191
191
|
|
|
192
|
+
/* Weight scale — regular is the default voice for body/UI text everywhere;
|
|
193
|
+
medium/semibold/bold are reserved for genuine emphasis (active state,
|
|
194
|
+
unread counts, own-message author, section headers). Never reach for a
|
|
195
|
+
hardcoded 600/700 in a component rule — use these so the whole surface
|
|
196
|
+
can be re-tuned in one place instead of drifting per-component. */
|
|
197
|
+
--fw-regular: 400;
|
|
198
|
+
--fw-medium: 500;
|
|
199
|
+
--fw-semibold: 600;
|
|
200
|
+
--fw-bold: 700;
|
|
201
|
+
|
|
192
202
|
/* Sub-12px tiers exist ONLY for dense OS/data chrome — taskbar strips,
|
|
193
203
|
session chips, tool-call headers, file-row metadata, ID/stat columns.
|
|
194
204
|
Never use them for body copy or ordinary UI text: at these sizes the
|
|
@@ -203,12 +213,24 @@
|
|
|
203
213
|
--fs-body: 16px;
|
|
204
214
|
--fs-lg: 18px;
|
|
205
215
|
--fs-xl: 21px;
|
|
206
|
-
--fs-h4: clamp(
|
|
207
|
-
--fs-h3: clamp(
|
|
216
|
+
--fs-h4: clamp(24px, 2cqi, 28px);
|
|
217
|
+
--fs-h3: clamp(26px, 2.6cqi, 34px);
|
|
208
218
|
--fs-h2: clamp(28px, 3.6cqi, 44px);
|
|
209
219
|
--fs-h1: clamp(34px, 5cqi, 64px);
|
|
210
220
|
--fs-hero: clamp(42px, 7cqi, 96px);
|
|
211
221
|
--fs-mega: clamp(56px, 11cqi, 168px);
|
|
222
|
+
/* Bridges the fixed --fs-* ladder (tops out at --fs-xl, 21px) and the fluid
|
|
223
|
+
heading clamps below it — use for fixed (non-clamping) UI text that needs
|
|
224
|
+
to sit between --fs-xl and a heading tier, e.g. empty-state icon glyphs. */
|
|
225
|
+
--fs-2xl: 28px;
|
|
226
|
+
|
|
227
|
+
/* Icon size scale — canonical sizes for glyphs/icons across the kit going
|
|
228
|
+
forward. Existing ad-hoc pixel values (6/7/8/10/12/14/16/18px etc.)
|
|
229
|
+
don't need to be migrated in this pass; new/updated icon usage should. */
|
|
230
|
+
--icon-xs: 12px;
|
|
231
|
+
--icon-sm: 16px;
|
|
232
|
+
--icon-md: 20px;
|
|
233
|
+
--icon-lg: 24px;
|
|
212
234
|
|
|
213
235
|
/* App/chrome typescale: the default heading scale above is tuned for
|
|
214
236
|
marketing/hero layouts (h1 up to 64px). Application chrome — page titles,
|
|
@@ -357,6 +379,9 @@
|
|
|
357
379
|
--z-below: -1;
|
|
358
380
|
--z-base: 0;
|
|
359
381
|
--z-raised: 100;
|
|
382
|
+
--z-raised-1: calc(var(--z-raised) + 1);
|
|
383
|
+
--z-raised-2: calc(var(--z-raised) + 2);
|
|
384
|
+
--z-raised-3: calc(var(--z-raised) + 3);
|
|
360
385
|
--z-sticky: 200;
|
|
361
386
|
--z-header: 300;
|
|
362
387
|
--z-drawer: 400;
|
|
@@ -386,6 +411,17 @@
|
|
|
386
411
|
--sidebar-width: 220px;
|
|
387
412
|
--sidebar-width-collapsed: 64px;
|
|
388
413
|
|
|
414
|
+
/* Canonical breakpoint values — @media can't reference custom properties,
|
|
415
|
+
so these are documented here (not tokenized) for consistency across
|
|
416
|
+
responsive.css/responsive2-workspace.css/hero-content.css:
|
|
417
|
+
- 480px (max-width) mobile portrait
|
|
418
|
+
- 768px (max-width) mobile/tablet boundary, compact nav/sidebar collapse
|
|
419
|
+
- 768-1024px (min/max-width) tablet landscape band
|
|
420
|
+
- 900px (max-width) / 901px (min-width) tablet/desktop layout reflow
|
|
421
|
+
- 1025px (min-width) desktop
|
|
422
|
+
Always use these exact values; a near-miss (e.g. 760px, 481px) should be
|
|
423
|
+
aligned to its canonical neighbour when touched. */
|
|
424
|
+
|
|
389
425
|
--lh-tall: 1.4;
|
|
390
426
|
|
|
391
427
|
/* Control size scale — heights for status/topbar/crumb + controls. */
|
|
@@ -417,6 +453,9 @@
|
|
|
417
453
|
--focus-w: 2px;
|
|
418
454
|
--focus-offset: 2px;
|
|
419
455
|
--focus-ring-inset: inset 0 0 0 var(--focus-w) var(--focus-color);
|
|
456
|
+
|
|
457
|
+
/* letterbox background for video/media containers */
|
|
458
|
+
--media-letterbox: #000;
|
|
420
459
|
}
|
|
421
460
|
|
|
422
461
|
/* ============================================================
|
|
@@ -519,6 +558,27 @@
|
|
|
519
558
|
--code-num: var(--sun);
|
|
520
559
|
}
|
|
521
560
|
|
|
561
|
+
/* [data-accent="X"] overrides (below) hardcode LIGHT-tuned fills (--acid,
|
|
562
|
+
--purple, --green) with no dark-theme companion, so data-theme=dark +
|
|
563
|
+
data-accent=acid/purple/green produced a near-invisible fill against the
|
|
564
|
+
dark page bg (measured: acid 1.15:1, purple 1.04:1, green 2.98:1 on --ink
|
|
565
|
+
-- all under the 3:1 non-text UI-fill floor). Same convention as the base
|
|
566
|
+
--accent retune above: restate the fill as its dark-tuned equivalent so
|
|
567
|
+
the swatch stays visible, using tones already verified elsewhere in this
|
|
568
|
+
file (green retune 7.48:1 on --ink, purple-2 retune 6.11:1 on --ink). */
|
|
569
|
+
.ds-247420[data-theme="ink"][data-accent="acid"],
|
|
570
|
+
.ds-247420[data-theme="dark"][data-accent="acid"] {
|
|
571
|
+
--accent: #BFBFBF; --accent-bright: #BFBFBF; --accent-fg: var(--ink); --accent-ink: var(--paper); --panel-accent: #BFBFBF;
|
|
572
|
+
}
|
|
573
|
+
.ds-247420[data-theme="ink"][data-accent="purple"],
|
|
574
|
+
.ds-247420[data-theme="dark"][data-accent="purple"] {
|
|
575
|
+
--accent: #C277FF; --accent-bright: #C277FF; --accent-fg: var(--ink); --accent-ink: #C277FF; --panel-accent: #C277FF;
|
|
576
|
+
}
|
|
577
|
+
.ds-247420[data-theme="ink"][data-accent="green"],
|
|
578
|
+
.ds-247420[data-theme="dark"][data-accent="green"] {
|
|
579
|
+
--accent: #5CBF52; --accent-bright: #5CBF52; --accent-fg: var(--ink); --accent-ink: #5CBF52; --panel-accent: #5CBF52;
|
|
580
|
+
}
|
|
581
|
+
|
|
522
582
|
/* Restores the pre-existing (weaker) dark-theme selection tint after the
|
|
523
583
|
light-theme-only bump in app-shell.css's base ::selection rule. */
|
|
524
584
|
.ds-247420[data-theme="ink"] ::selection,
|
|
@@ -718,8 +778,20 @@
|
|
|
718
778
|
|
|
719
779
|
/* Type-scale modifier — opt-in body/lg/xl bump for surfaces that want denser
|
|
720
780
|
or larger reading sizes without a custom override. */
|
|
721
|
-
.ds-247420[data-typescale="sm"] {
|
|
722
|
-
|
|
781
|
+
.ds-247420[data-typescale="sm"] {
|
|
782
|
+
--fs-body: 15px; --fs-lg: 17px; --fs-xl: 20px;
|
|
783
|
+
--fs-h4: clamp(22px, 1.9cqi, 24px);
|
|
784
|
+
--fs-h3: clamp(23px, 2.4cqi, 32px);
|
|
785
|
+
--fs-h2: clamp(26px, 3.4cqi, 41px);
|
|
786
|
+
--fs-h1: clamp(32px, 4.7cqi, 60px);
|
|
787
|
+
}
|
|
788
|
+
.ds-247420[data-typescale="lg"] {
|
|
789
|
+
--fs-body: 17px; --fs-lg: 20px; --fs-xl: 24px;
|
|
790
|
+
--fs-h4: clamp(27px, 2.2cqi, 31px);
|
|
791
|
+
--fs-h3: clamp(28px, 2.9cqi, 38px);
|
|
792
|
+
--fs-h2: clamp(31px, 4cqi, 49px);
|
|
793
|
+
--fs-h1: clamp(38px, 5.6cqi, 71px);
|
|
794
|
+
}
|
|
723
795
|
|
|
724
796
|
/* Debug grid overlay — 8px mascot grid. Toggle via class on any container. */
|
|
725
797
|
.ds-247420 .with-grid-overlay {
|
|
@@ -805,50 +877,41 @@
|
|
|
805
877
|
}
|
|
806
878
|
|
|
807
879
|
/* app-shell.css */
|
|
808
|
-
/* ============================================================
|
|
809
|
-
247420 design system — component sheet
|
|
810
|
-
shadcn-neutral: system-font display + body + mono, no custom web fonts.
|
|
811
|
-
Confident hierarchy, centered editorial stack, neutral grayscale accent.
|
|
812
|
-
Indicator rails over hairlines.
|
|
813
|
-
============================================================ */
|
|
814
|
-
|
|
815
|
-
/* ============================================================
|
|
816
|
-
Base
|
|
817
|
-
============================================================ */
|
|
818
880
|
.ds-247420 * { box-sizing: border-box; }
|
|
819
881
|
.ds-247420, .ds-247420 body { margin: 0; padding: 0; }
|
|
820
882
|
.ds-247420 button, .ds-247420 input, .ds-247420 select, .ds-247420 textarea { font: inherit; }
|
|
821
883
|
|
|
822
|
-
/*
|
|
823
|
-
|
|
824
|
-
|
|
884
|
+
/* Global reduced-motion safety net: catches any component transition/animation
|
|
885
|
+
that lacks its own per-file prefers-reduced-motion override (most components
|
|
886
|
+
already opt out locally; this is the backstop for the rest, e.g.
|
|
887
|
+
plugins-config.css, catalog-theme.css, sidebar-misc.css, row-print.css,
|
|
888
|
+
topbar.css, primitives.css, git-status.css, panel-row.css). Scroll-snap
|
|
889
|
+
carousels handle scroll-behavior themselves and are unaffected. */
|
|
890
|
+
@media (prefers-reduced-motion: reduce) {
|
|
891
|
+
.ds-247420 *, .ds-247420 *::before, .ds-247420 *::after {
|
|
892
|
+
animation-duration: 0.001ms !important;
|
|
893
|
+
animation-iteration-count: 1 !important;
|
|
894
|
+
transition-duration: 0.001ms !important;
|
|
895
|
+
scroll-behavior: auto !important;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
825
899
|
.ds-247420 .skip-link {
|
|
900
|
+
--skip-link-preflight-translate-clear: -100%;
|
|
826
901
|
position: absolute;
|
|
827
|
-
/* -40px alone left the 44px-tall pill (padding + min-height floor below)
|
|
828
|
-
poking ~4px into every page pre-focus -- measured live via
|
|
829
|
-
getBoundingClientRect(). The offset must clear the full rendered height,
|
|
830
|
-
not a guessed constant, so translateY pushes it out by its own box. */
|
|
831
902
|
top: 0;
|
|
832
903
|
left: 0;
|
|
833
|
-
transform: translateY(-
|
|
904
|
+
transform: translateY(var(--skip-link-preflight-translate-clear));
|
|
834
905
|
background: var(--accent);
|
|
835
906
|
color: var(--accent-fg);
|
|
836
907
|
padding: var(--space-2) var(--space-3);
|
|
837
908
|
text-decoration: none;
|
|
838
|
-
/* Must outrank every layer of chrome once focused, or the first Tab press
|
|
839
|
-
lands on a control hidden behind the sticky header (was z-index:100,
|
|
840
|
-
which the header alone now matches). */
|
|
841
909
|
z-index: var(--z-top);
|
|
842
910
|
border-radius: var(--r-pill);
|
|
843
911
|
font-weight: 600;
|
|
844
912
|
font-size: var(--fs-sm);
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
it 39px tall -- measured live under coarse-pointer emulation on every kit.
|
|
848
|
-
Floored unconditionally rather than under a pointer:coarse query, because
|
|
849
|
-
switch and head-pointer users are not detected as coarse pointers and need
|
|
850
|
-
the larger target just as much. */
|
|
851
|
-
min-height: 44px;
|
|
913
|
+
--skip-link-min-touch-target: 44px;
|
|
914
|
+
min-height: var(--skip-link-min-touch-target);
|
|
852
915
|
display: inline-flex;
|
|
853
916
|
align-items: center;
|
|
854
917
|
}
|
|
@@ -858,23 +921,6 @@
|
|
|
858
921
|
outline: var(--focus-w) solid var(--focus-color);
|
|
859
922
|
outline-offset: var(--focus-offset);
|
|
860
923
|
}
|
|
861
|
-
/* Visually-hidden but still in the accessibility tree. Emitted by Row() (the
|
|
862
|
-
rail status word), FilterBar()/FileGrid() (aria-live result counts) and
|
|
863
|
-
form-primitives' required marker — all of which shipped BEFORE this rule
|
|
864
|
-
existed anywhere the app shell loads. The only other definitions live in
|
|
865
|
-
app-surfaces.css (pre-scoped to `.ds-247420`, so it never reaches a kit that
|
|
866
|
-
does not mount that root) and editor-primitives.css (a separate opt-in
|
|
867
|
-
<link>), which left every app-shell consumer rendering screen-reader-only
|
|
868
|
-
text VISIBLY the moment it passed `rail`/`resultCount`.
|
|
869
|
-
Deliberately NOT `display:none` / `visibility:hidden` / `width:0`: those
|
|
870
|
-
remove the node from the accessibility tree too, which defeats the entire
|
|
871
|
-
purpose — the text exists only for AT. The clip + 1px box is what keeps it
|
|
872
|
-
announced while occupying no visible area.
|
|
873
|
-
`margin: -1px` is OFF-SCALE ON PURPOSE — it is not rhythm, it is one half of
|
|
874
|
-
the canonical visually-hidden idiom: the negative margin cancels the 1px box
|
|
875
|
-
so the clipped element contributes zero layout. Snapping it to a --space-*
|
|
876
|
-
rung would reintroduce a measurable gap. `clip` is deprecated but retained
|
|
877
|
-
alongside `clip-path` for older AT/browser pairs that ignore the latter. */
|
|
878
924
|
.ds-247420 .sr-only {
|
|
879
925
|
position: absolute;
|
|
880
926
|
width: 1px;
|
|
@@ -888,11 +934,6 @@
|
|
|
888
934
|
border: 0;
|
|
889
935
|
}
|
|
890
936
|
|
|
891
|
-
/* .ds-aspect — generic aspect-ratio utility. Native `aspect-ratio` property
|
|
892
|
-
(broadly supported for years) rather than the padding-bottom hack: no
|
|
893
|
-
extra wrapper markup, no absolutely-positioned inner layer needed just to
|
|
894
|
-
fill the box. `--aspect` defaults to 16/9; a caller overrides it inline
|
|
895
|
-
(e.g. style="--aspect:1/1") or via a ratio-named modifier class below. */
|
|
896
937
|
.ds-247420 .ds-aspect {
|
|
897
938
|
aspect-ratio: var(--aspect, 16 / 9);
|
|
898
939
|
width: 100%;
|
|
@@ -912,14 +953,11 @@
|
|
|
912
953
|
-webkit-font-smoothing: antialiased;
|
|
913
954
|
text-rendering: optimizeLegibility;
|
|
914
955
|
}
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
scoping a value per theme rather than sharing one across both). */
|
|
920
|
-
.ds-247420 ::selection { background: color-mix(in oklab, var(--accent) 46%, var(--bg-2)); color: var(--fg); }
|
|
956
|
+
.ds-247420 {
|
|
957
|
+
--selection-tint-paper-share: 46%;
|
|
958
|
+
}
|
|
959
|
+
.ds-247420 ::selection { background: color-mix(in oklab, var(--accent) var(--selection-tint-paper-share), var(--bg-2)); color: var(--fg); }
|
|
921
960
|
|
|
922
|
-
/* Every root has a CQ container so fluid type can resolve to a meaningful inline-size. */
|
|
923
961
|
.ds-247420 .app, .ds-247420 .ds-stage {
|
|
924
962
|
container-type: inline-size;
|
|
925
963
|
overflow-x: clip;
|
|
@@ -927,29 +965,31 @@
|
|
|
927
965
|
}
|
|
928
966
|
.ds-247420 .app * { min-width: 0; }
|
|
929
967
|
|
|
930
|
-
/* Scrollbar treatment, applied once at the root rather than per-component.
|
|
931
|
-
chat.css already styled its own thread and code blocks this way, but every
|
|
932
|
-
other scroll container (.app-side-shell, .app-main, .ds-scroll-x,
|
|
933
|
-
.ds-table-wrap, .ds-live-log) fell back to the UA default -- measured live,
|
|
934
|
-
4 of 4 containers on dashboard and 7 of 7 on gm_inspector were unstyled while
|
|
935
|
-
chat's two were not. A default scrollbar reads as a bright seam against a
|
|
936
|
-
near-black panel in the ink and dark themes, and inconsistently between two
|
|
937
|
-
panels on the same page. Tokens mean the thumb follows the active theme.
|
|
938
|
-
Inheriting from the container also covers scrollers added later. */
|
|
939
968
|
.ds-247420 .app, .ds-247420 .ds-stage, .ds-247420 .app *, .ds-247420 .ds-stage * {
|
|
940
969
|
scrollbar-width: thin;
|
|
941
970
|
scrollbar-color: var(--bg-3) transparent;
|
|
942
971
|
}
|
|
972
|
+
/* Firefox gets themed scrollbars via scrollbar-width/-color above; Chrome,
|
|
973
|
+
Safari, and Edge need the ::-webkit-scrollbar family too, or every
|
|
974
|
+
scrollable node in the app shell falls back to the raw OS scrollbar and
|
|
975
|
+
clashes with the dark UI. Same selector scope, same --bg-3 token. */
|
|
976
|
+
.ds-247420 .app::-webkit-scrollbar, .ds-247420 .ds-stage::-webkit-scrollbar, .ds-247420 .app *::-webkit-scrollbar, .ds-247420 .ds-stage *::-webkit-scrollbar {
|
|
977
|
+
width: 8px;
|
|
978
|
+
height: 8px;
|
|
979
|
+
}
|
|
980
|
+
.ds-247420 .app::-webkit-scrollbar-track, .ds-247420 .ds-stage::-webkit-scrollbar-track, .ds-247420 .app *::-webkit-scrollbar-track, .ds-247420 .ds-stage *::-webkit-scrollbar-track {
|
|
981
|
+
background: transparent;
|
|
982
|
+
}
|
|
983
|
+
.ds-247420 .app::-webkit-scrollbar-thumb, .ds-247420 .ds-stage::-webkit-scrollbar-thumb, .ds-247420 .app *::-webkit-scrollbar-thumb, .ds-247420 .ds-stage *::-webkit-scrollbar-thumb {
|
|
984
|
+
background: var(--bg-3);
|
|
985
|
+
border-radius: var(--r-pill, 999px);
|
|
986
|
+
}
|
|
943
987
|
|
|
944
|
-
/* ============================================================
|
|
945
|
-
Typography
|
|
946
|
-
============================================================ */
|
|
947
988
|
.ds-247420 h1, .ds-247420 .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; }
|
|
948
989
|
.ds-247420 h2, .ds-247420 .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; }
|
|
949
990
|
.ds-247420 h3, .ds-247420 .t-h3 { font-family: var(--ff-display); font-size: var(--fs-h3); line-height: var(--lh-snug); letter-spacing: -0.01em; font-weight: 600; margin: 0; }
|
|
950
991
|
.ds-247420 h4, .ds-247420 .t-h4 { font-family: var(--ff-display); font-size: var(--fs-h4); line-height: var(--lh-snug); font-weight: 600; margin: 0; }
|
|
951
992
|
|
|
952
|
-
/* App/chrome typescale opt-in: compact heading ceiling for application UIs. */
|
|
953
993
|
.ds-247420[data-typescale="app"] h1, .ds-247420[data-typescale="app"] .t-h1 { font-size: var(--fs-h1-app); line-height: 1.15; }
|
|
954
994
|
.ds-247420[data-typescale="app"] h2, .ds-247420[data-typescale="app"] .t-h2 { font-size: var(--fs-h2-app); }
|
|
955
995
|
.ds-247420[data-typescale="app"] h3, .ds-247420[data-typescale="app"] .t-h3 { font-size: var(--fs-h3-app); }
|
|
@@ -959,16 +999,9 @@
|
|
|
959
999
|
.ds-247420 .t-mega { font-family: var(--ff-display); font-size: var(--fs-mega); line-height: 0.92; letter-spacing: var(--tr-tighter); font-weight: 700; margin: 0; }
|
|
960
1000
|
|
|
961
1001
|
.ds-247420 .t-display { font-family: var(--ff-display); font-weight: 600; letter-spacing: var(--tr-tight); }
|
|
962
|
-
.ds-247420 .t-mono { font-family: var(--ff-mono); }
|
|
1002
|
+
.ds-247420 .t-mono { font-family: var(--ff-mono); font-weight: 400; }
|
|
963
1003
|
.ds-247420 .t-body { font-family: var(--ff-body); }
|
|
964
1004
|
|
|
965
|
-
/* House small-label voice, in two sizes. Every declaration here is sourced
|
|
966
|
-
from a token, so a sheet that cannot join these selector lists (community.css
|
|
967
|
-
and gm-prose.css ship as separate <link>-able exports and must not depend on
|
|
968
|
-
app-shell.css being present) still composes the same voice by referencing the
|
|
969
|
-
same four tokens — --ff-mono / --fs-* / uppercase / --tr-label. That token
|
|
970
|
-
set, not this rule, is the single source of truth; a selector that restates a
|
|
971
|
-
literal instead of the token is the drift this pairing exists to prevent. */
|
|
972
1005
|
.ds-247420 .t-label { font-family: var(--ff-mono); font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: var(--tr-label); font-weight: 500; }
|
|
973
1006
|
.ds-247420 .t-micro { font-family: var(--ff-mono); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: var(--tr-label); color: var(--fg-3); }
|
|
974
1007
|
.ds-247420 .t-meta { font-family: var(--ff-body); font-size: var(--fs-sm); color: var(--fg-3); }
|
|
@@ -979,17 +1012,18 @@
|
|
|
979
1012
|
margin: 0;
|
|
980
1013
|
}
|
|
981
1014
|
|
|
982
|
-
/* h1/h2/h3/h4 and .lede/.t-lede are both margin:0 primitives by design (a
|
|
983
|
-
heading used standalone must not force space its context doesn't want).
|
|
984
|
-
But a heading immediately followed by a lede is a named pairing, not two
|
|
985
|
-
independent primitives that happen to be adjacent -- it needs its own gap
|
|
986
|
-
regardless of whether the surrounding shell opts into .ds-app-surface
|
|
987
|
-
(which only adds this spacing on landing/marketing surfaces, leaving every
|
|
988
|
-
Operate-mode kit that skips that class with a zero-gap heading+subtitle). */
|
|
989
1015
|
.ds-247420 h1 + .lede, .ds-247420 h1 + .t-lede, .ds-247420 h2 + .lede, .ds-247420 h2 + .t-lede, .ds-247420 h3 + .lede, .ds-247420 h3 + .t-lede, .ds-247420 .t-h1 + .lede, .ds-247420 .t-h1 + .t-lede {
|
|
990
1016
|
margin-top: var(--space-2);
|
|
991
1017
|
}
|
|
992
1018
|
|
|
1019
|
+
.ds-247420 .lede + .post-body, .ds-247420 .t-lede + .post-body, .ds-247420 .lede + .ds-prose, .ds-247420 .t-lede + .ds-prose {
|
|
1020
|
+
margin-top: var(--space-4);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
.ds-247420 .lede + .ds-section, .ds-247420 .t-lede + .ds-section {
|
|
1024
|
+
margin-top: var(--space-8);
|
|
1025
|
+
}
|
|
1026
|
+
|
|
993
1027
|
.ds-247420 .eyebrow {
|
|
994
1028
|
font-family: var(--ff-mono);
|
|
995
1029
|
font-size: var(--fs-tiny);
|
|
@@ -999,7 +1033,6 @@
|
|
|
999
1033
|
color: var(--accent-ink);
|
|
1000
1034
|
display: inline-flex; align-items: center; gap: 12px;
|
|
1001
1035
|
}
|
|
1002
|
-
/* Editorial kicker mark — a short solid ink rule, the print-byline tell. */
|
|
1003
1036
|
.ds-247420 .eyebrow::before {
|
|
1004
1037
|
content: '';
|
|
1005
1038
|
width: 28px; height: 3px; background: currentColor;
|
|
@@ -1028,21 +1061,6 @@
|
|
|
1028
1061
|
font-family: var(--ff-body);
|
|
1029
1062
|
}
|
|
1030
1063
|
.ds-247420 .ds-prose blockquote p:last-child { margin-bottom: 0; }
|
|
1031
|
-
/* Closing line of an article ("end. reply by opening a pr."), set off from the
|
|
1032
|
-
body it terminates. Quieter and smaller than the prose around it: it takes
|
|
1033
|
-
the mono face and the --fg-3 tone the house uses for ancillary voices
|
|
1034
|
-
(.t-micro, .dim), so the endnote reads as chrome around the article rather
|
|
1035
|
-
than a final paragraph of it. The --space-5 lead does the "set off" — it
|
|
1036
|
-
breaks the paragraph rhythm so the eye registers the piece has ended before
|
|
1037
|
-
reading the words; margin-bottom:0 overrides .ds-prose p's --space-4 so the
|
|
1038
|
-
article does not end on dead space.
|
|
1039
|
-
Lives here, beside the rest of the .ds-prose family, NOT in gm-prose.css:
|
|
1040
|
-
the blog kit that uses this class links only colors_and_type.css +
|
|
1041
|
-
app-shell.css, so a rule in that separately-<link>-ed export would be exactly
|
|
1042
|
-
as undefined as the class was before. Sized at --fs-xs, not the --fs-micro
|
|
1043
|
-
label rung: this is a readable sentence with a link in it, not a micro-label.
|
|
1044
|
-
The link inherits .ds-prose a's --accent-ink treatment (a readable TEXT tone;
|
|
1045
|
-
the bare --accent fill is ~1.07:1 on paper) — deliberately not re-stated. */
|
|
1046
1064
|
.ds-247420 .ds-prose .ds-prose-endnote,
|
|
1047
1065
|
.ds-247420 .ds-prose-endnote {
|
|
1048
1066
|
margin-top: var(--space-5);
|
|
@@ -1055,7 +1073,6 @@
|
|
|
1055
1073
|
|
|
1056
1074
|
.ds-247420 .dim { color: var(--fg-3); }
|
|
1057
1075
|
|
|
1058
|
-
/* Links */
|
|
1059
1076
|
.ds-247420 a { color: inherit; text-decoration: none; }
|
|
1060
1077
|
.ds-247420 a.ds-link-accent, .ds-247420 .ds-prose a {
|
|
1061
1078
|
color: var(--accent-ink);
|
|
@@ -1063,6 +1080,13 @@
|
|
|
1063
1080
|
text-underline-offset: 4px;
|
|
1064
1081
|
text-decoration-thickness: 2px;
|
|
1065
1082
|
}
|
|
1083
|
+
/* Visited state was entirely absent -- a returning user had no way to tell an
|
|
1084
|
+
already-read link from an unread one, the one link state browsers don't
|
|
1085
|
+
fake for you. --purple-2 keeps it distinct from both the unvisited accent
|
|
1086
|
+
and any hover/danger tone already in the palette. */
|
|
1087
|
+
.ds-247420 a.ds-link-accent:visited, .ds-247420 .ds-prose a:visited {
|
|
1088
|
+
color: var(--purple-2);
|
|
1089
|
+
}
|
|
1066
1090
|
.ds-247420 a.ds-link-accent:hover, .ds-247420 .ds-prose a:hover {
|
|
1067
1091
|
background: var(--accent); color: var(--accent-fg); text-decoration-color: transparent;
|
|
1068
1092
|
}
|
|
@@ -1073,8 +1097,9 @@
|
|
|
1073
1097
|
}
|
|
1074
1098
|
|
|
1075
1099
|
.ds-247420 code {
|
|
1100
|
+
--code-pill-tier3-surface: var(--bg-3);
|
|
1076
1101
|
font-family: var(--ff-mono); font-size: 0.92em;
|
|
1077
|
-
background: var(--
|
|
1102
|
+
background: var(--code-pill-tier3-surface); padding: 0.15em 0.5em; border-radius: var(--r-1);
|
|
1078
1103
|
}
|
|
1079
1104
|
|
|
1080
1105
|
.ds-247420 pre {
|
|
@@ -1145,7 +1170,7 @@
|
|
|
1145
1170
|
display: flex; flex-wrap: wrap;
|
|
1146
1171
|
align-items: center; gap: var(--space-4);
|
|
1147
1172
|
min-height: var(--app-topbar-h);
|
|
1148
|
-
padding:
|
|
1173
|
+
padding: var(--space-2-5) var(--pad-x);
|
|
1149
1174
|
background: color-mix(in oklab, var(--bg) 97%, transparent);
|
|
1150
1175
|
}
|
|
1151
1176
|
|
|
@@ -1158,7 +1183,7 @@
|
|
|
1158
1183
|
position: sticky; top: 0; z-index: var(--z-header);
|
|
1159
1184
|
display: flex; flex-wrap: wrap; align-items: center;
|
|
1160
1185
|
gap: var(--space-2) var(--space-4);
|
|
1161
|
-
padding:
|
|
1186
|
+
padding: var(--space-2) var(--pad-x);
|
|
1162
1187
|
background: color-mix(in oklab, var(--bg) 97%, transparent);
|
|
1163
1188
|
}
|
|
1164
1189
|
.ds-247420 .app-chrome > .app-topbar,
|
|
@@ -1175,7 +1200,24 @@
|
|
|
1175
1200
|
.ds-247420 .app-topbar > .brand { flex: 0 0 auto; }
|
|
1176
1201
|
.ds-247420 .app-topbar > .app-search { flex: 1 1 auto; }
|
|
1177
1202
|
.ds-247420 .app-topbar > nav { margin-left: auto; }
|
|
1178
|
-
|
|
1203
|
+
/* Utility cluster grouping: the theme toggle sits after the repo-info nav
|
|
1204
|
+
links with no visual separation between the two groups, so the row read
|
|
1205
|
+
as one undifferentiated strip of controls. A thin inset rule plus extra
|
|
1206
|
+
left gap reads as "these are a distinct utility group", matching the
|
|
1207
|
+
subtle divider already used between .app-status segments. */
|
|
1208
|
+
.ds-247420 .app-topbar > .app-topbar-theme {
|
|
1209
|
+
flex: 0 0 auto;
|
|
1210
|
+
margin-left: var(--space-2);
|
|
1211
|
+
padding-left: var(--space-3);
|
|
1212
|
+
position: relative;
|
|
1213
|
+
}
|
|
1214
|
+
.ds-247420 .app-topbar > .app-topbar-theme::before {
|
|
1215
|
+
content: ''; position: absolute; left: 0; top: 50%;
|
|
1216
|
+
transform: translateY(-50%);
|
|
1217
|
+
width: 1px; height: 18px;
|
|
1218
|
+
background: var(--rule-strong);
|
|
1219
|
+
}
|
|
1220
|
+
.ds-247420 .app-topbar nav { display: flex; gap: var(--space-1); font-size: var(--fs-sm); flex-wrap: wrap; }
|
|
1179
1221
|
.ds-247420 .app-topbar nav a { flex: 0 0 auto; }
|
|
1180
1222
|
.ds-247420 .app-topbar nav a {
|
|
1181
1223
|
color: var(--fg-2);
|
|
@@ -1228,6 +1270,12 @@
|
|
|
1228
1270
|
border-radius: var(--r-pill);
|
|
1229
1271
|
font-size: var(--fs-sm); color: var(--fg-3);
|
|
1230
1272
|
max-width: 360px;
|
|
1273
|
+
/* Match the system-wide input border language (.ds-field / .ds-search-input:
|
|
1274
|
+
tonal fill + printed baseline rule) instead of a borderless pill, so the
|
|
1275
|
+
topbar search reads as the same control family as every other input. */
|
|
1276
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule),
|
|
1277
|
+
inset 0 calc(-1 * var(--bw-rule)) 0 var(--rule-strong);
|
|
1278
|
+
transition: box-shadow var(--dur-snap) var(--ease), background var(--dur-snap) var(--ease);
|
|
1231
1279
|
}
|
|
1232
1280
|
.ds-247420 .app-search .icon { opacity: 0.6; }
|
|
1233
1281
|
.ds-247420 .app-search input {
|
|
@@ -1235,22 +1283,70 @@
|
|
|
1235
1283
|
font-family: inherit; font-size: inherit; color: var(--fg);
|
|
1236
1284
|
width: 100%;
|
|
1237
1285
|
}
|
|
1286
|
+
/* Same focus language as .ds-field/.ds-search-input: no outline ring, the
|
|
1287
|
+
baseline rule thickens to the accent instead — matching every other form
|
|
1288
|
+
input in the system rather than a one-off outline ring. */
|
|
1238
1289
|
.ds-247420 .app-search:focus-within {
|
|
1239
|
-
|
|
1240
|
-
|
|
1290
|
+
background: var(--bg);
|
|
1291
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule),
|
|
1292
|
+
inset 0 calc(-1 * var(--bw-chunk)) 0 var(--accent);
|
|
1241
1293
|
}
|
|
1242
1294
|
|
|
1243
1295
|
.ds-247420 .app-crumb {
|
|
1244
1296
|
min-height: var(--app-crumb-h);
|
|
1245
|
-
padding:
|
|
1246
|
-
display: flex; align-items: center; gap:
|
|
1297
|
+
padding: var(--space-1-75) var(--pad-x);
|
|
1298
|
+
display: flex; align-items: center; gap: var(--space-2);
|
|
1247
1299
|
font-size: var(--fs-sm); color: var(--fg-3);
|
|
1300
|
+
min-width: 0;
|
|
1248
1301
|
}
|
|
1249
|
-
.ds-247420 .app-crumb .sep { opacity: 0.5; }
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
.ds-247420 .app-
|
|
1302
|
+
.ds-247420 .app-crumb .sep { opacity: 0.5; flex: 0 0 auto; }
|
|
1303
|
+
/* Trail segments and the current/leaf segment truncate independently instead
|
|
1304
|
+
of the whole crumb bar overflowing — a long segment (deep file path, long
|
|
1305
|
+
title) must not push the sibling segments or the right slot off-screen. */
|
|
1306
|
+
.ds-247420 .app-crumb > span:not(.sep):not(.crumb-right) {
|
|
1307
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
1308
|
+
min-width: 0; flex: 0 1 auto;
|
|
1309
|
+
}
|
|
1310
|
+
/* Ancestor trail segments previously had no rule of their own and simply
|
|
1311
|
+
inherited .app-crumb's base --fg-3 — the same tone the separators sit on
|
|
1312
|
+
top of (before their own 0.5 opacity dims them further). That leaves only
|
|
1313
|
+
two visually distinct tiers in practice (dim separator, bold leaf) rather
|
|
1314
|
+
than three, since the ancestor tone reads as "default text colour", not a
|
|
1315
|
+
deliberate middle step. --fg-3 is the crumb bar's OWN base, so explicitly
|
|
1316
|
+
restating it here is the anchor for the 3-tier read: separator (--fg-3 at
|
|
1317
|
+
0.5 opacity, dimmest) < ancestor (--fg-3, mid) < leaf (--fg bold, brightest). */
|
|
1318
|
+
.ds-247420 .app-crumb > span:not(.sep):not(.leaf):not(.crumb-right) { color: var(--fg-3); }
|
|
1319
|
+
.ds-247420 .app-crumb .leaf { color: var(--fg); font-weight: 600; flex: 0 1 auto; }
|
|
1320
|
+
.ds-247420 .app-crumb .crumb-right { margin-left: auto; color: var(--fg-3); flex: 0 0 auto; }
|
|
1321
|
+
|
|
1322
|
+
/* The shell is the grid cell (.app-body's fixed sidebar column); it must own
|
|
1323
|
+
its own scroll, not just size to content, because .app-body's row track is
|
|
1324
|
+
`minmax(0, 1fr)` — a real height the sidebar can overflow once bins +
|
|
1325
|
+
labels + more exceed it. Without this the extra rows were silently chopped
|
|
1326
|
+
at the viewport edge with no way to reach them. */
|
|
1327
|
+
/* .app-side-shell and .app-main (below) are two INDEPENDENT scroll regions
|
|
1328
|
+
side by side -- correct by design (a sidebar nav and a main panel each own
|
|
1329
|
+
their own overflow), but with default invisible/overlay OS scrollbars a
|
|
1330
|
+
user hovering the boundary has no visual cue which region the wheel will
|
|
1331
|
+
scroll, or that there even are two scrollable zones rather than one page
|
|
1332
|
+
scroll. Thin always-visible scrollbar tracks make each region's own scroll
|
|
1333
|
+
ownership legible without changing the (correct) two-region architecture. */
|
|
1334
|
+
.ds-247420 .app-side-shell {
|
|
1335
|
+
background: var(--bg); overflow-y: auto; min-height: 0;
|
|
1336
|
+
scrollbar-width: thin; scrollbar-color: var(--rule-strong) transparent;
|
|
1337
|
+
/* Bottom-edge fade: a rail longer than the viewport otherwise shows only
|
|
1338
|
+
the thin scrollbar track as its sole "there is more below" cue. Mirrors
|
|
1339
|
+
the horizontal fade already used by .os-instances (src/kits/os/theme.css)
|
|
1340
|
+
for its own overflow edge, oriented top-to-bottom for this vertical
|
|
1341
|
+
scroller. The top edge stays fully opaque (rows start flush under the
|
|
1342
|
+
topbar with no need to hint upward scroll on initial load); only the
|
|
1343
|
+
trailing 24px softens toward transparent. */
|
|
1344
|
+
-webkit-mask-image: linear-gradient(to bottom, black calc(100% - 24px), transparent);
|
|
1345
|
+
mask-image: linear-gradient(to bottom, black calc(100% - 24px), transparent);
|
|
1346
|
+
}
|
|
1347
|
+
.ds-247420 .app-side-shell::-webkit-scrollbar { width: 8px; }
|
|
1348
|
+
.ds-247420 .app-side-shell::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: var(--r-pill, 999px); }
|
|
1349
|
+
.ds-247420 .app-side-shell::-webkit-scrollbar-track { background: transparent; }
|
|
1254
1350
|
.ds-247420 .app-body { display: grid; grid-template-columns: var(--sidebar-width) minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); align-items: stretch; align-content: stretch; flex: 1; min-height: 0; }
|
|
1255
1351
|
.ds-247420 .app-body.no-side { grid-template-columns: minmax(0, 1fr); }
|
|
1256
1352
|
/* When there is no sidebar, the empty side-shell must not occupy a grid row,
|
|
@@ -1273,7 +1369,7 @@
|
|
|
1273
1369
|
.ds-247420 .app-side .group {
|
|
1274
1370
|
font-size: var(--fs-xs); font-weight: 600;
|
|
1275
1371
|
color: var(--fg-3); padding: 0 var(--space-3);
|
|
1276
|
-
margin-bottom:
|
|
1372
|
+
margin-bottom: var(--space-1-75);
|
|
1277
1373
|
}
|
|
1278
1374
|
.ds-247420 .app-side a {
|
|
1279
1375
|
display: grid; grid-template-columns: 18px 1fr auto;
|
|
@@ -1288,7 +1384,7 @@
|
|
|
1288
1384
|
min-height: 44px;
|
|
1289
1385
|
border-radius: var(--r-1);
|
|
1290
1386
|
color: var(--fg-2);
|
|
1291
|
-
margin-bottom:
|
|
1387
|
+
margin-bottom: var(--space-hair);
|
|
1292
1388
|
}
|
|
1293
1389
|
@media (pointer: coarse) {
|
|
1294
1390
|
.ds-247420 .app-side a { min-height: 44px; padding: var(--space-2-75) var(--space-3); }
|
|
@@ -1358,6 +1454,15 @@
|
|
|
1358
1454
|
/* Reserve the scrollbar track so routes with/without overflow don't shift
|
|
1359
1455
|
the layout horizontally when the bar appears. */
|
|
1360
1456
|
.ds-247420 .app-main { scrollbar-gutter: stable; }
|
|
1457
|
+
/* Same visible-scroll-ownership rationale as .app-side-shell above -- makes
|
|
1458
|
+
this the visually distinct SECOND independent scroll region rather than
|
|
1459
|
+
an invisible-scrollbar mystery next to the sidebar. */
|
|
1460
|
+
.ds-247420 .app-main {
|
|
1461
|
+
scrollbar-width: thin; scrollbar-color: var(--rule-strong) transparent;
|
|
1462
|
+
}
|
|
1463
|
+
.ds-247420 .app-main::-webkit-scrollbar { width: 8px; }
|
|
1464
|
+
.ds-247420 .app-main::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: var(--r-pill, 999px); }
|
|
1465
|
+
.ds-247420 .app-main::-webkit-scrollbar-track { background: transparent; }
|
|
1361
1466
|
/* Jump-target anchors clear the inner-scroll top edge (no chrome overlap,
|
|
1362
1467
|
but a little breathing room when deep-linked within .app-main). */
|
|
1363
1468
|
.ds-247420 .app-main [id] { scroll-margin-top: var(--space-4); }
|
|
@@ -1367,13 +1472,41 @@
|
|
|
1367
1472
|
.ds-247420 .app-main > .ds-file-stage,
|
|
1368
1473
|
.ds-247420 .app-main > .ds-files-stack,
|
|
1369
1474
|
.ds-247420 .app-main > .grow { flex: 1 1 auto; min-height: 0; }
|
|
1370
|
-
|
|
1475
|
+
/* width:100% is load-bearing, not redundant with max-width: .app-body is a
|
|
1476
|
+
CSS grid, and margin:auto on a grid item overrides the default stretch,
|
|
1477
|
+
shrinking the item to its max-content width instead of filling the track
|
|
1478
|
+
and then clamping -- confirmed live at 2560px viewport where mainWidth
|
|
1479
|
+
measured 688px against a correctly-resolved 1400px max-width. Explicit
|
|
1480
|
+
width:100% restores fill-then-cap for every .narrow page, not just wide
|
|
1481
|
+
viewports (the shrink-to-fit bug undersized even the base 760px case). */
|
|
1482
|
+
.ds-247420 .app-main.narrow { width: 100%; max-width: var(--measure-narrow); margin: 0 auto; }
|
|
1483
|
+
/* .narrow means "prose reading measure", not "shrink the whole shell on wide
|
|
1484
|
+
screens". The old clamp(760px, 46vw, 1000px) grew too slowly to track the
|
|
1485
|
+
real available column: at 1920px viewport the .app-body grid's second
|
|
1486
|
+
track (.app width minus --sidebar-width) is ~1556px, but 46vw=883px sat
|
|
1487
|
+
well under the 1000px ceiling, leaving a ~340px dead gutter between the
|
|
1488
|
+
sidebar and the centered narrow column on an ordinary desktop screen (not
|
|
1489
|
+
just ultrawide) -- confirmed live via a real 1920x1080 CDP viewport, a
|
|
1490
|
+
project page (#/p/<slug>). 62vw tracks the actual column growth far closer
|
|
1491
|
+
(1920*0.62=1190px, much nearer the 1556px track than 883px was) while the
|
|
1492
|
+
1200px ceiling still keeps prose from stretching into an unreadable
|
|
1493
|
+
full-bleed line -- sidebar-present narrow pages read the same width class
|
|
1494
|
+
as the no-side variant below instead of visibly starving next to it. */
|
|
1495
|
+
.ds-247420 .app-body:not(.no-side) .app-main.narrow {
|
|
1496
|
+
max-width: clamp(var(--measure-narrow), 62vw, 1200px);
|
|
1497
|
+
}
|
|
1371
1498
|
/* A shell with no sidebar has no competing column, so the prose clamp there was
|
|
1372
1499
|
leaving the whole sidebar's worth of width empty -- 760px of content inside a
|
|
1373
1500
|
1413px shell on a real page. Widen the clamp by the space the absent sidebar
|
|
1374
|
-
would have taken so the measure still reads as prose, just not starved.
|
|
1501
|
+
would have taken so the measure still reads as prose, just not starved.
|
|
1502
|
+
The floor stays a fixed 980px (no-side is still readable narrow); the
|
|
1503
|
+
ceiling grows with viewport instead of staying pinned at 980px forever --
|
|
1504
|
+
on a 2560px ultrawide the old fixed value left over half the shell as dead
|
|
1505
|
+
side margin. 1400px ceiling keeps prose measure sane (nobody wants a
|
|
1506
|
+
2400px-wide paragraph) while letting non-prose content (index rows, meta)
|
|
1507
|
+
actually use the extra room. */
|
|
1375
1508
|
.ds-247420 .app-body.no-side .app-main.narrow {
|
|
1376
|
-
max-width: calc(var(--measure-narrow) + var(--sidebar-width));
|
|
1509
|
+
max-width: clamp(calc(var(--measure-narrow) + var(--sidebar-width)), 60vw, 1400px);
|
|
1377
1510
|
}
|
|
1378
1511
|
/* Article-body heading rhythm and lede spacing, consumed by flatspace-rendered
|
|
1379
1512
|
long-form pages (docs, papers) that drop headings/panels directly into .app-main. */
|
|
@@ -1426,8 +1559,16 @@
|
|
|
1426
1559
|
color: var(--fg-3);
|
|
1427
1560
|
border-top: 1px solid var(--rule);
|
|
1428
1561
|
}
|
|
1429
|
-
.ds-247420 .app-status .item { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
|
|
1562
|
+
.ds-247420 .app-status .item { color: inherit; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; display: flex; align-items: center; gap: var(--space-3); }
|
|
1430
1563
|
.ds-247420 .app-status .item:first-of-type { color: var(--accent-ink); }
|
|
1564
|
+
/* Subtle divider between adjacent status segments — a thin inset rule, not a
|
|
1565
|
+
full-height border, so it reads as a quiet separator rather than boxing
|
|
1566
|
+
each item. */
|
|
1567
|
+
.ds-247420 .app-status .item:not(:first-of-type)::before {
|
|
1568
|
+
content: ''; flex: 0 0 auto;
|
|
1569
|
+
width: 1px; height: 10px;
|
|
1570
|
+
background: var(--rule-strong);
|
|
1571
|
+
}
|
|
1431
1572
|
.ds-247420 .app-status .spread { flex: 1; }
|
|
1432
1573
|
/* The status bar NEVER wraps: at narrow widths the trailing items (hints,
|
|
1433
1574
|
agent target) drop in priority order instead of breaking mid-word onto a
|
|
@@ -1448,17 +1589,21 @@
|
|
|
1448
1589
|
color: var(--fg-3);
|
|
1449
1590
|
}
|
|
1450
1591
|
.ds-247420 .dateline span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
|
|
1451
|
-
|
|
1592
|
+
/* The spreader itself only ever set flex-basis -- an empty div with no
|
|
1593
|
+
background renders as blank space, not the "dotted spreader" the preview
|
|
1594
|
+
page's own caption describes. border-bottom (not background-image) keeps
|
|
1595
|
+
the dots crisp at 1px without a repeating-gradient banding artifact. */
|
|
1596
|
+
.ds-247420 .dateline .spread {
|
|
1597
|
+
flex: 1 1 auto; min-width: var(--space-3); align-self: stretch;
|
|
1598
|
+
display: flex; align-items: center;
|
|
1599
|
+
}
|
|
1600
|
+
.ds-247420 .dateline .spread::after {
|
|
1601
|
+
content: ''; flex: 1 1 auto;
|
|
1602
|
+
border-bottom: var(--bw-hair, 1px) dotted var(--rule-strong);
|
|
1603
|
+
}
|
|
1452
1604
|
|
|
1453
|
-
/* ============================================================
|
|
1454
|
-
Primitives
|
|
1455
|
-
============================================================ */
|
|
1456
1605
|
.ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
|
|
1457
1606
|
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
|
|
1458
|
-
/* Fixed height + horizontal-only padding: the control height is exact and
|
|
1459
|
-
alignable (flex centres the label vertically), the way webgeist snaps every
|
|
1460
|
-
control to a height ladder. Default is the --ctl-md rung; --btn-sm/--btn-lg
|
|
1461
|
-
retune height + h-padding + font per size. Density scales the ladder. */
|
|
1462
1607
|
height: var(--ctl-md); min-height: var(--ctl-md);
|
|
1463
1608
|
padding: 0 var(--space-2-75);
|
|
1464
1609
|
font-family: var(--ff-body);
|
|
@@ -1466,41 +1611,28 @@
|
|
|
1466
1611
|
text-decoration: none;
|
|
1467
1612
|
white-space: nowrap;
|
|
1468
1613
|
cursor: pointer;
|
|
1469
|
-
/* Rounded-rect app chrome, not a marketing-page stadium CTA.
|
|
1470
|
-
Shape vocabulary: r-1/r-2 = actionable buttons, icon-buttons, and
|
|
1471
|
-
containers; r-pill = reserved for status/input/chip/badge/progress
|
|
1472
|
-
surfaces (composer input, chips, badges, progress bars, theme-toggle
|
|
1473
|
-
segments) - never for actions. */
|
|
1474
1614
|
border-radius: var(--r-1);
|
|
1475
1615
|
border: var(--bw-hair) solid transparent;
|
|
1476
1616
|
box-shadow: none;
|
|
1477
|
-
/* Restrained hover-lift: a 1px rise + hairline shadow reads as a crisp,
|
|
1478
|
-
confident affordance rather than a soft glow-card float. */
|
|
1479
1617
|
transition: transform var(--dur-base) var(--ease-spring), background var(--dur-snap) var(--ease),
|
|
1480
1618
|
color var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring),
|
|
1481
1619
|
border-color var(--dur-snap) var(--ease);
|
|
1482
1620
|
}
|
|
1483
1621
|
.ds-247420 .btn { background: var(--bg-2); color: var(--fg); border-color: var(--rule); }
|
|
1484
1622
|
.ds-247420 .btn:hover { background: var(--bg-3); color: var(--fg); transform: translateY(-1px); box-shadow: var(--shadow-1); }
|
|
1485
|
-
/* Primary CTA — the electric lead as a solid editorial block; hover inverts to
|
|
1486
|
-
an ink block with the lead as text, a confident two-tone flip. */
|
|
1487
1623
|
.ds-247420 .btn-primary {
|
|
1488
|
-
background: var(--
|
|
1624
|
+
background: var(--green); color: var(--on-color);
|
|
1489
1625
|
font-weight: 700;
|
|
1490
1626
|
}
|
|
1491
|
-
.ds-247420 .btn-primary:hover { background: var(--fg); color: var(--
|
|
1627
|
+
.ds-247420 .btn-primary:hover { background: var(--fg); color: var(--green); transform: translateY(-1px); box-shadow: var(--shadow-2); }
|
|
1492
1628
|
.ds-247420 .btn-ghost { background: transparent; color: var(--fg); box-shadow: inset 0 0 0 2px var(--fg); }
|
|
1493
|
-
.ds-247420 .btn-ghost:hover { background: var(--fg)
|
|
1629
|
+
.ds-247420 .btn-ghost:hover { background: color-mix(in oklab, var(--fg) 12%, transparent); transform: translateY(-1px); }
|
|
1494
1630
|
.ds-247420 .btn:active, .ds-247420 .btn-primary:active, .ds-247420 .btn-ghost:active { transform: translateY(1px); box-shadow: none; }
|
|
1495
1631
|
.ds-247420 .btn:focus-visible, .ds-247420 .btn-primary:focus-visible, .ds-247420 .btn-ghost:focus-visible, .ds-247420 .ds-icon-btn:focus-visible {
|
|
1496
1632
|
outline: var(--focus-w) solid var(--focus-color);
|
|
1497
1633
|
outline-offset: var(--focus-offset);
|
|
1498
1634
|
}
|
|
1499
1635
|
|
|
1500
|
-
/* Button size ladder — the size prop on Btn() (sm | md | lg). md is the base
|
|
1501
|
-
rule above; sm/lg retune height (off the --ctl-* ladder), horizontal padding,
|
|
1502
|
-
and font-size so a size swap is one class, never inline padding overrides
|
|
1503
|
-
(the old preview faked sizes with style=). Applies to every variant. */
|
|
1504
1636
|
.ds-247420 .btn-sm, .ds-247420 .btn-sm.btn-primary, .ds-247420 .btn-sm.btn-ghost {
|
|
1505
1637
|
height: var(--ctl-sm); min-height: var(--ctl-sm);
|
|
1506
1638
|
padding: 0 var(--space-2); font-size: var(--fs-tiny); gap: var(--space-1);
|
|
@@ -1510,10 +1642,9 @@
|
|
|
1510
1642
|
padding: 0 var(--space-4); font-size: var(--fs-body); gap: var(--space-2);
|
|
1511
1643
|
}
|
|
1512
1644
|
|
|
1513
|
-
/* App
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
no motion, no elevation. Marketing surfaces (no data-typescale) keep the lift. */
|
|
1645
|
+
/* App chrome is compact/dense (see --fs-h1-app etc in colors_and_type.css) --
|
|
1646
|
+
the marketing-scale hover lift/shadow reads as an oversized flourish at
|
|
1647
|
+
this density, so app-typescale buttons opt out of it deliberately. */
|
|
1517
1648
|
.ds-247420[data-typescale="app"] .btn:hover,
|
|
1518
1649
|
.ds-247420[data-typescale="app"] .btn-primary:hover,
|
|
1519
1650
|
.ds-247420[data-typescale="app"] .btn-ghost:hover { transform: none; box-shadow: none; }
|
|
@@ -1524,36 +1655,38 @@
|
|
|
1524
1655
|
.ds-247420[data-typescale="app"] a.row:hover .meta,
|
|
1525
1656
|
.ds-247420[data-typescale="app"] .row[role="button"]:hover .meta { transform: none; }
|
|
1526
1657
|
|
|
1527
|
-
/* ============================================================
|
|
1528
|
-
IconButton — square icon-only button
|
|
1529
|
-
============================================================ */
|
|
1530
1658
|
.ds-247420 .ds-icon-btn {
|
|
1531
1659
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1532
1660
|
padding: 0; border: none; cursor: pointer;
|
|
1533
|
-
border-radius: var(--r-1,
|
|
1661
|
+
border-radius: var(--r-1, 8px);
|
|
1534
1662
|
background: transparent; color: var(--fg);
|
|
1535
1663
|
width: 32px; height: 32px;
|
|
1664
|
+
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
1536
1665
|
}
|
|
1666
|
+
.ds-247420 .ds-icon-btn:hover { background: var(--bg-2); }
|
|
1537
1667
|
.ds-247420 .ds-icon-btn-xs { width: 22px; height: 22px; }
|
|
1538
1668
|
.ds-247420 .ds-icon-btn-sm { width: 26px; height: 26px; }
|
|
1539
1669
|
.ds-247420 .ds-icon-btn-base { width: 32px; height: 32px; }
|
|
1540
1670
|
.ds-247420 .ds-icon-btn-lg { width: 40px; height: 40px; }
|
|
1541
1671
|
.ds-247420 .ds-icon-btn-xl { width: 48px; height: 48px; }
|
|
1672
|
+
@media (pointer: coarse) {
|
|
1673
|
+
.ds-247420 .ds-icon-btn-xs { width: 32px; height: 32px; }
|
|
1674
|
+
.ds-247420 .ds-icon-btn-sm { width: 32px; height: 32px; }
|
|
1675
|
+
}
|
|
1542
1676
|
.ds-247420 .ds-icon-btn-ghost { background: transparent; }
|
|
1543
1677
|
.ds-247420 .ds-icon-btn-ghost:hover { background: var(--fg); color: var(--bg); }
|
|
1544
1678
|
.ds-247420 .ds-icon-btn-primary { background: var(--accent); color: var(--accent-fg); }
|
|
1545
1679
|
.ds-247420 .ds-icon-btn-primary:hover { background: var(--fg); color: var(--accent-ink); }
|
|
1546
|
-
/*
|
|
1547
|
-
|
|
1680
|
+
/* --ink, not --on-color: --on-color is a fixed #fff, which measures 3.07:1 on
|
|
1681
|
+
--warn (#FF5A52) -- below the 4.5:1 AA floor. --ink measures 6.27:1. Same
|
|
1682
|
+
fix as .btn-primary.danger in app-shell/files.css. */
|
|
1683
|
+
.ds-247420 .ds-icon-btn-danger { background: var(--warn); color: var(--ink); }
|
|
1548
1684
|
.ds-247420 .ds-icon-btn-danger:hover { filter: brightness(0.92); }
|
|
1549
1685
|
.ds-247420 .ds-icon-btn:active { transform: translateY(1px); }
|
|
1550
1686
|
.ds-247420 .ds-icon-btn:disabled, .ds-247420 .ds-icon-btn.is-disabled {
|
|
1551
1687
|
opacity: 0.5; cursor: not-allowed; pointer-events: none;
|
|
1552
1688
|
}
|
|
1553
1689
|
|
|
1554
|
-
/* ============================================================
|
|
1555
|
-
Badge — small inline count/status pill
|
|
1556
|
-
============================================================ */
|
|
1557
1690
|
.ds-247420 .ds-badge {
|
|
1558
1691
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1559
1692
|
min-width: 18px; height: 18px; padding: 0 6px;
|
|
@@ -1561,18 +1694,25 @@
|
|
|
1561
1694
|
border-radius: var(--r-pill);
|
|
1562
1695
|
background: var(--bg-3); color: var(--fg-2);
|
|
1563
1696
|
}
|
|
1564
|
-
/*
|
|
1565
|
-
|
|
1566
|
-
.ds-
|
|
1697
|
+
/* --fs-nano (11px), not --fs-pico (10px): --fs-pico sits below the 11px
|
|
1698
|
+
legibility floor other small-scale labels in this system respect (see
|
|
1699
|
+
.ds-stat-lbl, .ds-session-row-id), and this size is used live for the
|
|
1700
|
+
workspace rail item-count badge (atoms.js Badge size="sm"). */
|
|
1701
|
+
.ds-247420 .ds-badge.ds-badge--sm { min-width: var(--icon-xs); height: var(--icon-xs); padding: 0 var(--space-1); font-size: var(--fs-nano); }
|
|
1567
1702
|
.ds-247420 .ds-badge.ds-badge--lg { min-width: 22px; height: 22px; padding: 0 var(--space-2); font-size: var(--fs-tiny); }
|
|
1568
|
-
|
|
1569
|
-
other tone name grouped into the same rule below (tone-green/tone-live,
|
|
1570
|
-
tone-flame, tone-wip, tone-sun/tone-yellow, tone-ok/tone-miss) is a
|
|
1571
|
-
true-synonym legacy alias, kept working but sharing one declaration so the
|
|
1572
|
-
tone-family colors can't drift apart across names. */
|
|
1573
|
-
.ds-247420 .ds-badge.tone-green, .ds-247420 .ds-badge.tone-live, .ds-247420 .ds-badge.tone-success {
|
|
1703
|
+
.ds-247420 .ds-badge.tone-green, .ds-247420 .ds-badge.tone-success {
|
|
1574
1704
|
background: var(--green-tint); color: var(--green-deep);
|
|
1575
1705
|
}
|
|
1706
|
+
/* tone-live is its own hue (sky), split out of the success/green group:
|
|
1707
|
+
"live/broadcasting now" and "operation succeeded" are different facts and
|
|
1708
|
+
read identically when both borrow the brand's accent green — a LIVE badge
|
|
1709
|
+
next to an "ok" chip must not look like the same state. --sky is already
|
|
1710
|
+
used for informational surfaces (ds-alert-info, audio-file icons) and is
|
|
1711
|
+
never pinned by the thebird brand's `--accent:var(--green)!important`
|
|
1712
|
+
override, so it stays visually distinct under every accent preset. */
|
|
1713
|
+
.ds-247420 .ds-badge.tone-live {
|
|
1714
|
+
background: color-mix(in oklab, var(--sky) 22%, var(--bg)); color: var(--sky);
|
|
1715
|
+
}
|
|
1576
1716
|
.ds-247420 .ds-badge.tone-flame, .ds-247420 .ds-badge.tone-error {
|
|
1577
1717
|
background: var(--flame); color: var(--on-color);
|
|
1578
1718
|
}
|
|
@@ -1585,7 +1725,7 @@
|
|
|
1585
1725
|
background: var(--sun); color: var(--ink);
|
|
1586
1726
|
}
|
|
1587
1727
|
.ds-247420 .ds-badge.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
|
|
1588
|
-
.ds-247420 .ds-badge.tone-orange { background: color-mix(in oklab, var(--flame)
|
|
1728
|
+
.ds-247420 .ds-badge.tone-orange { background: color-mix(in oklab, var(--flame) 22%, var(--bg)); color: var(--flame); }
|
|
1589
1729
|
|
|
1590
1730
|
.ds-247420 .chip {
|
|
1591
1731
|
display: inline-flex; align-items: center; gap: var(--space-1-75);
|
|
@@ -1596,42 +1736,55 @@
|
|
|
1596
1736
|
letter-spacing: var(--tr-caps); text-transform: uppercase;
|
|
1597
1737
|
border-radius: var(--r-pill);
|
|
1598
1738
|
}
|
|
1599
|
-
/* Chip size ladder — sm for dense toolbars/table cells, lg for prominent
|
|
1600
|
-
status. tone-* colouring (below) is orthogonal to size. */
|
|
1601
1739
|
.ds-247420 .chip.chip--sm { padding: var(--space-half) var(--space-2); font-size: var(--fs-micro); gap: var(--space-1); }
|
|
1602
1740
|
.ds-247420 .chip.chip--lg { padding: var(--space-1-75) var(--space-2-75); font-size: var(--fs-xs); }
|
|
1603
|
-
/* Tag variant — a rectangular, sentence-case chip for dense data (table cells,
|
|
1604
|
-
inline labels) where the all-caps pill reads too shouty and space-hungry.
|
|
1605
|
-
Keeps the tone-* palette; drops the caps + pill for a tight --r-0 corner. */
|
|
1606
1741
|
.ds-247420 .chip.chip--tag {
|
|
1607
1742
|
text-transform: none; letter-spacing: 0; font-weight: 500;
|
|
1608
1743
|
border-radius: var(--r-0); padding: var(--space-half) var(--space-2);
|
|
1609
1744
|
}
|
|
1610
|
-
|
|
1611
|
-
.ds-247420 .chip.tone-green, .ds-247420 .chip.tone-live, .ds-247420 .chip.tone-success, .ds-247420 .chip.tone-ok {
|
|
1745
|
+
.ds-247420 .chip.tone-green, .ds-247420 .chip.tone-success, .ds-247420 .chip.tone-ok {
|
|
1612
1746
|
background: var(--green-tint); color: var(--green-deep);
|
|
1613
1747
|
}
|
|
1748
|
+
/* tone-live: its own sky hue, split from tone-ok/tone-success — see the
|
|
1749
|
+
.ds-badge.tone-live comment above for the rationale. A small pulsing dot
|
|
1750
|
+
precedes the label so "live" reads as an active broadcast state, not a
|
|
1751
|
+
static status chip. */
|
|
1752
|
+
.ds-247420 .chip.tone-live {
|
|
1753
|
+
background: color-mix(in oklab, var(--sky) 16%, var(--bg));
|
|
1754
|
+
color: var(--sky);
|
|
1755
|
+
position: relative;
|
|
1756
|
+
padding-left: 22px;
|
|
1757
|
+
}
|
|
1758
|
+
.ds-247420 .chip.tone-live::before {
|
|
1759
|
+
content: '';
|
|
1760
|
+
position: absolute;
|
|
1761
|
+
left: 10px; top: 50%;
|
|
1762
|
+
width: 6px; height: 6px;
|
|
1763
|
+
border-radius: 50%;
|
|
1764
|
+
background: var(--sky);
|
|
1765
|
+
transform: translateY(-50%);
|
|
1766
|
+
animation: chip-live-pulse 1.6s ease-in-out infinite;
|
|
1767
|
+
}
|
|
1768
|
+
@keyframes chip-live-pulse {
|
|
1769
|
+
0%, 100% { opacity: 1; box-shadow: 0 0 0 0 color-mix(in oklab, var(--sky) 50%, transparent); }
|
|
1770
|
+
50% { opacity: 0.7; box-shadow: 0 0 0 4px transparent; }
|
|
1771
|
+
}
|
|
1772
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1773
|
+
.ds-247420 .chip.tone-live::before { animation: none; }
|
|
1774
|
+
}
|
|
1614
1775
|
.ds-247420 .chip.tone-flame, .ds-247420 .chip.tone-error, .ds-247420 .chip.tone-miss {
|
|
1615
1776
|
background: var(--flame); color: var(--on-color);
|
|
1616
1777
|
}
|
|
1778
|
+
.ds-247420 .chip.tone-warn {
|
|
1779
|
+
background: color-mix(in oklab, var(--amber) 22%, var(--bg));
|
|
1780
|
+
color: var(--amber);
|
|
1781
|
+
}
|
|
1617
1782
|
.ds-247420 .chip.tone-wip, .ds-247420 .chip.tone-neutral {
|
|
1618
1783
|
background: var(--bg-3); color: var(--fg-2);
|
|
1619
1784
|
}
|
|
1620
|
-
/* `.chip.accent` is the bare-adjective spelling of tone-accent (ui_kits/blog
|
|
1621
|
-
uses it for a "draft" chip). It had no rule anywhere, so an accented chip
|
|
1622
|
-
rendered byte-identical to a plain one. Folded into the alias grouping rather
|
|
1623
|
-
than given its own block, so the two spellings cannot drift apart. --accent
|
|
1624
|
-
is the FILL and --accent-ink the readable text tone (AGENTS.md) — the bare
|
|
1625
|
-
lead is ~1.07:1 on paper and unreadable as text. */
|
|
1626
1785
|
.ds-247420 .chip.accent, .ds-247420 .chip.tone-accent {
|
|
1627
1786
|
background: var(--accent-tint); color: var(--accent-ink);
|
|
1628
1787
|
}
|
|
1629
|
-
/* tone-dim was applied by five kits (aicat, project_page, signin, system_primer,
|
|
1630
|
-
terminal) with no rule anywhere, so a "dim" chip rendered byte-identical to a
|
|
1631
|
-
plain one — measured at rgb(234,230,218) on rgb(31,31,38), same opacity. It is
|
|
1632
|
-
the recede-into-the-row tone: the tier-3 foreground on the same recessed
|
|
1633
|
-
surface tone-wip uses, which is quieter than the default --fg-2 without
|
|
1634
|
-
dropping to an opacity fade that would take the border and background with it. */
|
|
1635
1788
|
.ds-247420 .chip.tone-dim {
|
|
1636
1789
|
background: var(--bg-3); color: var(--fg-3);
|
|
1637
1790
|
}
|
|
@@ -1643,12 +1796,7 @@
|
|
|
1643
1796
|
.ds-247420 .chip.tone-disabled { background: var(--bg-3); color: var(--fg-3); }
|
|
1644
1797
|
.ds-247420 .chip.tone-blue { background: var(--accent-tint); color: var(--accent-ink); }
|
|
1645
1798
|
.ds-247420 .chip.tone-orange { background: color-mix(in oklab, var(--flame) 30%, var(--sun) 70%); color: var(--ink); }
|
|
1646
|
-
.ds-247420 .chip.tone-yellow { background: var(--sun); color: var(--ink); }
|
|
1647
1799
|
|
|
1648
|
-
/* Removable chip — a trailing dismiss (x) button for editable tag/filter
|
|
1649
|
-
chip lists (session tags, saved-search chips). Reuses the chip's own
|
|
1650
|
-
tone/size; the button itself stays neutral-at-rest, per the standing
|
|
1651
|
-
color-reserved-for-meaning convention, tinting only on hover/focus. */
|
|
1652
1800
|
.ds-247420 .chip.ds-chip-removable { padding-right: var(--space-1); }
|
|
1653
1801
|
.ds-247420 .ds-chip-remove-btn {
|
|
1654
1802
|
display: inline-flex; align-items: center; justify-content: center;
|
|
@@ -1658,14 +1806,12 @@
|
|
|
1658
1806
|
cursor: pointer;
|
|
1659
1807
|
}
|
|
1660
1808
|
.ds-247420 .ds-chip-remove-btn:hover, .ds-247420 .ds-chip-remove-btn:focus-visible { opacity: 1; background: color-mix(in oklab, currentColor 16%, transparent); }
|
|
1661
|
-
.ds-247420 .ds-chip-remove-btn svg { width:
|
|
1809
|
+
.ds-247420 .ds-chip-remove-btn svg { width: var(--icon-xs); height: var(--icon-xs); }
|
|
1662
1810
|
@media (pointer: coarse) {
|
|
1663
1811
|
.ds-247420 .ds-chip-remove-btn { width: 24px; height: 24px; margin-left: 0; }
|
|
1664
|
-
.ds-247420 .ds-chip-remove-btn svg { width:
|
|
1812
|
+
.ds-247420 .ds-chip-remove-btn svg { width: var(--icon-xs); height: var(--icon-xs); }
|
|
1665
1813
|
}
|
|
1666
1814
|
|
|
1667
|
-
/* ds-pill — plain neutral chip, distinct from the toned .ds-badge/.chip family
|
|
1668
|
-
(gmsniff's .pill: a bare rounded label with no semantic tone). */
|
|
1669
1815
|
.ds-247420 .ds-pill {
|
|
1670
1816
|
display: inline-block;
|
|
1671
1817
|
padding: 1px 7px;
|
|
@@ -1677,26 +1823,75 @@
|
|
|
1677
1823
|
.ds-247420 .ds-pill.tone-accent { background: var(--accent-tint); color: var(--accent-ink); }
|
|
1678
1824
|
.ds-247420 .ds-pill.tone-muted { background: transparent; color: var(--fg-3); box-shadow: inset 0 0 0 1px var(--rule); }
|
|
1679
1825
|
|
|
1826
|
+
/* .glyph-* sizes (14/18/22px) are for small inline text-adjacent glyphs
|
|
1827
|
+
(single characters/icons sitting in a text flow), a different scale and
|
|
1828
|
+
purpose than the .ds-icon-btn-* tap-target scale (22/26/32/40/48px) below --
|
|
1829
|
+
the -sm/-lg naming overlap is coincidental, not a shared system. */
|
|
1680
1830
|
.ds-247420 .glyph {
|
|
1681
1831
|
display: inline-flex; align-items: center; justify-content: center;
|
|
1682
1832
|
width: 18px; height: 18px;
|
|
1683
1833
|
font-family: var(--ff-mono); font-size: var(--fs-tiny);
|
|
1684
1834
|
opacity: 0.8;
|
|
1685
1835
|
}
|
|
1686
|
-
/* Glyph() (src/components/shell/atoms.js) emits `glyph glyph-{size}` and an
|
|
1687
|
-
inline `font-size: var(--glyph-size-{size}, <literal>)`. The custom property
|
|
1688
|
-
is the documented theming hook — it is what lets a theme retune glyph scale
|
|
1689
|
-
without touching the component — but nothing declared it, so every glyph fell
|
|
1690
|
-
through to the hard-coded inline literal and the hook was inert. Declaring
|
|
1691
|
-
the three rungs on the scale makes the hook real; the sm/lg classes also give
|
|
1692
|
-
the box a matching footprint instead of the one-size 18px square. */
|
|
1693
|
-
/* Values mirror Glyph()'s own inline fallbacks exactly (11 / 13 / 16px), so
|
|
1694
|
-
declaring the hook changes nothing visually — it only makes the property
|
|
1695
|
-
themeable, which is what it always claimed to be. */
|
|
1696
1836
|
.ds-247420 .glyph { --glyph-size-sm: var(--fs-nano); --glyph-size-base: var(--fs-tiny); --glyph-size-lg: var(--fs-body); }
|
|
1697
|
-
.ds-247420 .glyph-sm { width:
|
|
1837
|
+
.ds-247420 .glyph-sm { width: var(--icon-xs); height: var(--icon-xs); }
|
|
1838
|
+
.ds-247420 .glyph-base { width: 18px; height: 18px; }
|
|
1698
1839
|
.ds-247420 .glyph-lg { width: 22px; height: 22px; }
|
|
1699
1840
|
|
|
1841
|
+
/* Shared empty-state base -- hero-content.css's .empty and community.css's
|
|
1842
|
+
.fd-empty previously duplicated this full rule set; both are joined into
|
|
1843
|
+
this selector list so the shared declarations live in one place, with
|
|
1844
|
+
each keeping its own file-local rule for context-specific extras
|
|
1845
|
+
(background/radius/font-size for .empty; padding for .fd-empty). New
|
|
1846
|
+
consumers can add .ds-empty-state directly instead of a fresh copy. */
|
|
1847
|
+
.ds-247420 .ds-empty-state, .ds-247420 .empty, .ds-247420 .fd-empty {
|
|
1848
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
1849
|
+
gap: var(--space-2);
|
|
1850
|
+
padding: var(--space-6) var(--space-3);
|
|
1851
|
+
text-align: center;
|
|
1852
|
+
color: var(--fg-3);
|
|
1853
|
+
}
|
|
1854
|
+
.ds-247420 .ds-empty-state--panel { background: var(--bg-2); border-radius: var(--r-1); }
|
|
1855
|
+
.ds-247420 .ds-empty-state--compact { padding: var(--space-5) var(--space-3); }
|
|
1856
|
+
|
|
1857
|
+
/* .ds-tooltip — shared floating bubble (overlay-primitives/tooltip.js appends
|
|
1858
|
+
one instance to <body> and repositions it via useFloating). Fade timing
|
|
1859
|
+
matches the component's own 350ms hover-intent delay. */
|
|
1860
|
+
.ds-247420 .ds-tooltip {
|
|
1861
|
+
position: fixed;
|
|
1862
|
+
z-index: var(--z-top);
|
|
1863
|
+
max-width: 240px;
|
|
1864
|
+
padding: var(--space-1) var(--space-2);
|
|
1865
|
+
border-radius: var(--r-1);
|
|
1866
|
+
background: var(--fg);
|
|
1867
|
+
color: var(--bg);
|
|
1868
|
+
font-size: var(--fs-xs);
|
|
1869
|
+
line-height: 1.35;
|
|
1870
|
+
box-shadow: var(--shadow-2);
|
|
1871
|
+
pointer-events: none;
|
|
1872
|
+
opacity: 0;
|
|
1873
|
+
transform: scale(0.96);
|
|
1874
|
+
transition: opacity var(--dur-snap) var(--ease), transform var(--dur-snap) var(--ease);
|
|
1875
|
+
}
|
|
1876
|
+
.ds-247420 .ds-tooltip:not([hidden]) { opacity: 1; transform: scale(1); }
|
|
1877
|
+
.ds-247420 .ds-tooltip::after {
|
|
1878
|
+
content: '';
|
|
1879
|
+
position: absolute;
|
|
1880
|
+
width: 6px;
|
|
1881
|
+
height: 6px;
|
|
1882
|
+
background: var(--fg);
|
|
1883
|
+
transform: rotate(45deg);
|
|
1884
|
+
}
|
|
1885
|
+
.ds-247420 .ds-tooltip[data-placement^="top"]::after { bottom: -3px; left: 50%; margin-left: -3px; }
|
|
1886
|
+
.ds-247420 .ds-tooltip[data-placement^="bottom"]::after { top: -3px; left: 50%; margin-left: -3px; }
|
|
1887
|
+
.ds-247420 .ds-tooltip[data-placement^="left"]::after { right: -3px; top: 50%; margin-top: -3px; }
|
|
1888
|
+
.ds-247420 .ds-tooltip[data-placement^="right"]::after { left: -3px; top: 50%; margin-top: -3px; }
|
|
1889
|
+
.ds-247420 .ds-tooltip.kind-danger { background: var(--warn); color: var(--ink); }
|
|
1890
|
+
.ds-247420 .ds-tooltip.kind-danger::after { background: var(--warn); }
|
|
1891
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1892
|
+
.ds-247420 .ds-tooltip { transition: none; }
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1700
1895
|
/* ============================================================
|
|
1701
1896
|
Panel — soft tonal container, no border decoration
|
|
1702
1897
|
============================================================ */
|
|
@@ -1758,9 +1953,19 @@
|
|
|
1758
1953
|
font-size: var(--fs-tiny); font-weight: 600;
|
|
1759
1954
|
color: var(--fg-3);
|
|
1760
1955
|
letter-spacing: var(--tr-caps); text-transform: uppercase;
|
|
1956
|
+
/* A hairline divider is the header's only structural separator from the
|
|
1957
|
+
body — without it, an uppercase caps label at fs-tiny/600 reads as just
|
|
1958
|
+
another dim meta line once the eye drops past the top of the panel. */
|
|
1959
|
+
border-bottom: var(--bw-hair) solid var(--rule);
|
|
1960
|
+
margin-bottom: var(--space-1);
|
|
1761
1961
|
}
|
|
1762
1962
|
.ds-247420 .panel.panel-wide .panel-head { padding-left: 0; padding-right: 0; }
|
|
1763
|
-
|
|
1963
|
+
/* A borderless .panel-wide (no card edge to lean on) would otherwise show a
|
|
1964
|
+
divider floating with nothing to visually anchor it — drop it there and
|
|
1965
|
+
rely on spacing alone, matching panel-wide's already-transparent chrome. */
|
|
1966
|
+
.ds-247420 .panel.panel-wide .panel-head { border-bottom: none; margin-bottom: 0; }
|
|
1967
|
+
.ds-247420 .panel.panel--dense .panel-head { border-bottom: var(--bw-hair) solid var(--rule); margin-bottom: 0; }
|
|
1968
|
+
.ds-247420 .panel-head > :last-child:not(.ds-badge) {
|
|
1764
1969
|
font-weight: 500; color: var(--fg-3);
|
|
1765
1970
|
font-family: var(--ff-mono); letter-spacing: 0;
|
|
1766
1971
|
}
|
|
@@ -1772,6 +1977,13 @@
|
|
|
1772
1977
|
margin: 0; font: inherit; font-size: inherit; font-weight: inherit;
|
|
1773
1978
|
letter-spacing: inherit; text-transform: inherit; color: inherit;
|
|
1774
1979
|
}
|
|
1980
|
+
/* Category glyph beside a panel title (kits / previews / decks / docs on the
|
|
1981
|
+
homepage) — same inline-svg vocabulary as icons.js, sized to sit on the
|
|
1982
|
+
text baseline rather than dominating it. */
|
|
1983
|
+
.ds-247420 .ds-panel-title-glyph {
|
|
1984
|
+
display: inline-flex; align-items: center; gap: var(--space-1-5, 6px);
|
|
1985
|
+
}
|
|
1986
|
+
.ds-247420 .ds-panel-title-glyph .ds-icon { flex-shrink: 0; color: var(--fg-3); }
|
|
1775
1987
|
.ds-247420 .panel-body { padding: var(--space-2) var(--space-3) var(--space-3); }
|
|
1776
1988
|
.ds-247420 .panel-body > * { margin: 0; }
|
|
1777
1989
|
/* One-line explanatory caption under a panel's title — e.g. distinguishing
|
|
@@ -1812,6 +2024,14 @@
|
|
|
1812
2024
|
transition: background var(--dur-snap) var(--ease), box-shadow var(--dur-base) var(--ease-spring);
|
|
1813
2025
|
}
|
|
1814
2026
|
.ds-247420 .row + .row { margin-top: 2px; }
|
|
2027
|
+
/* Mobile tap-target floor: at compact/comfortable density on a touch
|
|
2028
|
+
viewport the padding-only row height can fall under the 44px effective
|
|
2029
|
+
tap target (WCAG 2.5.5), especially at [data-density="compact"] (0.75x).
|
|
2030
|
+
Force a min-height on narrow/coarse-pointer viewports only, so the dense
|
|
2031
|
+
desktop mono/list layout (file-row, index-row) is untouched above 640px. */
|
|
2032
|
+
@media (max-width: 640px), (pointer: coarse) {
|
|
2033
|
+
.ds-247420 .row, .ds-247420 a.row, .ds-247420 button.row, .ds-247420 .row[role="button"] { min-height: 44px; }
|
|
2034
|
+
}
|
|
1815
2035
|
/* Interactive rows (anchor/button wrappers) get a hairline lift on hover,
|
|
1816
2036
|
matching the btn/panel elevation language — non-interactive rows (plain
|
|
1817
2037
|
divs used as static list items) are unaffected since the selector needs a
|
|
@@ -2046,6 +2266,12 @@
|
|
|
2046
2266
|
padding-bottom: var(--space-2); border-bottom: var(--bw-hair) solid var(--bg-3);
|
|
2047
2267
|
}
|
|
2048
2268
|
.ds-247420 .ds-hero-stat:last-child { border-bottom: 0; padding-bottom: 0; }
|
|
2269
|
+
/* HeroFromPageData's richer badge shape ({label, desc}) renders a strong
|
|
2270
|
+
figure plus a muted descriptor inside the same .ds-hero-stat row — give
|
|
2271
|
+
the pair a baseline-aligned inline layout instead of falling back to
|
|
2272
|
+
unstyled default inline flow. */
|
|
2273
|
+
.ds-247420 .ds-hero-stat-n { font-weight: 700; color: var(--fg); margin-right: var(--space-2); }
|
|
2274
|
+
.ds-247420 .ds-hero-stat-l { color: var(--fg-3); font-size: var(--fs-xs); }
|
|
2049
2275
|
.ds-247420 .ds-hero-title {
|
|
2050
2276
|
font-family: var(--ff-display); font-weight: 700;
|
|
2051
2277
|
/* Bespoke display clamp, deliberately off the --fs-* ladder: --fs-hero is
|
|
@@ -2054,7 +2280,12 @@
|
|
|
2054
2280
|
still fits a narrow column, and a 116px ceiling between the two tiers.
|
|
2055
2281
|
Snapping to either changes the hero's whole optical weight. */
|
|
2056
2282
|
font-size: clamp(40px, 9cqi, 116px);
|
|
2057
|
-
|
|
2283
|
+
/* 0.96 let ascenders/descenders visibly touch between wrapped lines at the
|
|
2284
|
+
upper end of this clamp (measured on "the creative department of the
|
|
2285
|
+
internet" at the 116px ceiling) -- 1.02 keeps the tight, no-air display
|
|
2286
|
+
feel this title wants while clearing enough vertical room that letters
|
|
2287
|
+
stop colliding. */
|
|
2288
|
+
line-height: 1.02; letter-spacing: var(--tr-tighter);
|
|
2058
2289
|
margin: 0; max-width: 20ch; text-wrap: balance;
|
|
2059
2290
|
}
|
|
2060
2291
|
.ds-247420 .ds-hero-body {
|
|
@@ -2066,8 +2297,20 @@
|
|
|
2066
2297
|
.ds-247420 .ds-hero-accent { color: var(--accent-ink); font-weight: 700; }
|
|
2067
2298
|
.ds-247420 .ds-hero-actions {
|
|
2068
2299
|
display: flex; gap: var(--space-2, 10px); flex-wrap: wrap;
|
|
2069
|
-
justify-content: flex-start; margin-top: var(--space-
|
|
2070
|
-
}
|
|
2300
|
+
justify-content: flex-start; margin-top: var(--space-4);
|
|
2301
|
+
}
|
|
2302
|
+
/* Hero CTA labels are content-driven (e.g. "GitHub", proper nouns from
|
|
2303
|
+
home.yaml) and the site's voice is deliberately all-lowercase everywhere
|
|
2304
|
+
else. Force the rendered case here rather than hand-lowercasing every
|
|
2305
|
+
proper-noun label at the content layer, so a future CTA label doesn't
|
|
2306
|
+
silently reintroduce Title Case. */
|
|
2307
|
+
.ds-247420 .ds-hero-actions .btn { text-transform: lowercase; }
|
|
2308
|
+
/* Filter input above the homepage's "ui kits" panel — reuses the same
|
|
2309
|
+
.input token the search kit's own topbar query box uses, just placed
|
|
2310
|
+
inline above the panel instead of in a topbar slot. */
|
|
2311
|
+
.ds-247420 .ds-kits-panel-wrap { display: flex; flex-direction: column; gap: var(--space-2, 10px); }
|
|
2312
|
+
.ds-247420 .ds-kits-filter { display: flex; }
|
|
2313
|
+
.ds-247420 .ds-kits-filter-input { width: 100%; max-width: 32ch; }
|
|
2071
2314
|
/* Below this width the aside card's own internal rhythm (stat rows still
|
|
2072
2315
|
stacked vertically at full width) is already correct for a narrow column —
|
|
2073
2316
|
no separate breakpoint override needed now that .ds-hero is always a
|
|
@@ -2141,12 +2384,15 @@
|
|
|
2141
2384
|
padding: var(--space-2) 0;
|
|
2142
2385
|
font-family: var(--ff-display); font-weight: 600;
|
|
2143
2386
|
text-transform: uppercase; letter-spacing: var(--tr-caps);
|
|
2387
|
+
mask-image: linear-gradient(90deg, transparent 0, var(--fg) 28px, var(--fg) calc(100% - 28px), transparent 100%);
|
|
2388
|
+
-webkit-mask-image: linear-gradient(90deg, transparent 0, var(--fg) 28px, var(--fg) calc(100% - 28px), transparent 100%);
|
|
2144
2389
|
}
|
|
2145
2390
|
.ds-247420 .ds-marquee-track {
|
|
2146
2391
|
display: inline-flex; gap: var(--space-5);
|
|
2147
2392
|
white-space: nowrap; will-change: transform;
|
|
2148
2393
|
animation: ds-marquee-run 28s linear infinite;
|
|
2149
2394
|
}
|
|
2395
|
+
.ds-247420 .ds-marquee-run { display: inline-flex; align-items: center; gap: var(--space-5); }
|
|
2150
2396
|
.ds-247420 .ds-marquee-item { display: inline-flex; align-items: center; gap: var(--space-5); }
|
|
2151
2397
|
.ds-247420 .ds-marquee-sep { color: var(--accent-ink); }
|
|
2152
2398
|
.ds-247420 .ds-marquee:hover .ds-marquee-track,
|
|
@@ -2172,7 +2418,7 @@
|
|
|
2172
2418
|
.ds-247420 .cli {
|
|
2173
2419
|
display: flex; align-items: center; gap: 14px;
|
|
2174
2420
|
overflow-x: auto;
|
|
2175
|
-
padding:
|
|
2421
|
+
padding: var(--space-3-5) var(--space-4);
|
|
2176
2422
|
background: var(--ink); color: var(--paper);
|
|
2177
2423
|
border-radius: var(--r-3);
|
|
2178
2424
|
font-family: var(--ff-mono); font-size: var(--fs-lg);
|
|
@@ -2180,12 +2426,13 @@
|
|
|
2180
2426
|
.ds-247420 .cli .prompt { color: var(--green-2); }
|
|
2181
2427
|
.ds-247420 .cli .cmd { flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; color: var(--paper); }
|
|
2182
2428
|
.ds-247420 .cli .copy {
|
|
2183
|
-
padding:
|
|
2429
|
+
padding: var(--space-2) var(--space-3); background: transparent; color: var(--paper);
|
|
2184
2430
|
font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: var(--tr-caps);
|
|
2185
2431
|
cursor: pointer; box-shadow: inset 0 0 0 1px var(--rule-strong);
|
|
2186
2432
|
border-radius: var(--r-pill);
|
|
2187
2433
|
}
|
|
2188
2434
|
.ds-247420 .cli .copy:hover { background: var(--fg-3); }
|
|
2435
|
+
.ds-247420 .cli .copy:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
2189
2436
|
|
|
2190
2437
|
/* Multi-line CLI block: when .cli holds .ds-cli-row / .ds-cli-comment children
|
|
2191
2438
|
(quickstart scripts, multi-command snippets — see CliBlock in
|
|
@@ -2202,12 +2449,32 @@
|
|
|
2202
2449
|
padding: 3px 0;
|
|
2203
2450
|
}
|
|
2204
2451
|
.ds-247420 .ds-cli-row .prompt { color: var(--green-2); flex: 0 0 auto; user-select: none; }
|
|
2205
|
-
|
|
2452
|
+
/* `overflow-wrap: break-word` only breaks a token when it genuinely cannot
|
|
2453
|
+
fit the line at all (last resort); `word-break: break-word` (its
|
|
2454
|
+
predecessor here) breaks ANY overflowing token eagerly, which is what
|
|
2455
|
+
split "anentrypoint-design" mid-identifier inside the importmap JSON line.
|
|
2456
|
+
`min-width: 0` lets the flex child actually shrink to trigger wrapping
|
|
2457
|
+
instead of pushing the panel wider. */
|
|
2458
|
+
.ds-247420 .ds-cli-row .cmd { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; overflow-wrap: break-word; word-break: normal; color: var(--paper); }
|
|
2206
2459
|
.ds-247420 .ds-cli-comment {
|
|
2207
2460
|
color: var(--fg-3);
|
|
2208
2461
|
font-family: var(--ff-mono); font-size: var(--fs-tiny); line-height: 1.6;
|
|
2209
|
-
padding: 3px 0; white-space: pre-wrap;
|
|
2462
|
+
padding: 3px 0; white-space: pre-wrap; overflow-wrap: break-word; word-break: normal;
|
|
2463
|
+
}
|
|
2464
|
+
|
|
2465
|
+
/* Quickstart copy button: sits below the multi-line block (Install's inline
|
|
2466
|
+
copy button assumes a single-line row with room beside it; the stacked
|
|
2467
|
+
quickstart block has no such side room). */
|
|
2468
|
+
.ds-247420 .ds-quickstart-cli { flex-direction: column; align-items: stretch; gap: var(--space-2); }
|
|
2469
|
+
.ds-247420 .ds-quickstart-copy {
|
|
2470
|
+
align-self: flex-end;
|
|
2471
|
+
padding: var(--space-2) var(--space-3); background: transparent; color: var(--paper);
|
|
2472
|
+
font-family: var(--ff-mono); font-size: var(--fs-tiny); text-transform: uppercase; letter-spacing: var(--tr-caps);
|
|
2473
|
+
cursor: pointer; box-shadow: inset 0 0 0 1px var(--rule-strong);
|
|
2474
|
+
border-radius: var(--r-pill); border: none;
|
|
2210
2475
|
}
|
|
2476
|
+
.ds-247420 .ds-quickstart-copy:hover { background: var(--fg-3); }
|
|
2477
|
+
.ds-247420 .ds-quickstart-copy:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
2211
2478
|
|
|
2212
2479
|
/* ============================================================
|
|
2213
2480
|
Receipt — key/value table
|
|
@@ -2257,13 +2524,27 @@
|
|
|
2257
2524
|
(was 12/14 x 16 => ~43px rows). Density scales the vertical padding. */
|
|
2258
2525
|
border-radius: var(--r-0); overflow: hidden;
|
|
2259
2526
|
}
|
|
2527
|
+
/* Panel heads / KPI labels / table headers were all identical uppercase-
|
|
2528
|
+
tracked-mono weight (600), so a page with several of these side by side
|
|
2529
|
+
(a dashboard) reads as one flat volume with no anchor -- the most
|
|
2530
|
+
repetitive, least-singular label (a column header, one of many per
|
|
2531
|
+
table) drops to a lighter 500 with slightly tighter tracking, keeping the
|
|
2532
|
+
system's uppercase-mono voice but giving panel titles (still 600) a real
|
|
2533
|
+
step up as the "read this first" tier. */
|
|
2260
2534
|
.ds-247420 table th {
|
|
2261
2535
|
text-align: left;
|
|
2262
2536
|
padding: calc(var(--space-2) * var(--density)) var(--space-2-75);
|
|
2263
|
-
font-size: var(--fs-tiny); font-weight:
|
|
2264
|
-
color: var(--fg-3); text-transform: uppercase; letter-spacing: var(--tr-caps);
|
|
2537
|
+
font-size: var(--fs-tiny); font-weight: 500;
|
|
2538
|
+
color: var(--fg-3); text-transform: uppercase; letter-spacing: calc(var(--tr-caps) * 0.7);
|
|
2265
2539
|
background: var(--bg-2);
|
|
2266
2540
|
}
|
|
2541
|
+
/* letter-spacing adds trailing space AFTER the last glyph too, but the table's
|
|
2542
|
+
own border-radius+overflow:hidden (above) clips flush to the card edge --
|
|
2543
|
+
the last header's positive tracking bleeds past its own padding box and
|
|
2544
|
+
gets cropped mid-word ("STATUS" -> "STATI"). Absorb that bleed with a bit
|
|
2545
|
+
of extra right padding on the last column only, so no header text sits
|
|
2546
|
+
closer to the clip edge than --tr-caps can push it. */
|
|
2547
|
+
.ds-247420 table th:last-child { padding-right: calc(var(--space-2-75) + var(--tr-caps, 0px)); }
|
|
2267
2548
|
.ds-247420 table td { padding: calc(var(--space-2) * var(--density)) var(--space-2-75); border-top: 1px solid var(--rule); }
|
|
2268
2549
|
.ds-247420 table tr.clickable { cursor: pointer; }
|
|
2269
2550
|
.ds-247420 table tr.clickable:hover td { background: var(--bg-2); }
|
|
@@ -2272,6 +2553,12 @@
|
|
|
2272
2553
|
outline-offset: -2px;
|
|
2273
2554
|
}
|
|
2274
2555
|
.ds-247420 table tr.clickable:focus-visible td { background: var(--bg-2); }
|
|
2556
|
+
/* Non-clickable (static) rows still get a subtle hover cue — most dashboard
|
|
2557
|
+
tables (freddie's sessions-by-platform/model, tool distribution, commands)
|
|
2558
|
+
never pass onRowClick, so they had zero row-hover feedback at all. A dim
|
|
2559
|
+
hover on ANY row (not just .clickable) reads as "you're scanning this
|
|
2560
|
+
row" without implying it's actionable. */
|
|
2561
|
+
.ds-247420 table tr:not(.clickable):hover td { background: color-mix(in oklab, var(--bg-2) 60%, transparent); }
|
|
2275
2562
|
|
|
2276
2563
|
/* Table() striped/compact opt-in density modifiers (webgeist g-table parity).
|
|
2277
2564
|
Scoped under .ds-table-wrap so they never leak onto an unrelated bare
|
|
@@ -2279,8 +2566,15 @@
|
|
|
2279
2566
|
.ds-247420 .ds-table-wrap.is-striped table tr:nth-child(even) td { background: var(--bg-2); }
|
|
2280
2567
|
.ds-247420 .ds-table-wrap.is-striped table tr.clickable:nth-child(even):hover td,
|
|
2281
2568
|
.ds-247420 .ds-table-wrap.is-striped table tr.clickable:nth-child(even):focus-visible td { background: var(--bg-3, var(--bg-2)); }
|
|
2569
|
+
.ds-247420 .ds-table-wrap.is-striped table tr:not(.clickable):nth-child(even):hover td { background: color-mix(in oklab, var(--bg-3, var(--bg-2)) 60%, transparent); }
|
|
2282
2570
|
.ds-247420 .ds-table-wrap.is-compact table th { padding: var(--space-1-5, 5px) var(--space-2, 8px); }
|
|
2283
2571
|
.ds-247420 .ds-table-wrap.is-compact table td { padding: var(--space-1-5, 5px) var(--space-2, 8px); }
|
|
2572
|
+
/* Numeric-column right-alignment: Table() (content/table.js) tags a cell
|
|
2573
|
+
td.is-num when its raw content is a plain integer/decimal, so digit
|
|
2574
|
+
columns (session counts, tool counts, etc.) line up on the ones place
|
|
2575
|
+
instead of ragged-left like prose columns. th.is-num mirrors it on the
|
|
2576
|
+
matching header so the label sits over its column. */
|
|
2577
|
+
.ds-247420 table td.is-num, .ds-247420 table th.is-num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
2284
2578
|
|
|
2285
2579
|
/* ============================================================
|
|
2286
2580
|
Changelog
|
|
@@ -2343,7 +2637,10 @@
|
|
|
2343
2637
|
.ds-247420 .ds-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex-shrink: 0; vertical-align: middle; }
|
|
2344
2638
|
.ds-247420 .ds-dot-on { color: var(--green-2); }
|
|
2345
2639
|
.ds-247420 .ds-dot-off { color: var(--fg-3); }
|
|
2346
|
-
|
|
2640
|
+
/* live is a distinct hue from a plain "on" dot — see .chip.tone-live's
|
|
2641
|
+
comment for the success-vs-live rationale. */
|
|
2642
|
+
.ds-247420 .ds-dot-live { color: var(--sky); }
|
|
2643
|
+
.ds-247420 .ds-dot-warn { color: var(--amber); }
|
|
2347
2644
|
.ds-247420 .ds-dot-idle { color: var(--fg-3); }
|
|
2348
2645
|
|
|
2349
2646
|
/* ============================================================
|
|
@@ -2360,6 +2657,37 @@
|
|
|
2360
2657
|
padding: var(--space-3);
|
|
2361
2658
|
background: var(--bg-2);
|
|
2362
2659
|
border-radius: var(--r-1);
|
|
2660
|
+
/* A thin border + hover elevation gives the tile real edges and a "this is
|
|
2661
|
+
a distinct object" affordance instead of a flat color patch that blends
|
|
2662
|
+
into the surrounding panel — matches the "no border, no hover state"
|
|
2663
|
+
gap named against the stat tiles. */
|
|
2664
|
+
border: 1px solid var(--rule);
|
|
2665
|
+
position: relative;
|
|
2666
|
+
transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
|
|
2667
|
+
}
|
|
2668
|
+
.ds-247420 .kpi-card:hover {
|
|
2669
|
+
border-color: color-mix(in oklab, var(--accent) 40%, var(--rule));
|
|
2670
|
+
transform: translateY(-1px);
|
|
2671
|
+
box-shadow: var(--shadow-1, 0 2px 8px rgba(0,0,0,.12));
|
|
2672
|
+
}
|
|
2673
|
+
/* Number+caption stack, isolated from .kpi-foot below it. Previously the
|
|
2674
|
+
number and label were plain block children of .kpi-card with the label's
|
|
2675
|
+
own margin-top providing the gap — visually fine for a single card, but
|
|
2676
|
+
across a row of four the caption's WRAPPED height (one line vs two, e.g.
|
|
2677
|
+
"requests · 24h" vs "error rate · 5xx+4xx") pushed .kpi-foot down by a
|
|
2678
|
+
different amount per card, so the deltas/sparklines never lined up on one
|
|
2679
|
+
shared baseline. A dedicated flex column groups exactly the two elements
|
|
2680
|
+
that must stay glued together, independent of whatever sits below. */
|
|
2681
|
+
.ds-247420 .kpi-stack {
|
|
2682
|
+
display: flex; flex-direction: column; align-items: flex-start;
|
|
2683
|
+
}
|
|
2684
|
+
.ds-247420 .kpi-glyph {
|
|
2685
|
+
position: absolute;
|
|
2686
|
+
top: var(--space-2);
|
|
2687
|
+
right: var(--space-2);
|
|
2688
|
+
color: var(--fg-3);
|
|
2689
|
+
opacity: 0.6;
|
|
2690
|
+
display: inline-flex;
|
|
2363
2691
|
}
|
|
2364
2692
|
.ds-247420 .kpi-card .num {
|
|
2365
2693
|
font-family: var(--ff-body); font-weight: 600;
|
|
@@ -2383,10 +2711,13 @@
|
|
|
2383
2711
|
display: inline-flex; align-items: center; gap: var(--space-hair);
|
|
2384
2712
|
font-size: var(--fs-xs); font-weight: 600;
|
|
2385
2713
|
}
|
|
2714
|
+
/* --green, not --success (--green-2): --success measures 3.2:1 on --paper-2,
|
|
2715
|
+
below the 4.5:1 AA floor for text -- --success is tuned for non-text uses
|
|
2716
|
+
(fills/backgrounds, where 3:1 suffices), --green clears 5.2:1 as text. */
|
|
2386
2717
|
.ds-247420 .kpi-delta-up { color: var(--green); }
|
|
2387
2718
|
.ds-247420 .kpi-delta-down { color: var(--danger); }
|
|
2388
2719
|
.ds-247420 .ds-sparkline path { stroke: currentColor; }
|
|
2389
|
-
.ds-247420 .ds-sparkline-up { color: var(--
|
|
2720
|
+
.ds-247420 .ds-sparkline-up { color: var(--green); }
|
|
2390
2721
|
.ds-247420 .ds-sparkline-down { color: var(--danger); }
|
|
2391
2722
|
|
|
2392
2723
|
/* ============================================================
|
|
@@ -2417,13 +2748,12 @@
|
|
|
2417
2748
|
/* ============================================================
|
|
2418
2749
|
Empty state
|
|
2419
2750
|
============================================================ */
|
|
2751
|
+
/* Shares its base declarations with .ds-empty-state (primitives.css) via the
|
|
2752
|
+
combined selector there -- .empty only adds its own font-size/background/
|
|
2753
|
+
radius modifiers on top. Was --space-8 (96px) padding; --space-6 (48px)
|
|
2754
|
+
still centres a message with air without the empty state dominating the
|
|
2755
|
+
fold. */
|
|
2420
2756
|
.ds-247420 .empty {
|
|
2421
|
-
/* Was --space-8 (96px) — an empty list spent 192px of vertical space on
|
|
2422
|
-
nothing. --space-6 (48px) still centres a message with air, without the
|
|
2423
|
-
empty state dominating the fold. Mobile drops it further (below). */
|
|
2424
|
-
padding: var(--space-6);
|
|
2425
|
-
text-align: center;
|
|
2426
|
-
color: var(--fg-3);
|
|
2427
2757
|
background: var(--bg-2);
|
|
2428
2758
|
border-radius: var(--r-1);
|
|
2429
2759
|
font-size: var(--fs-sm);
|
|
@@ -2433,18 +2763,40 @@
|
|
|
2433
2763
|
Form
|
|
2434
2764
|
============================================================ */
|
|
2435
2765
|
.ds-247420 .row-form {
|
|
2436
|
-
display: grid; gap:
|
|
2766
|
+
display: grid; gap: var(--space-2-75);
|
|
2437
2767
|
padding: var(--space-5);
|
|
2438
2768
|
background: var(--bg-2);
|
|
2439
2769
|
border-radius: var(--r-3);
|
|
2440
|
-
|
|
2770
|
+
/* Grid's default justify-items:stretch was silently stretching the submit
|
|
2771
|
+
* button (a direct grid child, same as every input) to the full column
|
|
2772
|
+
* width -- other primary buttons elsewhere (e.g. session-ui's "new
|
|
2773
|
+
* session") are inline/compact by contrast, since they're not grid
|
|
2774
|
+
* children. justify-self:start keeps inputs/textareas at their natural
|
|
2775
|
+
* grid-stretched width (a form field SHOULD fill its column) while the
|
|
2776
|
+
* submit button sizes to its own content, matching the compact convention
|
|
2777
|
+
* used everywhere else primary buttons appear. */
|
|
2778
|
+
}
|
|
2779
|
+
.ds-247420 .row-form > button[type="submit"] { justify-self: start; }
|
|
2441
2780
|
.ds-247420 .row-form input,
|
|
2442
2781
|
.ds-247420 .row-form textarea {
|
|
2443
2782
|
font-family: inherit; font-size: var(--fs-sm);
|
|
2444
2783
|
padding: 12px 16px;
|
|
2445
|
-
|
|
2784
|
+
/* --bg here previously resolved to the SAME color as .row-form's own
|
|
2785
|
+
* --bg-2 background in the dark theme, leaving only a 14%-opacity
|
|
2786
|
+
* currentColor ring (var(--rule)) as the sole edge between an input and
|
|
2787
|
+
* the panel behind it -- effectively invisible. --bg-3 (one step darker
|
|
2788
|
+
* than the panel) plus a stronger border restores a real, panel-distinct
|
|
2789
|
+
* field surface.
|
|
2790
|
+
* LOAD-BEARING !important: `.row-form input` and states-interactions.css's
|
|
2791
|
+
* bare `input[type="text"]:where(...)` rule are both (0,1,1) specificity
|
|
2792
|
+
* (the :where() wrapper there is intentionally zero-specificity) --
|
|
2793
|
+
* states-interactions.css @imports AFTER this file in app-shell.css, so on
|
|
2794
|
+
* this exact tie it wins by source order and silently discarded these two
|
|
2795
|
+
* declarations. Only !important beats that without restructuring the
|
|
2796
|
+
* shared bare-input rule's own selector, which many other consumers rely on. */
|
|
2797
|
+
background: var(--bg-3) !important; color: var(--fg);
|
|
2446
2798
|
border: 0; border-radius: var(--r-2);
|
|
2447
|
-
box-shadow: inset 0 0 0 1px
|
|
2799
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, currentColor 28%, transparent) !important;
|
|
2448
2800
|
}
|
|
2449
2801
|
.ds-247420 .row-form input:focus-visible,
|
|
2450
2802
|
.ds-247420 .row-form textarea:focus-visible { box-shadow: var(--focus-ring-inset); }
|
|
@@ -2466,6 +2818,19 @@
|
|
|
2466
2818
|
Responsive Design — Mobile (480px), Tablet (1024px), Desktop (1440px+)
|
|
2467
2819
|
============================================================ */
|
|
2468
2820
|
|
|
2821
|
+
/* Breakpoint reference (CSS custom properties can't be used in @media queries,
|
|
2822
|
+
so these are documented here for consistency — always use these exact values):
|
|
2823
|
+
- Mobile/tablet boundary: 768px (max-width) — used for compact nav/sidebar
|
|
2824
|
+
collapse (catalog-theme.css, sidebar-misc.css). Note: kits-appended.css
|
|
2825
|
+
uses 760px for the same kind of collapse in a few places — a near-miss
|
|
2826
|
+
of this value, worth aligning to 768px when touched.
|
|
2827
|
+
- Tablet/desktop boundary: 900px (max-width) / 901px (min-width) — used for
|
|
2828
|
+
main layout reflow (hero-content.css, responsive2-workspace.css)
|
|
2829
|
+
- Tablet landscape band: 768px–1024px (min-width 768px / max-width 1024px) —
|
|
2830
|
+
used in this file (responsive.css) for a specific tablet treatment;
|
|
2831
|
+
aligned to the 768px mobile/tablet boundary above (was 481px, a near-miss).
|
|
2832
|
+
*/
|
|
2833
|
+
|
|
2469
2834
|
/* --------------------------------------------------------------------
|
|
2470
2835
|
Mobile Portrait Breakpoint (480px and below)
|
|
2471
2836
|
---------------------------------------------------------------------- */
|
|
@@ -2540,8 +2905,7 @@
|
|
|
2540
2905
|
.ds-247420 .app .row.ds-changelog-row { grid-template-columns: minmax(70px, 10ch) minmax(0, 1fr) !important; }
|
|
2541
2906
|
.ds-247420 .ds-changelog-row .title { grid-column: 1 / -1; }
|
|
2542
2907
|
|
|
2543
|
-
|
|
2544
|
-
.ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
|
|
2908
|
+
.ds-247420 .btn:not(.btn-sm):not(.btn-lg), .ds-247420 .btn-primary:not(.btn-sm):not(.btn-lg), .ds-247420 .btn-ghost:not(.btn-sm):not(.btn-lg) {
|
|
2545
2909
|
/* 11px vertical is optical, not scale drift: --space-2-75 (12) would tip
|
|
2546
2910
|
the intrinsic box past the 44px min-height floor below and make the
|
|
2547
2911
|
floor dead, changing the mobile button rhythm. */
|
|
@@ -2644,7 +3008,7 @@
|
|
|
2644
3008
|
/* --------------------------------------------------------------------
|
|
2645
3009
|
Tablet Landscape Breakpoint (768px to 1024px)
|
|
2646
3010
|
---------------------------------------------------------------------- */
|
|
2647
|
-
@media (min-width:
|
|
3011
|
+
@media (min-width: 768px) and (max-width: 1024px) {
|
|
2648
3012
|
/* App Layout — side handled by 900px drawer block; restore for 901-1024 */
|
|
2649
3013
|
.ds-247420 .app-side a {
|
|
2650
3014
|
padding: var(--space-2-75) var(--space-2-75); gap: var(--space-2);
|
|
@@ -2707,8 +3071,7 @@
|
|
|
2707
3071
|
gap: var(--space-3);
|
|
2708
3072
|
}
|
|
2709
3073
|
|
|
2710
|
-
|
|
2711
|
-
.ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost {
|
|
3074
|
+
.ds-247420 .btn:not(.btn-sm):not(.btn-lg), .ds-247420 .btn-primary:not(.btn-sm):not(.btn-lg), .ds-247420 .btn-ghost:not(.btn-sm):not(.btn-lg) {
|
|
2712
3075
|
/* 18px inline has no tier (--space-3 is 16, --space-3-5 is 20); it is the
|
|
2713
3076
|
tablet CTA width tuned against the 12px vertical, so snapping changes
|
|
2714
3077
|
the button aspect on the most visible control in the kit. */
|
|
@@ -2870,7 +3233,12 @@
|
|
|
2870
3233
|
border-color: var(--rule);
|
|
2871
3234
|
}
|
|
2872
3235
|
.ds-247420 .ds-file-row:active { transform: translateY(1px); }
|
|
2873
|
-
|
|
3236
|
+
/* file-grid's own header/caption both claim NEVER A BORDER -- border-color
|
|
3237
|
+
here silently broke that promise for exactly the row it's meant to call
|
|
3238
|
+
out (the row a screenshot/manual test would actually look at). Selected
|
|
3239
|
+
state stays legible via the tint alone; border-color stays transparent so
|
|
3240
|
+
the base rule's promise holds for every row, active or not. */
|
|
3241
|
+
.ds-247420 .ds-file-row.active { background: var(--accent-tint); }
|
|
2874
3242
|
.ds-247420 .ds-file-row[data-file-type="dir"] { border-left-width: 3px; border-left-color: var(--accent); }
|
|
2875
3243
|
.ds-247420 .ds-file-row[data-file-type="image"],
|
|
2876
3244
|
.ds-247420 .ds-file-row[data-file-type="video"],
|
|
@@ -3036,6 +3404,12 @@
|
|
|
3036
3404
|
display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
|
|
3037
3405
|
gap: var(--space-3); align-items: start;
|
|
3038
3406
|
}
|
|
3407
|
+
/* Mobile fallback: auto-fill can still pack 2 cramped columns down to ~320px
|
|
3408
|
+
viewports; force a single column below the shared mobile breakpoint
|
|
3409
|
+
(docs/responsive.md) so thumbnails and file rails always read as a list. */
|
|
3410
|
+
@media (max-width: 480px) {
|
|
3411
|
+
.ds-247420 .ds-file-grid-thumb { grid-template-columns: 1fr; }
|
|
3412
|
+
}
|
|
3039
3413
|
.ds-247420 .ds-file-cell {
|
|
3040
3414
|
position: relative;
|
|
3041
3415
|
background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
@@ -3205,20 +3579,35 @@
|
|
|
3205
3579
|
}
|
|
3206
3580
|
.ds-247420 .ds-error-banner:hover { background: color-mix(in oklab, var(--warn) 20%, var(--bg)); }
|
|
3207
3581
|
|
|
3208
|
-
/* Dropzone
|
|
3582
|
+
/* Dropzone — a tonal target, not a dashed-border affordance (preview/
|
|
3583
|
+
dropzone.html's own header/caption both describe this: "NO DASHED
|
|
3584
|
+
BORDERS" / "tonal panel that swaps to --panel-select on dragover"). A
|
|
3585
|
+
solid hairline plus the idle->dragover background swap is the actual
|
|
3586
|
+
design; dashed was this system's OTHER "drop target" vocabulary
|
|
3587
|
+
(.panel-docs, kits-appended.css) leaking in here by copy-paste. */
|
|
3209
3588
|
.ds-247420 .ds-dropzone {
|
|
3210
|
-
border: var(--bw-rule)
|
|
3589
|
+
border: var(--bw-rule) solid var(--rule);
|
|
3211
3590
|
border-radius: var(--r-3); background: var(--bg);
|
|
3212
3591
|
transition: border-color var(--dur-base) var(--ease), background var(--dur-base) var(--ease);
|
|
3213
3592
|
}
|
|
3593
|
+
/* Idle hover: a quiet pre-drag affordance (border firms up, faint tint) so a
|
|
3594
|
+
pointer resting over the zone reads as "droppable" before a drag even
|
|
3595
|
+
starts — distinct from and weaker than the .dragover treatment below. */
|
|
3596
|
+
.ds-247420 .ds-dropzone:hover {
|
|
3597
|
+
border-color: var(--fg-3);
|
|
3598
|
+
background: var(--bg-2);
|
|
3599
|
+
}
|
|
3214
3600
|
.ds-247420 .ds-dropzone-inner {
|
|
3215
3601
|
display: flex; align-items: center; justify-content: center;
|
|
3216
3602
|
gap: var(--space-2); flex-wrap: wrap;
|
|
3217
3603
|
padding: var(--space-4) var(--space-3); text-align: center;
|
|
3218
3604
|
}
|
|
3219
3605
|
/* Icon size, not type — see .ds-file-cell-media .ds-file-icon above. */
|
|
3220
|
-
.ds-247420 .ds-dropzone-glyph { font-size:
|
|
3606
|
+
.ds-247420 .ds-dropzone-glyph { font-size: var(--icon-lg, 24px); color: var(--fg-3); }
|
|
3221
3607
|
.ds-247420 .ds-dropzone-label { font-size: var(--fs-sm); color: var(--fg-3); }
|
|
3608
|
+
.ds-247420 .ds-dropzone:not(.dragover):not(.rejected):hover {
|
|
3609
|
+
border-color: var(--fg-3);
|
|
3610
|
+
}
|
|
3222
3611
|
.ds-247420 .ds-dropzone.dragover {
|
|
3223
3612
|
border-color: var(--accent);
|
|
3224
3613
|
background: var(--accent-tint);
|
|
@@ -3232,6 +3621,26 @@
|
|
|
3232
3621
|
0%, 100% { border-color: var(--accent); }
|
|
3233
3622
|
50% { border-color: color-mix(in oklab, var(--accent) 45%, transparent); }
|
|
3234
3623
|
}
|
|
3624
|
+
/* Rejected — an in-flight drag carrying a disallowed payload (wrong type,
|
|
3625
|
+
over the size cap). Distinct from dragover: warn tone, not accent, so the
|
|
3626
|
+
two "something is happening" states never read as the same affordance. */
|
|
3627
|
+
.ds-247420 .ds-dropzone.rejected {
|
|
3628
|
+
border-color: var(--warn);
|
|
3629
|
+
background: color-mix(in oklab, var(--warn) 10%, var(--bg));
|
|
3630
|
+
}
|
|
3631
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
3632
|
+
.ds-247420 .ds-dropzone.rejected { animation: ds-dropzone-shake 0.4s var(--ease); }
|
|
3633
|
+
}
|
|
3634
|
+
.ds-247420 .ds-dropzone.rejected .ds-dropzone-glyph,
|
|
3635
|
+
.ds-247420 .ds-dropzone.rejected .ds-dropzone-label { color: var(--warn); }
|
|
3636
|
+
@keyframes ds-dropzone-shake {
|
|
3637
|
+
0%, 100% { transform: translateX(0); }
|
|
3638
|
+
25% { transform: translateX(-3px); }
|
|
3639
|
+
75% { transform: translateX(3px); }
|
|
3640
|
+
}
|
|
3641
|
+
.ds-247420 .ds-dropzone--wrap.rejected > .ds-dropzone-inner {
|
|
3642
|
+
outline-color: var(--warn);
|
|
3643
|
+
}
|
|
3235
3644
|
/* Wrapper form (has children): no permanent chrome - the content renders as if
|
|
3236
3645
|
the zone were not there, and the dashed affordance overlays it ONLY while a
|
|
3237
3646
|
drag is in flight. */
|
|
@@ -3339,6 +3748,8 @@
|
|
|
3339
3748
|
max(var(--space-3), env(safe-area-inset-bottom))
|
|
3340
3749
|
max(var(--space-3), env(safe-area-inset-left));
|
|
3341
3750
|
background: color-mix(in oklab, var(--ink) 55%, transparent);
|
|
3751
|
+
backdrop-filter: blur(2px);
|
|
3752
|
+
-webkit-backdrop-filter: blur(2px);
|
|
3342
3753
|
}
|
|
3343
3754
|
@media (prefers-reduced-motion: no-preference) {
|
|
3344
3755
|
.ds-247420 .ds-modal-backdrop { animation: ds-modal-fade var(--dur-base) var(--ease); }
|
|
@@ -3413,10 +3824,17 @@
|
|
|
3413
3824
|
floor. --ink on the same fill measures 6.27:1. Same principle as the
|
|
3414
3825
|
--accent/--accent-ink split the token layer documents: a light saturated fill
|
|
3415
3826
|
takes the dark text tone. Measured in a live browser. */
|
|
3827
|
+
/* Severity is never color-alone (gd-14, color-blindness/grayscale-print safe):
|
|
3828
|
+
the bold weight + widened letter-spacing is a shape cue that survives a
|
|
3829
|
+
colorless render, matching how .btn-primary.danger differs from every
|
|
3830
|
+
other .btn-primary at a glance even with color stripped out. */
|
|
3416
3831
|
.ds-247420 .btn-primary.danger {
|
|
3417
3832
|
background: var(--warn);
|
|
3418
3833
|
border-color: var(--warn);
|
|
3419
3834
|
color: var(--ink);
|
|
3835
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) color-mix(in oklab, var(--ink) 25%, transparent);
|
|
3836
|
+
font-weight: 700;
|
|
3837
|
+
letter-spacing: 0.01em;
|
|
3420
3838
|
}
|
|
3421
3839
|
.ds-247420 .btn-primary.danger:hover { filter: brightness(0.92); border-color: var(--warn); }
|
|
3422
3840
|
|
|
@@ -3497,7 +3915,7 @@
|
|
|
3497
3915
|
.ds-247420 .ds-preview-code::-webkit-scrollbar,
|
|
3498
3916
|
.ds-247420 .ds-preview-text::-webkit-scrollbar,
|
|
3499
3917
|
.ds-247420 .ds-preview-body::-webkit-scrollbar,
|
|
3500
|
-
.ds-247420 .ds-modal-body::-webkit-scrollbar { width:
|
|
3918
|
+
.ds-247420 .ds-modal-body::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
3501
3919
|
.ds-247420 .ds-preview-code::-webkit-scrollbar-thumb,
|
|
3502
3920
|
.ds-247420 .ds-preview-text::-webkit-scrollbar-thumb {
|
|
3503
3921
|
background: color-mix(in oklab, var(--paper) 28%, transparent);
|
|
@@ -3570,6 +3988,12 @@
|
|
|
3570
3988
|
.ds-247420 .ds-demo-label { font-size: var(--fs-xs); font-weight: 500; margin: 0 0 var(--space-1); }
|
|
3571
3989
|
.ds-247420 .ds-demo-desc { font-size: var(--fs-tiny); color: var(--fg-3); margin: 0 0 var(--space-2); }
|
|
3572
3990
|
|
|
3991
|
+
/* Per-preview backlink to the full token map/doc — names which token
|
|
3992
|
+
families the specimen above it demonstrates, then links out to the
|
|
3993
|
+
generated theme-map for the resolved values. */
|
|
3994
|
+
.ds-247420 .tokens-backlink { font-family: var(--ff-mono); font-size: var(--fs-xs); color: var(--fg-3); margin-top: 2px; }
|
|
3995
|
+
.ds-247420 .tokens-backlink a { color: inherit; }
|
|
3996
|
+
|
|
3573
3997
|
@media (max-width: 768px) {
|
|
3574
3998
|
.ds-247420 .ds-catalog { flex-direction: column; }
|
|
3575
3999
|
.ds-247420 .ds-catalog-side { width: 100%; height: auto; position: static; border-right: 0; border-bottom: var(--bw-hair) solid var(--rule); }
|
|
@@ -3666,13 +4090,25 @@
|
|
|
3666
4090
|
font-family: var(--ff-mono); font-size: var(--fs-xs);
|
|
3667
4091
|
display: inline-flex; align-items: center; gap: 6px;
|
|
3668
4092
|
}
|
|
3669
|
-
/* CSS-drawn
|
|
3670
|
-
legible when its text label is hidden (icon-only rail strip).
|
|
4093
|
+
/* CSS-drawn disc mark on the compact theme toggle: keeps the control
|
|
4094
|
+
legible when its text label is hidden (icon-only rail strip). Per-mode
|
|
4095
|
+
fill gives the icon itself a distinct look for auto/light/dark, so state
|
|
4096
|
+
reads without relying on the title tooltip alone. */
|
|
3671
4097
|
.ds-247420 .ds-theme-disc {
|
|
3672
4098
|
flex: 0 0 auto; width: 14px; height: 14px; border-radius: 50%;
|
|
3673
4099
|
border: var(--bw-hair) solid var(--fg-3);
|
|
4100
|
+
/* auto: half-and-half, matches default (no data-mode) for safety */
|
|
4101
|
+
background: linear-gradient(90deg, var(--fg-3) 0 50%, transparent 50% 100%);
|
|
4102
|
+
}
|
|
4103
|
+
.ds-247420 .ds-theme-disc[data-mode="auto"] {
|
|
3674
4104
|
background: linear-gradient(90deg, var(--fg-3) 0 50%, transparent 50% 100%);
|
|
3675
4105
|
}
|
|
4106
|
+
.ds-247420 .ds-theme-disc[data-mode="paper"] {
|
|
4107
|
+
background: var(--bg); border-color: var(--fg-3);
|
|
4108
|
+
}
|
|
4109
|
+
.ds-247420 .ds-theme-disc[data-mode="ink"] {
|
|
4110
|
+
background: var(--fg-3); border-color: var(--fg-3);
|
|
4111
|
+
}
|
|
3676
4112
|
|
|
3677
4113
|
/* ============================================================
|
|
3678
4114
|
Chat kit polish — styles every class emitted by Chat /
|
|
@@ -3735,6 +4171,7 @@
|
|
|
3735
4171
|
text-transform: lowercase; letter-spacing: 0.02em; user-select: none;
|
|
3736
4172
|
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
|
3737
4173
|
position: relative;
|
|
4174
|
+
box-shadow: inset 0 0 0 1px var(--rule);
|
|
3738
4175
|
}
|
|
3739
4176
|
.ds-247420 .chat-msg:hover .chat-avatar { transform: scale(1.03); box-shadow: 0 1px 4px color-mix(in oklab, var(--fg) 6%, transparent); }
|
|
3740
4177
|
.ds-247420 .chat-msg.you .chat-avatar {
|
|
@@ -3745,6 +4182,18 @@
|
|
|
3745
4182
|
background: color-mix(in oklab, var(--mascot) 26%, var(--bg-2));
|
|
3746
4183
|
color: var(--mascot-deep);
|
|
3747
4184
|
}
|
|
4185
|
+
/* Plain assistant turns ('them', no aicat persona) previously fell through to
|
|
4186
|
+
the bare .chat-avatar gray disc with no role identity at all — 'you' and
|
|
4187
|
+
'aicat' both got a tinted background + ring, the default assistant got
|
|
4188
|
+
nothing. Give it the same tinted-background treatment via --color-success
|
|
4189
|
+
(the conventional assistant/bot association, distinct from the accent hue
|
|
4190
|
+
'you' owns and the mascot hue 'aicat' owns) plus a thin identity ring so
|
|
4191
|
+
role is readable from the avatar alone, not just bubble position/color. */
|
|
4192
|
+
.ds-247420 .chat-msg.them:not(.aicat) .chat-avatar {
|
|
4193
|
+
background: color-mix(in oklab, var(--color-success) 20%, var(--bg-3));
|
|
4194
|
+
color: color-mix(in oklab, var(--color-success) 65%, var(--fg));
|
|
4195
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-success) 35%, transparent);
|
|
4196
|
+
}
|
|
3748
4197
|
|
|
3749
4198
|
.ds-247420 .chat-stack {
|
|
3750
4199
|
display: flex; flex-direction: column; gap: var(--space-1);
|
|
@@ -3764,6 +4213,13 @@
|
|
|
3764
4213
|
min-width: 0;
|
|
3765
4214
|
transition: transform 0.12s ease, box-shadow 0.12s ease;
|
|
3766
4215
|
}
|
|
4216
|
+
/* Tail corner: the bubble edge nearest its own avatar (bottom-left for
|
|
4217
|
+
'them', bottom-right for 'you') squares off slightly, matching bubble
|
|
4218
|
+
position to the sender's avatar the way a speech-bubble tail would — a
|
|
4219
|
+
consistent radius on all four corners reads as a generic card, not a
|
|
4220
|
+
turn in a conversation. */
|
|
4221
|
+
.ds-247420 .chat-msg:not(.you) .chat-bubble { border-bottom-left-radius: var(--r-0); }
|
|
4222
|
+
.ds-247420 .chat-msg.you .chat-bubble { border-bottom-right-radius: var(--r-0); }
|
|
3767
4223
|
.ds-247420 .chat-msg:hover .chat-bubble { transform: translateY(-1px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 6%, transparent); transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease); }
|
|
3768
4224
|
/* Own bubble — calm tinted lead, not a full electric fill (chat stays readable). */
|
|
3769
4225
|
.ds-247420 .chat-msg.you .chat-bubble { background: var(--accent-tint); color: var(--fg); }
|
|
@@ -4048,9 +4504,27 @@
|
|
|
4048
4504
|
.ds-247420 .chat-reactions .rxn .n { font-family: var(--ff-mono); font-weight: 600; font-size: var(--fs-nano); color: var(--fg-2); }
|
|
4049
4505
|
.ds-247420 .chat-reactions .rxn.you .n { color: var(--accent-ink); }
|
|
4050
4506
|
|
|
4507
|
+
/* Typing indicator renders through the same .chat-bubble container as a real
|
|
4508
|
+
message, but must never read as a bubble holding actual content — no
|
|
4509
|
+
border, no hover-lift shadow, no tail-corner cut; just a pill-shaped
|
|
4510
|
+
borderless dot cluster, visually lighter than any card/bubble on the page. */
|
|
4511
|
+
/* Double-class selector (.chat-bubble.chat-bubble-typing) deliberately, not
|
|
4512
|
+
bare .chat-bubble-typing: chat.css (loaded after app-shell.css on every
|
|
4513
|
+
kit that links both) still carries a plain `.chat-bubble { background:
|
|
4514
|
+
var(--bg-2) }` rule at the same (0,1,0) specificity, and cascade order
|
|
4515
|
+
would let that later rule win over an equal-specificity selector here. */
|
|
4516
|
+
.ds-247420 .chat-bubble.chat-bubble-typing {
|
|
4517
|
+
background: transparent;
|
|
4518
|
+
padding: var(--space-2) var(--space-1);
|
|
4519
|
+
border-radius: var(--r-pill);
|
|
4520
|
+
}
|
|
4521
|
+
.ds-247420 .chat-msg:hover .chat-bubble.chat-bubble-typing { transform: none; box-shadow: none; }
|
|
4522
|
+
.ds-247420 .chat-msg:not(.you) .chat-bubble.chat-bubble-typing,
|
|
4523
|
+
.ds-247420 .chat-msg.you .chat-bubble.chat-bubble-typing { border-bottom-left-radius: var(--r-pill); border-bottom-right-radius: var(--r-pill); }
|
|
4524
|
+
|
|
4051
4525
|
.ds-247420 .chat-typing { display: inline-flex; gap: var(--space-1); align-items: center; }
|
|
4052
4526
|
.ds-247420 .chat-typing span {
|
|
4053
|
-
width:
|
|
4527
|
+
width: 8px; height: 8px; border-radius: 50%; background: var(--fg-3);
|
|
4054
4528
|
}
|
|
4055
4529
|
|
|
4056
4530
|
@media (prefers-reduced-motion: no-preference) {
|
|
@@ -4172,8 +4646,18 @@
|
|
|
4172
4646
|
|
|
4173
4647
|
.ds-247420 .aicat-portrait { display: inline-flex; align-items: center; gap: var(--space-2-5); padding: var(--space-1) 0; }
|
|
4174
4648
|
.ds-247420 .aicat-face {
|
|
4175
|
-
/*
|
|
4176
|
-
|
|
4649
|
+
/* The face is 3 lines of ascii art ( /\_/\ , ( o.o ) , > ^ < ), not a
|
|
4650
|
+
single icon glyph -- the previous 24px/line-height:normal sizing (sized
|
|
4651
|
+
like .chat-file .glyph's single-char icon) ran to ~3 line-heights tall
|
|
4652
|
+
and clipped the ear/whisker rows against this box's fixed 32px height
|
|
4653
|
+
+ overflow:hidden. pico (10px) + line-height:1 fits all 3 lines in 30px.
|
|
4654
|
+
padding:0 overrides the global `pre { padding: var(--space-5) }` (32px)
|
|
4655
|
+
-- box-sizing:border-box + that padding alone exceeded the declared
|
|
4656
|
+
32x32 box, so the box never actually enforced 32x32 and rendered at its
|
|
4657
|
+
forced min-content size instead, clipping the art regardless of font
|
|
4658
|
+
size. */
|
|
4659
|
+
width: 32px; height: 32px; font-size: var(--fs-pico); line-height: 1;
|
|
4660
|
+
padding: 0;
|
|
4177
4661
|
display: inline-flex; align-items: center; justify-content: center;
|
|
4178
4662
|
background: color-mix(in oklab, var(--mascot) 22%, var(--bg-2));
|
|
4179
4663
|
border-radius: 50%; flex-shrink: 0;
|
|
@@ -4191,10 +4675,182 @@
|
|
|
4191
4675
|
fell back to the paper tone at 3.13:1 on ink. */
|
|
4192
4676
|
.ds-247420 .aicat-meta .name { color: var(--mascot-deep, var(--mascot)); font-weight: 600; }
|
|
4193
4677
|
|
|
4678
|
+
/* ============================================================
|
|
4679
|
+
Composer attachment-detected badge, context line, hint, toolbar,
|
|
4680
|
+
note strip, elapsed counter, dragover state — all referenced from
|
|
4681
|
+
composer.js / composer-affordances.js but previously had no CSS at
|
|
4682
|
+
all (unstyled DOM nodes / plain text falling through to block
|
|
4683
|
+
defaults).
|
|
4684
|
+
============================================================ */
|
|
4685
|
+
.ds-247420 .chat-composer-context {
|
|
4686
|
+
display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-1);
|
|
4687
|
+
width: 100%; order: -1;
|
|
4688
|
+
padding: var(--space-1) var(--space-1) 0;
|
|
4689
|
+
font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3);
|
|
4690
|
+
letter-spacing: 0.01em;
|
|
4691
|
+
}
|
|
4692
|
+
.ds-247420 button.chat-composer-context {
|
|
4693
|
+
background: transparent; border: 0; cursor: pointer; text-align: left;
|
|
4694
|
+
border-radius: var(--r-0);
|
|
4695
|
+
}
|
|
4696
|
+
.ds-247420 button.chat-composer-context:hover { color: var(--fg-2); }
|
|
4697
|
+
.ds-247420 button.chat-composer-context:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
4698
|
+
.ds-247420 .chat-composer-context-sep { color: var(--fg-3); opacity: 0.6; }
|
|
4699
|
+
.ds-247420 .chat-composer-context-bit {
|
|
4700
|
+
background: transparent; border: 0; padding: 0; margin: 0; cursor: pointer;
|
|
4701
|
+
font: inherit; color: var(--fg-3); border-radius: var(--r-0);
|
|
4702
|
+
transition: color var(--dur-snap, .15s) var(--ease, ease);
|
|
4703
|
+
}
|
|
4704
|
+
.ds-247420 .chat-composer-context-bit:hover { color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; }
|
|
4705
|
+
.ds-247420 .chat-composer-context-bit:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
4706
|
+
.ds-247420 .chat-composer-context-text { color: var(--fg-3); }
|
|
4707
|
+
|
|
4708
|
+
.ds-247420 .chat-composer-detected-badge {
|
|
4709
|
+
display: flex; align-items: center; gap: var(--space-2);
|
|
4710
|
+
width: 100%; order: -1;
|
|
4711
|
+
padding: var(--space-1) var(--space-2-5);
|
|
4712
|
+
margin: 0 0 var(--space-1);
|
|
4713
|
+
background: color-mix(in oklab, var(--accent) 12%, var(--bg-2));
|
|
4714
|
+
border: 1px solid color-mix(in oklab, var(--accent) 28%, transparent);
|
|
4715
|
+
border-radius: var(--r-1);
|
|
4716
|
+
font-size: var(--fs-xs); color: var(--fg);
|
|
4717
|
+
}
|
|
4718
|
+
.ds-247420 .chat-composer-detected-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
4719
|
+
.ds-247420 .chat-composer-detected-dismiss {
|
|
4720
|
+
flex-shrink: 0; width: 20px; height: 20px;
|
|
4721
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
4722
|
+
background: transparent; border: 0; cursor: pointer; border-radius: 50%;
|
|
4723
|
+
color: var(--fg-3); font-family: var(--ff-mono); font-size: var(--fs-tiny); line-height: 1;
|
|
4724
|
+
transition: background var(--dur-snap, .15s) var(--ease, ease), color var(--dur-snap, .15s) var(--ease, ease);
|
|
4725
|
+
}
|
|
4726
|
+
.ds-247420 .chat-composer-detected-dismiss:hover { background: color-mix(in oklab, var(--fg) 10%, transparent); color: var(--fg); }
|
|
4727
|
+
.ds-247420 .chat-composer-detected-dismiss:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
4728
|
+
|
|
4729
|
+
.ds-247420 .chat-composer-hint {
|
|
4730
|
+
width: 100%; order: 2;
|
|
4731
|
+
font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3);
|
|
4732
|
+
padding: 0 var(--space-1);
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
.ds-247420 .chat-composer-toolbar {
|
|
4736
|
+
display: flex; align-items: center; gap: var(--space-1);
|
|
4737
|
+
flex-shrink: 0;
|
|
4738
|
+
}
|
|
4739
|
+
.ds-247420 .chat-composer-toolbar .composer-btn {
|
|
4740
|
+
width: 32px; height: 32px; border-radius: var(--r-1);
|
|
4741
|
+
}
|
|
4742
|
+
@media (pointer: coarse) {
|
|
4743
|
+
.ds-247420 .chat-composer-toolbar .composer-btn { width: 44px; height: 44px; }
|
|
4744
|
+
}
|
|
4745
|
+
|
|
4746
|
+
.ds-247420 .chat-composer-note {
|
|
4747
|
+
width: 100%; order: 3;
|
|
4748
|
+
font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3);
|
|
4749
|
+
padding: var(--space-1) var(--space-1) 0;
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
.ds-247420 .chat-composer-elapsed {
|
|
4753
|
+
font-family: var(--ff-mono); font-size: var(--fs-tiny); color: var(--fg-3);
|
|
4754
|
+
flex-shrink: 0; padding: 0 var(--space-1);
|
|
4755
|
+
}
|
|
4756
|
+
|
|
4757
|
+
.ds-247420 .chat-composer.dragover {
|
|
4758
|
+
border-color: var(--accent);
|
|
4759
|
+
box-shadow: 0 0 0 2px color-mix(in oklab, var(--accent) 18%, transparent);
|
|
4760
|
+
background: color-mix(in oklab, var(--accent) 4%, var(--bg));
|
|
4761
|
+
}
|
|
4762
|
+
|
|
4763
|
+
/* ============================================================
|
|
4764
|
+
EmojiPicker (ov-emoji-*) — an anchored popover with search input,
|
|
4765
|
+
category tabs, and an emoji grid; previously entirely unstyled.
|
|
4766
|
+
Search input mirrors .ds-search-input's tonal-fill treatment so it
|
|
4767
|
+
reads consistently with the rest of the system's search fields.
|
|
4768
|
+
============================================================ */
|
|
4769
|
+
.ds-247420 .ov-emoji-root {
|
|
4770
|
+
position: fixed;
|
|
4771
|
+
display: flex; flex-direction: column; gap: var(--space-2);
|
|
4772
|
+
width: 280px; max-height: 320px;
|
|
4773
|
+
padding: var(--space-2-5);
|
|
4774
|
+
background: var(--bg);
|
|
4775
|
+
border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
|
|
4776
|
+
border-radius: var(--r-2);
|
|
4777
|
+
box-shadow: var(--shadow-overlay, var(--shadow-3));
|
|
4778
|
+
z-index: var(--z-dropdown, var(--z-raised));
|
|
4779
|
+
}
|
|
4780
|
+
.ds-247420 .ov-emoji-search {
|
|
4781
|
+
width: 100%; box-sizing: border-box;
|
|
4782
|
+
font: inherit; font-size: var(--fs-sm); color: var(--fg);
|
|
4783
|
+
background: var(--bg-2); border: 0;
|
|
4784
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--rule);
|
|
4785
|
+
border-radius: var(--r-1);
|
|
4786
|
+
height: var(--ctl-sm, 32px);
|
|
4787
|
+
padding: 0 var(--space-2-5);
|
|
4788
|
+
transition: box-shadow var(--dur-snap, .15s) var(--ease, ease);
|
|
4789
|
+
}
|
|
4790
|
+
.ds-247420 .ov-emoji-search::placeholder { color: var(--fg-3); }
|
|
4791
|
+
.ds-247420 .ov-emoji-search:focus-visible,
|
|
4792
|
+
.ds-247420 .ov-emoji-search:focus {
|
|
4793
|
+
outline: none;
|
|
4794
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--accent), 0 0 0 2px color-mix(in oklab, var(--accent) 18%, transparent);
|
|
4795
|
+
}
|
|
4796
|
+
.ds-247420 .ov-emoji-tabs {
|
|
4797
|
+
display: flex; gap: var(--space-1);
|
|
4798
|
+
border-bottom: 1px solid color-mix(in oklab, var(--fg) 10%, transparent);
|
|
4799
|
+
padding-bottom: var(--space-1);
|
|
4800
|
+
}
|
|
4801
|
+
.ds-247420 .ov-emoji-tab {
|
|
4802
|
+
flex: 1;
|
|
4803
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
4804
|
+
height: 30px; font-size: var(--fs-sm);
|
|
4805
|
+
background: transparent; border: 0; border-radius: var(--r-1);
|
|
4806
|
+
cursor: pointer;
|
|
4807
|
+
transition: background var(--dur-snap, .15s) var(--ease, ease);
|
|
4808
|
+
}
|
|
4809
|
+
.ds-247420 .ov-emoji-tab:hover { background: color-mix(in oklab, var(--fg) 8%, transparent); }
|
|
4810
|
+
.ds-247420 .ov-emoji-tab[aria-selected="true"] { background: color-mix(in oklab, var(--accent) 16%, transparent); }
|
|
4811
|
+
.ds-247420 .ov-emoji-tab:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
4812
|
+
.ds-247420 .ov-emoji-grid { overflow-y: auto; flex: 1; min-height: 0; scrollbar-width: thin; scrollbar-color: var(--bg-3) transparent; }
|
|
4813
|
+
.ds-247420 .ov-emoji-grid-inner {
|
|
4814
|
+
display: grid; grid-template-columns: repeat(6, 1fr); gap: var(--space-1);
|
|
4815
|
+
}
|
|
4816
|
+
.ds-247420 .ov-emoji-cell {
|
|
4817
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
4818
|
+
aspect-ratio: 1; font-size: var(--fs-lg); line-height: 1;
|
|
4819
|
+
background: transparent; border: 0; border-radius: var(--r-1);
|
|
4820
|
+
cursor: pointer;
|
|
4821
|
+
transition: background var(--dur-snap, .15s) var(--ease, ease), transform 0.12s ease;
|
|
4822
|
+
}
|
|
4823
|
+
.ds-247420 .ov-emoji-cell:hover { background: color-mix(in oklab, var(--fg) 10%, transparent); transform: scale(1.12); }
|
|
4824
|
+
.ds-247420 .ov-emoji-cell:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; background: color-mix(in oklab, var(--fg) 10%, transparent); }
|
|
4825
|
+
.ds-247420 .ov-emoji-empty {
|
|
4826
|
+
grid-column: 1 / -1;
|
|
4827
|
+
text-align: center; color: var(--fg-3); font-size: var(--fs-xs);
|
|
4828
|
+
padding: var(--space-3) 0;
|
|
4829
|
+
}
|
|
4830
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4831
|
+
.ds-247420 .ov-emoji-cell { transition: background var(--dur-snap, .15s) var(--ease, ease); }
|
|
4832
|
+
.ds-247420 .ov-emoji-cell:hover { transform: none; }
|
|
4833
|
+
}
|
|
4834
|
+
|
|
4194
4835
|
/* ============================================================
|
|
4195
4836
|
Sidebar polish: hide zero-count badges; tonal active state;
|
|
4196
4837
|
monospace count chips.
|
|
4197
4838
|
============================================================ */
|
|
4839
|
+
/* Rail row rhythm: the sidebar rows (bins/labels) previously packed at
|
|
4840
|
+
--space-hair (2px) margin-bottom while the main content column reads at
|
|
4841
|
+
the --space-5/--space-3 outer/inner rhythm (AGENTS.md "panel rhythm").
|
|
4842
|
+
Bumping the inter-row gap to --space-1-5 (5px) — still a tight, dense-app
|
|
4843
|
+
value, but enough that adjacent rows no longer read as glued together —
|
|
4844
|
+
and making it density-aware via [data-density] mirrors the existing
|
|
4845
|
+
compact-density override pattern in files.css (.ds-file-grid[data-density]).
|
|
4846
|
+
[data-density="compact"] keeps the old tighter feel for long rail lists;
|
|
4847
|
+
[data-density="spacious"] opens it further. */
|
|
4848
|
+
.ds-247420 .app-side a { margin-bottom: var(--space-1-5); }
|
|
4849
|
+
.ds-247420 .app-side[data-density="compact"] a,
|
|
4850
|
+
.ds-247420 .app-side-shell[data-density="compact"] .app-side a { margin-bottom: var(--space-hair); }
|
|
4851
|
+
.ds-247420 .app-side[data-density="spacious"] a,
|
|
4852
|
+
.ds-247420 .app-side-shell[data-density="spacious"] .app-side a { margin-bottom: var(--space-2); }
|
|
4853
|
+
|
|
4198
4854
|
.ds-247420 .app-side .count {
|
|
4199
4855
|
padding: 1px 8px; font-size: var(--fs-micro); font-weight: 700;
|
|
4200
4856
|
font-family: var(--ff-mono); letter-spacing: 0.04em;
|
|
@@ -4298,12 +4954,32 @@
|
|
|
4298
4954
|
:disabled pseudo-class, so a disabled link-styled button relies entirely
|
|
4299
4955
|
on this class selector for its visual treatment (aria-disabled + tabindex
|
|
4300
4956
|
are set in JS; this is the paired CSS half). */
|
|
4957
|
+
/* opacity:0.6 alone barely separated from an active .btn-primary against a
|
|
4958
|
+
busy background -- close enough in dark mode that users clicked disabled
|
|
4959
|
+
buttons expecting them to work. grayscale flattens any color signal (no
|
|
4960
|
+
more "still looks clickable-green") and the steeper opacity drop reads as
|
|
4961
|
+
unmistakably inert at a glance, not just slightly dimmed. */
|
|
4301
4962
|
.ds-247420 .btn:disabled, .ds-247420 .btn-primary:disabled, .ds-247420 .btn-ghost:disabled, .ds-247420 .btn.is-disabled, .ds-247420 .btn-primary.is-disabled, .ds-247420 .btn-ghost.is-disabled, .ds-247420 button:disabled, .ds-247420[disabled] {
|
|
4302
|
-
opacity: 0.
|
|
4963
|
+
opacity: 0.5;
|
|
4964
|
+
filter: grayscale(60%);
|
|
4303
4965
|
cursor: not-allowed;
|
|
4304
4966
|
pointer-events: none;
|
|
4305
4967
|
}
|
|
4306
4968
|
|
|
4969
|
+
/* Systemic hover fallback — button-like elements with no design-system class
|
|
4970
|
+
(a bare <button>, [role="button"], or a generic .row/.chip usage) get a
|
|
4971
|
+
`transition` declared above (line ~106) but nothing to transition to, so
|
|
4972
|
+
they look inert until clicked. This is a low-specificity (0,0,1)/(0,1,1)
|
|
4973
|
+
catch-all: any element that also carries `.btn`/`.btn-primary`/`.btn-ghost`/
|
|
4974
|
+
`.ds-icon-btn`/etc. keeps its own component `:hover` (those selectors are
|
|
4975
|
+
equal-or-higher specificity and, for the shared ones, declared later in
|
|
4976
|
+
the cascade), so this never overrides a deliberate per-component hover —
|
|
4977
|
+
it only fills the gap for elements that don't have one. */
|
|
4978
|
+
.ds-247420 button:not(:disabled):hover,
|
|
4979
|
+
.ds-247420[role="button"]:not([aria-disabled="true"]):hover {
|
|
4980
|
+
background-color: var(--panel-hover, var(--bg-3));
|
|
4981
|
+
}
|
|
4982
|
+
|
|
4307
4983
|
/* Loading state — spinning indicator */
|
|
4308
4984
|
@keyframes spinner-rotate {
|
|
4309
4985
|
from { transform: rotate(0deg); }
|
|
@@ -4311,10 +4987,12 @@
|
|
|
4311
4987
|
}
|
|
4312
4988
|
/* Reusable spin utility: rotates the element (e.g. a refresh Icon used as a
|
|
4313
4989
|
busy indicator) via the shared spinner-rotate keyframe. Respects reduced
|
|
4314
|
-
motion. Use instead of a decorative rotation glyph.
|
|
4990
|
+
motion. Use instead of a decorative rotation glyph.
|
|
4991
|
+
Ring spinner — use for larger blocking/full-region loading states. */
|
|
4315
4992
|
.ds-247420 .ds-spin { animation: spinner-rotate 0.8s linear infinite; transform-origin: center; }
|
|
4316
4993
|
@media (prefers-reduced-motion: reduce) { .ds-247420 .ds-spin { animation: none; } }
|
|
4317
4994
|
|
|
4995
|
+
/* Ring spinner — use for larger blocking/full-region loading states. */
|
|
4318
4996
|
.ds-247420 .loading { position: relative; }
|
|
4319
4997
|
.ds-247420 .loading::after {
|
|
4320
4998
|
content: '';
|
|
@@ -4496,6 +5174,7 @@
|
|
|
4496
5174
|
}
|
|
4497
5175
|
.ds-247420 .ds-context-menu-item.danger {
|
|
4498
5176
|
color: var(--warn);
|
|
5177
|
+
box-shadow: inset 2px 0 0 var(--warn);
|
|
4499
5178
|
}
|
|
4500
5179
|
.ds-247420 .ds-context-menu-item.danger:hover {
|
|
4501
5180
|
background: color-mix(in oklab, var(--warn) 12%, var(--bg));
|
|
@@ -4598,6 +5277,7 @@
|
|
|
4598
5277
|
.ds-247420 .prose p { margin: 0 0 var(--space-4) 0; }
|
|
4599
5278
|
.ds-247420 .prose p:last-child { margin-bottom: 0; }
|
|
4600
5279
|
.ds-247420 .prose a { color: var(--accent-ink); text-decoration-color: var(--rule-strong); text-underline-offset: 0.15em; }
|
|
5280
|
+
.ds-247420 .prose a:visited { color: color-mix(in oklab, var(--accent-ink) 70%, var(--purple-2, var(--fg-3))); }
|
|
4601
5281
|
.ds-247420 .prose a:hover { text-decoration-color: currentColor; }
|
|
4602
5282
|
|
|
4603
5283
|
/* Rubber-stamp motif — a bordered, uppercase, letter-spaced badge with a
|
|
@@ -4614,7 +5294,13 @@
|
|
|
4614
5294
|
transform: rotate(-2deg);
|
|
4615
5295
|
white-space: nowrap;
|
|
4616
5296
|
}
|
|
4617
|
-
|
|
5297
|
+
/* border-color previously matched background exactly (var(--ink) on both) --
|
|
5298
|
+
same class of bug as the colors-core "paper" swatch: a border drawn in the
|
|
5299
|
+
identical color as its own fill is invisible, so the ink-toned stamp was
|
|
5300
|
+
the one variant on the page missing its box outline. --paper reads as a
|
|
5301
|
+
visible ring against the ink fill (paper-on-ink is this token pair's
|
|
5302
|
+
whole reason to exist), matching every other .stamp variant's contrast. */
|
|
5303
|
+
.ds-247420 .stamp.ink { background: var(--ink); border-color: var(--paper); color: var(--paper); }
|
|
4618
5304
|
.ds-247420 .stamp.acid { background: var(--accent); border-color: var(--accent-ink); color: var(--accent-ink); }
|
|
4619
5305
|
.ds-247420 .stamp.purple { border-color: var(--purple-2); color: var(--purple-2); }
|
|
4620
5306
|
.ds-247420 .stamp.mascot { border-color: var(--mascot); color: var(--mascot-deep); }
|
|
@@ -4629,6 +5315,11 @@
|
|
|
4629
5315
|
border: 2px solid var(--fg);
|
|
4630
5316
|
border-radius: var(--r-hair);
|
|
4631
5317
|
background: transparent; color: var(--fg);
|
|
5318
|
+
/* .stamp's own caption claims the rubber-stamp motif is "always rotated
|
|
5319
|
+
slightly" -- .btn-stamp is the same visual face as an interactive
|
|
5320
|
+
<button> (preview/stamps-lore.html's second row) and had no rotation at
|
|
5321
|
+
all, breaking that claim for every stamp in that row. */
|
|
5322
|
+
transform: rotate(-2deg);
|
|
4632
5323
|
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
4633
5324
|
}
|
|
4634
5325
|
.ds-247420 .btn-stamp:hover { background: var(--panel-hover); }
|
|
@@ -4645,12 +5336,25 @@
|
|
|
4645
5336
|
width: 100%; height: 0; border: 0;
|
|
4646
5337
|
}
|
|
4647
5338
|
.ds-247420 hr.rule { border-top: 1px solid var(--rule); }
|
|
4648
|
-
.ds-247420 hr.rule-double {
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
5339
|
+
.ds-247420 hr.rule-double {
|
|
5340
|
+
height: 3px;
|
|
5341
|
+
border-top: 1px solid var(--rule-strong);
|
|
5342
|
+
border-bottom: 1px solid var(--rule-strong);
|
|
5343
|
+
}
|
|
5344
|
+
/* 1px was indistinguishable from .rule -- border-style:dotted needs enough
|
|
5345
|
+
width to actually draw a gap between dots; below ~2px (esp. at DPRs where
|
|
5346
|
+
1px resolves to a sub-pixel value like 0.8px) Chrome collapses it to a
|
|
5347
|
+
solid line, which is exactly what preview/rules.html's report caught live. */
|
|
5348
|
+
.ds-247420 hr.rule-dotted { border-top: 2px dotted var(--rule-strong); }
|
|
5349
|
+
|
|
5350
|
+
/* Hairline-only text input — no full box, no permanent fill. A single bottom
|
|
5351
|
+
rule that thickens to 2px on focus, matching the row/rule zero-border
|
|
5352
|
+
aesthetic instead of a browser-default boxed field. A completely flat,
|
|
5353
|
+
static hairline reads as a static label rather than an editable control
|
|
5354
|
+
at a glance (no cue at rest, nothing on hover) -- the very faint permanent
|
|
5355
|
+
wash plus a stronger hover tint below signal "this is a field" without
|
|
5356
|
+
reverting to the boxed/filled chrome the hairline design deliberately
|
|
5357
|
+
moved away from. */
|
|
4654
5358
|
.ds-247420 .input {
|
|
4655
5359
|
display: block; width: 100%; box-sizing: border-box;
|
|
4656
5360
|
/* appearance:none alone is not enough: with color-scheme:dark set on the
|
|
@@ -4664,11 +5368,13 @@
|
|
|
4664
5368
|
color-scheme: normal;
|
|
4665
5369
|
border: 0; border-bottom: 1px solid var(--rule-strong);
|
|
4666
5370
|
border-radius: var(--r-0);
|
|
4667
|
-
background: transparent;
|
|
5371
|
+
background: color-mix(in oklab, var(--fg) 2.5%, transparent);
|
|
4668
5372
|
box-shadow: none;
|
|
4669
5373
|
padding: var(--space-2) var(--space-1);
|
|
4670
5374
|
font: inherit; color: var(--fg);
|
|
5375
|
+
transition: background var(--dur-snap) var(--ease), border-color var(--dur-snap) var(--ease);
|
|
4671
5376
|
}
|
|
5377
|
+
.ds-247420 .input:hover { background: color-mix(in oklab, var(--fg) 5%, transparent); }
|
|
4672
5378
|
/* Touch floor for the BASE input. Several specific inputs already carried this
|
|
4673
5379
|
(ds-file-filter-input, ds-modal-input, ds-term-input) but the primitive every
|
|
4674
5380
|
form actually uses did not, so a plain field measured 34px under a coarse
|
|
@@ -4686,6 +5392,15 @@
|
|
|
4686
5392
|
border-bottom-color: var(--accent-ink);
|
|
4687
5393
|
}
|
|
4688
5394
|
|
|
5395
|
+
/* Switch primitive (form-primitives.js Toggle) -- track + sliding knob.
|
|
5396
|
+
Canonical definition lives in editor-primitives.css alongside the rest of
|
|
5397
|
+
the .ds-check/.ds-radio/.ds-toggle form-primitive family (that file loads
|
|
5398
|
+
AFTER this one in the build.mjs concat order, so a second .ds-toggle block
|
|
5399
|
+
here was dead weight that silently lost the cascade while still disagreeing
|
|
5400
|
+
on size/colors/knob-offset with the surviving rule — a duplicate-source-of-
|
|
5401
|
+
-truth foot-gun, not an intentional override). Removed; see
|
|
5402
|
+
editor-primitives.css's ".ds-toggle" block for track/knob/disabled/focus. */
|
|
5403
|
+
|
|
4689
5404
|
/* -- Field controls: themed base for TextField / Select / SearchInput --
|
|
4690
5405
|
Root fix: previously only `transition` was set, so themed apps got
|
|
4691
5406
|
browser-default white boxes in dark mode and labels collided with inputs
|
|
@@ -4773,6 +5488,15 @@
|
|
|
4773
5488
|
button) - transparent to any flex/grid layout the bare input previously
|
|
4774
5489
|
sat in directly. */
|
|
4775
5490
|
.ds-247420 .ds-search-input-wrap { display: contents; }
|
|
5491
|
+
/* Leading-icon slot, matching .app-search's icon placement in Topbar so the
|
|
5492
|
+
two search surfaces read as one control family instead of icon-vs-no-icon. */
|
|
5493
|
+
.ds-247420 .ds-search-field { position: relative; display: inline-flex; align-items: center; min-width: 0; }
|
|
5494
|
+
.ds-247420 .ds-search-field .ds-search-icon {
|
|
5495
|
+
position: absolute; left: var(--space-3);
|
|
5496
|
+
display: inline-flex; pointer-events: none;
|
|
5497
|
+
color: var(--fg-3); opacity: 0.6;
|
|
5498
|
+
}
|
|
5499
|
+
.ds-247420 .ds-search-field .ds-search-input { padding-left: calc(var(--space-3) + 15px + var(--space-2)); }
|
|
4776
5500
|
|
|
4777
5501
|
/* Visible clear (X) button for SearchInput - mirrors .ds-alert-dismiss's
|
|
4778
5502
|
ghost-icon treatment but sized to the kit's 44px touch-target floor
|
|
@@ -4794,7 +5518,7 @@
|
|
|
4794
5518
|
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
4795
5519
|
}
|
|
4796
5520
|
.ds-247420 .ds-search-clear:hover { background: var(--bg-2); color: var(--fg); }
|
|
4797
|
-
.ds-247420 .ds-search-clear:focus-visible { outline:
|
|
5521
|
+
.ds-247420 .ds-search-clear:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
4798
5522
|
|
|
4799
5523
|
.ds-247420 .ds-field input:not(.input):focus-visible,
|
|
4800
5524
|
.ds-247420 .ds-field textarea:not(.input):focus-visible,
|
|
@@ -4809,12 +5533,12 @@
|
|
|
4809
5533
|
.ds-247420 .ds-field input:not(.input):disabled,
|
|
4810
5534
|
.ds-247420 .ds-field textarea:not(.input):disabled,
|
|
4811
5535
|
.ds-247420 .ds-field .ds-select:disabled {
|
|
4812
|
-
opacity: .
|
|
5536
|
+
opacity: 0.5;
|
|
4813
5537
|
cursor: not-allowed;
|
|
4814
5538
|
}
|
|
4815
5539
|
.ds-247420 .ds-field input:not(.input)[aria-invalid="true"],
|
|
4816
5540
|
.ds-247420 .ds-field textarea:not(.input)[aria-invalid="true"] {
|
|
4817
|
-
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--
|
|
5541
|
+
box-shadow: inset 0 0 0 var(--bw-hair, 1px) var(--danger);
|
|
4818
5542
|
}
|
|
4819
5543
|
|
|
4820
5544
|
/* Clear button for text inputs */
|
|
@@ -5021,18 +5745,61 @@
|
|
|
5021
5745
|
}
|
|
5022
5746
|
}
|
|
5023
5747
|
|
|
5748
|
+
/* Stacking host for the imperative toast()/<Toast> component
|
|
5749
|
+
(src/components/editor-primitives/toast.js). One fixed-position column;
|
|
5750
|
+
individual toasts are appended/removed as siblings inside it rather than
|
|
5751
|
+
each toast fixed-positioning itself, so more than one toast in flight
|
|
5752
|
+
stacks instead of overlapping at the same bottom-right point. */
|
|
5753
|
+
.ds-247420 .ds-ep-toast-host {
|
|
5754
|
+
position: fixed; z-index: var(--z-toast);
|
|
5755
|
+
bottom: 24px; right: 24px;
|
|
5756
|
+
display: flex; flex-direction: column-reverse; gap: var(--space-2);
|
|
5757
|
+
pointer-events: none;
|
|
5758
|
+
}
|
|
5759
|
+
.ds-247420 .ds-ep-toast {
|
|
5760
|
+
pointer-events: auto;
|
|
5761
|
+
display: flex; align-items: center; gap: var(--space-3);
|
|
5762
|
+
background: var(--bg-2); color: var(--fg);
|
|
5763
|
+
border: 1px solid var(--rule);
|
|
5764
|
+
border-radius: var(--r-2);
|
|
5765
|
+
padding: var(--space-3) var(--space-4);
|
|
5766
|
+
max-width: 320px;
|
|
5767
|
+
box-shadow: var(--shadow-overlay);
|
|
5768
|
+
font-size: var(--fs-sm);
|
|
5769
|
+
}
|
|
5770
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
5771
|
+
.ds-247420 .ds-ep-toast { animation: toast-slide-in 0.3s ease-out; }
|
|
5772
|
+
.ds-247420 .ds-ep-toast.leaving { animation: toast-slide-in 0.2s ease-in reverse; }
|
|
5773
|
+
}
|
|
5774
|
+
.ds-247420 .ds-ep-toast.kind-error { border-color: var(--danger, var(--warn)); }
|
|
5775
|
+
.ds-247420 .ds-ep-toast.kind-success { border-color: var(--green-2); }
|
|
5776
|
+
.ds-247420 .ds-ep-toast.kind-warning { border-color: var(--amber); }
|
|
5777
|
+
.ds-247420 .ds-ep-toast-msg { flex: 1; }
|
|
5778
|
+
.ds-247420 .ds-ep-toast-action {
|
|
5779
|
+
flex-shrink: 0;
|
|
5780
|
+
background: transparent; border: 0; color: var(--accent-ink);
|
|
5781
|
+
font: inherit; font-weight: 600; cursor: pointer; padding: 0;
|
|
5782
|
+
}
|
|
5783
|
+
.ds-247420 .ds-ep-toast-action:hover { text-decoration: underline; }
|
|
5784
|
+
|
|
5785
|
+
@media (max-width: 480px) {
|
|
5786
|
+
.ds-247420 .ds-ep-toast-host { bottom: 16px; right: 16px; left: 16px; }
|
|
5787
|
+
.ds-247420 .ds-ep-toast { max-width: none; }
|
|
5788
|
+
}
|
|
5789
|
+
|
|
5024
5790
|
/* ============================================================
|
|
5025
5791
|
Spinner — animated loading indicator
|
|
5026
5792
|
============================================================ */
|
|
5793
|
+
/* Dots spinner — use for small inline/compact loading states. */
|
|
5027
5794
|
.ds-247420 .ds-spinner {
|
|
5028
5795
|
display: inline-flex;
|
|
5029
|
-
gap:
|
|
5796
|
+
gap: var(--space-1);
|
|
5030
5797
|
align-items: center;
|
|
5031
5798
|
height: 16px;
|
|
5032
5799
|
}
|
|
5033
5800
|
.ds-247420 .ds-spinner span {
|
|
5034
|
-
width:
|
|
5035
|
-
height:
|
|
5801
|
+
width: var(--space-1);
|
|
5802
|
+
height: var(--space-1);
|
|
5036
5803
|
border-radius: 50%;
|
|
5037
5804
|
background: var(--accent);
|
|
5038
5805
|
}
|
|
@@ -5043,23 +5810,28 @@
|
|
|
5043
5810
|
.ds-247420 .ds-spinner span:nth-child(3) { animation-delay: 0.36s; }
|
|
5044
5811
|
}
|
|
5045
5812
|
|
|
5046
|
-
.ds-247420 .ds-spinner-lg { height: 24px; gap:
|
|
5047
|
-
.ds-247420 .ds-spinner-lg span { width:
|
|
5813
|
+
.ds-247420 .ds-spinner-lg { height: 24px; gap: var(--space-1-75); }
|
|
5814
|
+
.ds-247420 .ds-spinner-lg span { width: var(--space-1-75); height: var(--space-1-75); }
|
|
5048
5815
|
|
|
5049
|
-
.ds-247420 .ds-spinner-sm { height:
|
|
5050
|
-
.ds-247420 .ds-spinner-sm span { width:
|
|
5816
|
+
.ds-247420 .ds-spinner-sm { height: var(--space-2-5); gap: var(--space-hair); }
|
|
5817
|
+
.ds-247420 .ds-spinner-sm span { width: var(--space-hair); height: var(--space-hair); }
|
|
5051
5818
|
|
|
5052
|
-
.ds-247420 .ds-spinner-xs { height:
|
|
5819
|
+
.ds-247420 .ds-spinner-xs { height: var(--space-2); gap: 1px; }
|
|
5053
5820
|
.ds-247420 .ds-spinner-xs span { width: 1.5px; height: 1.5px; }
|
|
5054
5821
|
|
|
5055
|
-
.ds-247420 .ds-spinner-xl { height:
|
|
5056
|
-
.ds-247420 .ds-spinner-xl span { width:
|
|
5822
|
+
.ds-247420 .ds-spinner-xl { height: var(--space-5); gap: var(--space-2); }
|
|
5823
|
+
.ds-247420 .ds-spinner-xl span { width: var(--space-2); height: var(--space-2); }
|
|
5057
5824
|
|
|
5058
5825
|
@keyframes ds-bounce {
|
|
5059
5826
|
0%, 80%, 100% { transform: translateY(0); }
|
|
5060
5827
|
40% { transform: translateY(-8px); }
|
|
5061
5828
|
}
|
|
5062
5829
|
|
|
5830
|
+
/* Two spinner visual languages coexist intentionally: dots (.ds-spinner*)
|
|
5831
|
+
are for small inline/compact loading states (buttons, chips, list rows),
|
|
5832
|
+
the ring (.loading::after in states-interactions.css) is for larger
|
|
5833
|
+
blocking/full-region loading states (panels, full views). */
|
|
5834
|
+
|
|
5063
5835
|
/* ============================================================
|
|
5064
5836
|
Skeleton — animated loading placeholder
|
|
5065
5837
|
============================================================ */
|
|
@@ -5071,9 +5843,11 @@
|
|
|
5071
5843
|
.ds-247420 .ds-skeleton {
|
|
5072
5844
|
background: linear-gradient(90deg, var(--bg-2) 25%, var(--bg-3) 50%, var(--bg-2) 75%);
|
|
5073
5845
|
background-size: 200% 100%;
|
|
5074
|
-
animation: ds-shimmer 1.5s infinite;
|
|
5075
5846
|
border-radius: var(--r-1);
|
|
5076
5847
|
}
|
|
5848
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
5849
|
+
.ds-247420 .ds-skeleton { animation: ds-shimmer 1.5s infinite; }
|
|
5850
|
+
}
|
|
5077
5851
|
|
|
5078
5852
|
@keyframes ds-shimmer {
|
|
5079
5853
|
0% { background-position: 200% 0; }
|
|
@@ -5103,7 +5877,7 @@
|
|
|
5103
5877
|
flex-shrink: 0;
|
|
5104
5878
|
color: var(--alert-tone);
|
|
5105
5879
|
font-weight: 600;
|
|
5106
|
-
min-width:
|
|
5880
|
+
min-width: var(--icon-md);
|
|
5107
5881
|
text-align: center;
|
|
5108
5882
|
}
|
|
5109
5883
|
|
|
@@ -5132,13 +5906,14 @@
|
|
|
5132
5906
|
cursor: pointer;
|
|
5133
5907
|
color: var(--fg-3);
|
|
5134
5908
|
padding: 0;
|
|
5135
|
-
font-size:
|
|
5909
|
+
font-size: var(--fs-xs);
|
|
5136
5910
|
line-height: 1;
|
|
5137
|
-
min-width:
|
|
5911
|
+
min-width: var(--icon-md);
|
|
5138
5912
|
text-align: center;
|
|
5139
5913
|
transition: color var(--dur-snap) var(--ease);
|
|
5140
5914
|
}
|
|
5141
5915
|
.ds-247420 .ds-alert-dismiss:hover { color: var(--fg); }
|
|
5916
|
+
.ds-247420 .ds-alert-dismiss:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
5142
5917
|
|
|
5143
5918
|
/* ============================================================
|
|
5144
5919
|
Responsive Perfection — Drawer rail, ultrawide cap, mobile compact
|
|
@@ -5342,10 +6117,26 @@
|
|
|
5342
6117
|
/* Column resize handles: a thin keyboard-accessible separator pinned to the
|
|
5343
6118
|
right edge of each chrome track; drag (or ArrowLeft/Right) writes a clamped
|
|
5344
6119
|
inline --ws-*-w. */
|
|
5345
|
-
.ds-247420 .ws-resizer { grid-row: 1 / -1; align-self: stretch; justify-self: end; width: 8px; margin-right: -4px; z-index: var(--z-raised); cursor: col-resize; background: transparent; border: none; padding: 0; touch-action: none; }
|
|
5346
|
-
.ds-247420 .ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background:
|
|
5347
|
-
.ds-247420 .ws-resizer:hover::after, .ds-247420 .ws-resizer:focus-visible::after { background: var(--accent); }
|
|
6120
|
+
.ds-247420 .ws-resizer { position: relative; grid-row: 1 / -1; align-self: stretch; justify-self: end; width: 8px; margin-right: -4px; z-index: var(--z-raised); cursor: col-resize; background: transparent; border: none; padding: 0; touch-action: none; display: flex; align-items: center; justify-content: center; }
|
|
6121
|
+
.ds-247420 .ws-resizer::after { content: ""; display: block; width: 2px; height: 100%; margin: 0 auto; background: var(--rule); opacity: 0.4; transition: background var(--dur-snap) var(--ease), opacity var(--dur-snap) var(--ease); }
|
|
6122
|
+
.ds-247420 .ws-resizer:hover::after, .ds-247420 .ws-resizer:focus-visible::after { background: var(--accent); opacity: 1; }
|
|
6123
|
+
/* Grip: a small pill of dots centered on the handle, visible at rest (low
|
|
6124
|
+
contrast) so the resizer reads as a draggable affordance rather than an
|
|
6125
|
+
invisible hit zone, then brightens to accent on hover/drag like the line. */
|
|
6126
|
+
.ds-247420 .ws-resizer::before {
|
|
6127
|
+
content: ""; position: absolute; width: 4px; height: 20px; border-radius: var(--r-hair);
|
|
6128
|
+
background-image: radial-gradient(circle, var(--fg-3) 1px, transparent 1px);
|
|
6129
|
+
background-size: 4px 5px; background-repeat: repeat-y; background-position: center;
|
|
6130
|
+
opacity: 0.5; transition: opacity var(--dur-snap) var(--ease), background-image var(--dur-snap) var(--ease);
|
|
6131
|
+
pointer-events: none;
|
|
6132
|
+
}
|
|
6133
|
+
.ds-247420 .ws-resizer:hover::before, .ds-247420 .ws-resizer:focus-visible::before {
|
|
6134
|
+
opacity: 1; background-image: radial-gradient(circle, var(--accent) 1px, transparent 1px);
|
|
6135
|
+
}
|
|
5348
6136
|
.ds-247420 .ws-resizer:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
6137
|
+
/* Active drag state: wider + fully opaque accent grip so the handle a
|
|
6138
|
+
fast-moving pointer has left :hover on still visibly reads as "gripped". */
|
|
6139
|
+
.ds-247420 .ws-resizer.ws-resizer-active::after { background: var(--accent); width: 3px; }
|
|
5349
6140
|
.ds-247420 .ws-resizer.ws-resizer-rail { grid-column: 1; }
|
|
5350
6141
|
.ds-247420 .ws-resizer.ws-resizer-sessions { grid-column: 2; }
|
|
5351
6142
|
.ds-247420 .ws-resizer.ws-resizer-pane { grid-column: 3; justify-self: end; }
|
|
@@ -5400,7 +6191,10 @@
|
|
|
5400
6191
|
.ds-247420 .ws-rail-toggle:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
5401
6192
|
.ds-247420 .ws-rail-inner { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: var(--space-3) var(--space-2); gap: var(--space-2); }
|
|
5402
6193
|
.ds-247420 .ws-rail-head { display: flex; align-items: center; min-height: 36px; padding: 0 var(--space-2); }
|
|
5403
|
-
|
|
6194
|
+
/* Wordmark treatment matches .brand (topbar.css) — same display family/weight/
|
|
6195
|
+
tracking — so the rail brand reads as the SAME logotype as every other kit's
|
|
6196
|
+
topbar wordmark instead of a lighter, differently-set imitation. */
|
|
6197
|
+
.ds-247420 .ws-rail-brand { font-family: var(--ff-display); font-weight: 700; font-size: var(--fs-body); letter-spacing: var(--tr-tight); color: var(--fg); white-space: nowrap; overflow: hidden; }
|
|
5404
6198
|
.ds-247420 .ws-rail-action {
|
|
5405
6199
|
display: flex; align-items: center; gap: var(--space-2);
|
|
5406
6200
|
padding: var(--space-2) var(--space-3); margin: var(--space-1) 0;
|
|
@@ -5423,7 +6217,9 @@
|
|
|
5423
6217
|
.ds-247420 .ws-rail-item:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
5424
6218
|
.ds-247420 .ws-rail-item.active { background: var(--accent-tint); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
|
|
5425
6219
|
.ds-247420 .ws-rail-item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
|
|
5426
|
-
|
|
6220
|
+
/* Shape/color come from the shared .ds-badge component (see app-shell/primitives.css);
|
|
6221
|
+
this class is now just the rail-item layout hook (spacing, collapsed-state targeting). */
|
|
6222
|
+
.ds-247420 .ws-rail-item-count { flex: none; margin-inline-start: var(--space-1); }
|
|
5427
6223
|
.ds-247420 .ws-rail-item-flag { width: 6px; height: 6px; border-radius: 50%; flex: none; }
|
|
5428
6224
|
.ds-247420 .ws-rail-item-flag.tone-flame { background: var(--flame); box-shadow: 0 0 0 2px color-mix(in oklab, var(--flame) 38%, transparent); }
|
|
5429
6225
|
.ds-247420 .ws-rail-foot { margin-top: auto; padding-top: var(--space-2); border-top: var(--bw-hair) solid var(--bg-3); }
|
|
@@ -5466,7 +6262,14 @@
|
|
|
5466
6262
|
because the chat thread carries its own --measure gutter. */
|
|
5467
6263
|
.ds-247420 .ws-main { flex: 1; min-height: 0; overflow: auto; display: flex; flex-direction: column; padding: var(--space-4) var(--space-5); }
|
|
5468
6264
|
.ds-247420 .ws-main.ws-main--flush { padding: 0; }
|
|
6265
|
+
/* Skip-link target (workspace-shell.js's "#ws-main" skip-link, tabindex="-1")
|
|
6266
|
+
— it does receive real keyboard-driven focus when the skip link is
|
|
6267
|
+
activated, so it needs a visible ring rather than a bare outline:none. */
|
|
5469
6268
|
.ds-247420 .ws-main:focus { outline: none; }
|
|
6269
|
+
.ds-247420 .ws-main:focus-visible {
|
|
6270
|
+
outline: var(--focus-w) solid var(--focus-color);
|
|
6271
|
+
outline-offset: calc(-1 * var(--focus-offset));
|
|
6272
|
+
}
|
|
5470
6273
|
|
|
5471
6274
|
/* Right context pane */
|
|
5472
6275
|
.ds-247420 .ws-pane {
|
|
@@ -5623,7 +6426,7 @@
|
|
|
5623
6426
|
|
|
5624
6427
|
@media (prefers-reduced-motion: reduce) {
|
|
5625
6428
|
.ds-247420 .ws-shell, .ds-247420 .ws-rail, .ds-247420 .ws-pane, .ds-247420 .ws-sessions, .ds-247420 .ws-scrim { transition: none; }
|
|
5626
|
-
.ds-247420 .ws-resizer::after { transition: none; }
|
|
6429
|
+
.ds-247420 .ws-resizer::after, .ds-247420 .ws-resizer::before { transition: none; }
|
|
5627
6430
|
}
|
|
5628
6431
|
|
|
5629
6432
|
/* ============================================================
|
|
@@ -5659,13 +6462,26 @@
|
|
|
5659
6462
|
.ds-247420 .ds-filter-pill.active { background: var(--accent-tint); color: var(--fg); border-color: var(--accent); }
|
|
5660
6463
|
.ds-247420 .ds-filter-pill:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
5661
6464
|
|
|
6465
|
+
.ds-247420 .ds-filter-pill[class*="tone-"]::before {
|
|
6466
|
+
content: '';
|
|
6467
|
+
display: inline-block; width: 7px; height: 7px; border-radius: 50%;
|
|
6468
|
+
margin-right: var(--space-1);
|
|
6469
|
+
background: currentColor;
|
|
6470
|
+
}
|
|
6471
|
+
.ds-247420 .ds-filter-pill.tone-accent { color: var(--accent-ink); }
|
|
6472
|
+
.ds-247420 .ds-filter-pill.tone-warn { color: var(--amber); }
|
|
6473
|
+
.ds-247420 .ds-filter-pill.tone-live { color: var(--sky); }
|
|
6474
|
+
.ds-247420 .ds-filter-pill.tone-sun { color: var(--sun); }
|
|
6475
|
+
.ds-247420 .ds-filter-pill.tone-success { color: var(--green-deep); }
|
|
6476
|
+
.ds-247420 .ds-filter-pill.tone-dim { color: var(--fg-3); }
|
|
6477
|
+
|
|
5662
6478
|
/* Touch floor for the new small controls. */
|
|
5663
6479
|
@media (pointer: coarse) {
|
|
5664
6480
|
.ds-247420 .row-act, .ds-247420 .ds-filter-pill { min-height: 44px; }
|
|
5665
6481
|
}
|
|
5666
6482
|
|
|
5667
6483
|
/* Disabled file actions (read-only row / in-flight mutation) stay visible but inert. */
|
|
5668
|
-
.ds-247420 .ds-file-act:disabled { opacity: .
|
|
6484
|
+
.ds-247420 .ds-file-act:disabled { opacity: .5; cursor: default; }
|
|
5669
6485
|
.ds-247420 .ds-file-act:disabled:hover { background: transparent; color: var(--fg-3); }
|
|
5670
6486
|
.ds-247420 .ds-file-act:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
5671
6487
|
|
|
@@ -5698,6 +6514,39 @@
|
|
|
5698
6514
|
.ds-247420 .ds-live-log { height: auto; max-height: none; overflow: visible; }
|
|
5699
6515
|
.ds-247420 .ds-stat, .ds-247420 .kpi-card { border: 1px solid var(--rule); }
|
|
5700
6516
|
.ds-247420 .ds-session-row { break-inside: avoid; }
|
|
6517
|
+
|
|
6518
|
+
/* Receipt table (Receipt() in src/components/content/panel.js, `.kv`) — the
|
|
6519
|
+
project_page kit's "receipt" section, and any other kv-table consumer.
|
|
6520
|
+
On screen it inherits panel/token colors that can render as near-white
|
|
6521
|
+
text on a printer's assumed-white page background if the browser's
|
|
6522
|
+
"background graphics" print option is off (the common default); force
|
|
6523
|
+
the LIGHT-theme ink/paper tokens (real print-page colors, not a raw
|
|
6524
|
+
literal — --ink/--paper are the same "true black text on true white
|
|
6525
|
+
page" values the light theme already defines) and visible cell borders
|
|
6526
|
+
so it stays legible without relying on background-graphics printing at
|
|
6527
|
+
all. break-inside:avoid keeps a receipt from splitting a row across a
|
|
6528
|
+
page boundary. */
|
|
6529
|
+
.ds-247420 .kv { border-collapse: collapse; width: 100%; color: var(--ink); background: var(--paper); }
|
|
6530
|
+
.ds-247420 .kv tr { break-inside: avoid; }
|
|
6531
|
+
.ds-247420 .kv td { border: 1px solid var(--paper-3); padding: 4px 8px; color: var(--ink); }
|
|
6532
|
+
|
|
6533
|
+
/* Any button/interactive-only affordance still present inside otherwise-
|
|
6534
|
+
printable content (copy buttons, expand/collapse toggles, filter pills,
|
|
6535
|
+
the receipt/doc section's own action row) is chrome, not content. */
|
|
6536
|
+
.ds-247420 .btn, .ds-247420 .btn-primary, .ds-247420 .btn-ghost, .ds-247420 .row-act, .ds-247420 .ds-filter-pills, .ds-247420 .app-search, .ds-247420 input[type="search"] { display: none; }
|
|
6537
|
+
|
|
6538
|
+
/* Force real ink-on-paper for body copy: panel/fg tokens are tuned for
|
|
6539
|
+
screen surfaces (including dark theme, where --panel-text can resolve
|
|
6540
|
+
near-white) and a printer defaults to a white page regardless of
|
|
6541
|
+
data-theme, so an unconverted dark-theme page would print near-invisible
|
|
6542
|
+
text without this override. Same --ink/--paper light-theme pair as the
|
|
6543
|
+
receipt table above, not a second raw literal. */
|
|
6544
|
+
/* No !important: source order already wins here (this rule is the last
|
|
6545
|
+
word inside its own @media print block, same as every other override in
|
|
6546
|
+
this file), and an unconditional !important on `body` would beat even a
|
|
6547
|
+
future print-specific consumer override with higher specificity. */
|
|
6548
|
+
.ds-247420 body, .ds-247420 .app-main, .ds-247420 .page-body, .ds-247420 .ds-lede { color: var(--ink); background: var(--paper); }
|
|
6549
|
+
.ds-247420 a { color: var(--ink); text-decoration: underline; }
|
|
5701
6550
|
}
|
|
5702
6551
|
|
|
5703
6552
|
/* ============================================================
|
|
@@ -6056,7 +6905,17 @@
|
|
|
6056
6905
|
aspect-ratio: auto;
|
|
6057
6906
|
}
|
|
6058
6907
|
}
|
|
6059
|
-
.ds-247420 .ds-deck-slide {
|
|
6908
|
+
.ds-247420 .ds-deck-slide {
|
|
6909
|
+
flex: 1; display: flex; min-width: 0;
|
|
6910
|
+
animation: ds-deck-slide-in var(--dur-base) var(--ease);
|
|
6911
|
+
}
|
|
6912
|
+
@media (prefers-reduced-motion: reduce) {
|
|
6913
|
+
.ds-247420 .ds-deck-slide { animation: none; }
|
|
6914
|
+
}
|
|
6915
|
+
@keyframes ds-deck-slide-in {
|
|
6916
|
+
from { opacity: 0; transform: translateY(var(--space-1-75)); }
|
|
6917
|
+
to { opacity: 1; transform: none; }
|
|
6918
|
+
}
|
|
6060
6919
|
.ds-247420 .ds-deck-controls {
|
|
6061
6920
|
/* 14px sits between --space-2-75 (12) and --space-3 (16) with no tier; it is
|
|
6062
6921
|
the deck control spacing tuned against the mono glyph run. */
|
|
@@ -6067,6 +6926,19 @@
|
|
|
6067
6926
|
@media (pointer: coarse) {
|
|
6068
6927
|
.ds-247420 .ds-deck-controls .btn { min-height: 44px; min-width: 44px; }
|
|
6069
6928
|
}
|
|
6929
|
+
/* Dot progress indicator: one dot per slide, current slide filled with
|
|
6930
|
+
--accent (same fill token .ds-dot-on uses elsewhere in the system), rest
|
|
6931
|
+
dim at --fg-3 so the row reads as a track, not a second counter. */
|
|
6932
|
+
.ds-247420 .ds-deck-progress {
|
|
6933
|
+
display: flex; align-items: center; justify-content: center;
|
|
6934
|
+
gap: var(--space-1-5); padding-bottom: var(--space-2);
|
|
6935
|
+
}
|
|
6936
|
+
.ds-247420 .ds-deck-dot {
|
|
6937
|
+
width: var(--space-1-5); height: var(--space-1-5); border-radius: 50%;
|
|
6938
|
+
background: var(--fg-3); flex: 0 0 auto;
|
|
6939
|
+
transition: background var(--dur-base) var(--ease), transform var(--dur-base) var(--ease);
|
|
6940
|
+
}
|
|
6941
|
+
.ds-247420 .ds-deck-dot--active { background: var(--accent); transform: scale(1.3); }
|
|
6070
6942
|
/* Kit small-label voice — one local composition of the house `.t-label` recipe
|
|
6071
6943
|
(base.css) for every eyebrow/label in the appended kit blocks below. These
|
|
6072
6944
|
previously each restated the four declarations with drifted tracking
|
|
@@ -6177,7 +7049,12 @@
|
|
|
6177
7049
|
}
|
|
6178
7050
|
.ds-247420 .ds-gallery-tile {
|
|
6179
7051
|
cursor: pointer; display: flex; flex-direction: column; gap: var(--space-1-75);
|
|
6180
|
-
padding: var(--space-2-75); border-radius: var(--r-1);
|
|
7052
|
+
padding: var(--space-2-75); border-radius: var(--r-1);
|
|
7053
|
+
/* Fixed aspect-ratio (not just a min-height floor) so every tile in the grid
|
|
7054
|
+
occupies the same shape regardless of caption length — the ascii specimen
|
|
7055
|
+
is centered inside via .ds-tile-cap's flex alignment, the equivalent of
|
|
7056
|
+
object-fit: cover for a text tile with no bitmap to crop. */
|
|
7057
|
+
aspect-ratio: 4 / 3;
|
|
6181
7058
|
border: 0; text-align: left; font: inherit; color: inherit;
|
|
6182
7059
|
background: var(--tile-tone, var(--panel-1));
|
|
6183
7060
|
transition: transform var(--dur-base) var(--ease), box-shadow var(--dur-base) var(--ease);
|
|
@@ -6187,7 +7064,7 @@
|
|
|
6187
7064
|
translateY + shadow idiom .chat-msg:hover .chat-bubble already uses. */
|
|
6188
7065
|
.ds-247420 .ds-gallery-tile:hover { transform: translateY(-2px); box-shadow: 0 2px 8px color-mix(in oklab, var(--fg) 10%, transparent); }
|
|
6189
7066
|
.ds-247420 .ds-gallery-tile:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
6190
|
-
.ds-247420 .ds-gallery-tile--tight {
|
|
7067
|
+
.ds-247420 .ds-gallery-tile--tight { aspect-ratio: 3 / 2; }
|
|
6191
7068
|
/* The lightbox scrim/card chrome itself is now Dialog's (.ds-ep-dialog /
|
|
6192
7069
|
.ds-ep-dialog-backdrop in editor-primitives.css) — Dialog already ships
|
|
6193
7070
|
role="dialog", aria-modal, Tab-trap and focus-restore-on-close, which the
|
|
@@ -6211,13 +7088,21 @@
|
|
|
6211
7088
|
@media (max-width: 480px) {
|
|
6212
7089
|
.ds-247420 .ds-topbar-search { flex-basis: 100%; }
|
|
6213
7090
|
}
|
|
6214
|
-
.ds-
|
|
7091
|
+
/* Namespaced .ds-kit-empty-state (not .ds-empty-state) -- .ds-empty-state is
|
|
7092
|
+
primitives.css's shared base (padding var(--space-6), color var(--fg-3));
|
|
7093
|
+
this sheet loads after it in app-shell.css's import order, so reusing the
|
|
7094
|
+
same class name silently overrode that base's padding/color for every
|
|
7095
|
+
consumer, defeating the "shared base, one place" contract primitives.css
|
|
7096
|
+
documents. This block is unused by any component today, but kept
|
|
7097
|
+
namespaced so a future consumer gets this sheet's fluid clamp() treatment
|
|
7098
|
+
deliberately rather than by cascade accident. */
|
|
7099
|
+
.ds-247420 .ds-kit-empty-state { padding: clamp(var(--space-3), 5vw, var(--space-4)); text-align: center; color: var(--panel-text-3); }
|
|
6215
7100
|
/* Fluid ICON size (empty-state mark), not a type tier: it scales with the
|
|
6216
7101
|
viewport between 24 and 32px. Every fluid --fs-* tier is a heading clamp
|
|
6217
7102
|
tuned to cqi + heading weight, so none of them substitutes here. */
|
|
6218
|
-
.ds-247420 .ds-empty-state-glyph { font-size: clamp(24px, 6vw, 32px); }
|
|
6219
|
-
.ds-247420 .ds-empty-state-msg { margin: var(--space-1-75) 0; }
|
|
6220
|
-
.ds-247420 .ds-empty-state-hint { margin: 0; font-size: var(--fs-sm); }
|
|
7103
|
+
.ds-247420 .ds-kit-empty-state-glyph { font-size: clamp(24px, 6vw, 32px); }
|
|
7104
|
+
.ds-247420 .ds-kit-empty-state-msg { margin: var(--space-1-75) 0; }
|
|
7105
|
+
.ds-247420 .ds-kit-empty-state-hint { margin: 0; font-size: var(--fs-sm); }
|
|
6221
7106
|
|
|
6222
7107
|
/* --- system primer ------------------------------------------ */
|
|
6223
7108
|
/* The three primer panels below share one fluid inset,
|
|
@@ -6289,12 +7174,21 @@
|
|
|
6289
7174
|
gap: var(--space-1-75, 6px);
|
|
6290
7175
|
}
|
|
6291
7176
|
/* Table() scroll containment — wide tables scroll inside their own box,
|
|
6292
|
-
never the page body.
|
|
7177
|
+
never the page body. overflow-x:auto alone works but gives no visible cue
|
|
7178
|
+
that a table is wider than its box (macOS overlay scrollbars stay hidden
|
|
7179
|
+
until an active hover/scroll gesture) -- columns beyond the fold read as
|
|
7180
|
+
simply missing rather than reachable. An always-visible thin scrollbar
|
|
7181
|
+
track makes the overflow legible without a gesture first. */
|
|
6293
7182
|
.ds-247420 .ds-table-wrap {
|
|
6294
7183
|
overflow-x: auto;
|
|
6295
7184
|
-webkit-overflow-scrolling: touch;
|
|
6296
7185
|
max-width: 100%;
|
|
7186
|
+
scrollbar-width: thin;
|
|
7187
|
+
scrollbar-color: var(--rule-strong) transparent;
|
|
6297
7188
|
}
|
|
7189
|
+
.ds-247420 .ds-table-wrap::-webkit-scrollbar { height: 8px; }
|
|
7190
|
+
.ds-247420 .ds-table-wrap::-webkit-scrollbar-thumb { background: var(--rule-strong); border-radius: var(--r-pill, 999px); }
|
|
7191
|
+
.ds-247420 .ds-table-wrap::-webkit-scrollbar-track { background: transparent; }
|
|
6298
7192
|
.ds-247420 .ds-table-wrap > table { min-width: 100%; }
|
|
6299
7193
|
/* Sortable column headers (Table's opt-in sortable prop) — a docstudio-cue
|
|
6300
7194
|
addition: color stays neutral at rest (this is a structural control, not a
|
|
@@ -6341,6 +7235,11 @@
|
|
|
6341
7235
|
.ds-247420 .ds-btn-row-tight { gap: var(--space-1-75, 6px); }
|
|
6342
7236
|
.ds-247420 .ds-key-input { flex: 1 1 160px; min-width: 0; font-family: var(--ff-mono); }
|
|
6343
7237
|
.ds-247420 .ds-toggle-btn { min-width: 78px; }
|
|
7238
|
+
/* Side-by-side checked/unchecked reference pair (settings kit theme panel) --
|
|
7239
|
+
documents the visual difference between states in one static, non-live
|
|
7240
|
+
spot rather than requiring a viewer to toggle a real control back and
|
|
7241
|
+
forth to compare. */
|
|
7242
|
+
.ds-247420 .ds-toggle-state-sample { display: flex; align-items: center; gap: var(--space-1-5, 6px); }
|
|
6344
7243
|
.ds-247420 .ds-toggle-label { margin-left: var(--space-2, 8px); color: inherit; opacity: 0.7; }
|
|
6345
7244
|
.ds-247420 .ds-btn-warn { color: var(--warn); }
|
|
6346
7245
|
/* Raw --mascot text measures 3.11:1 on paper (fails 4.5:1); --mascot-deep is
|
|
@@ -6356,6 +7255,14 @@
|
|
|
6356
7255
|
justify-content: flex-end; gap: var(--space-2); flex-wrap: wrap;
|
|
6357
7256
|
padding: calc(var(--space-2-75) * var(--density)) calc(var(--space-3) * var(--density));
|
|
6358
7257
|
background: var(--panel-2); border-radius: var(--r-1);
|
|
7258
|
+
/* --panel-1 (this bar's parent .panel surface) and --panel-2 are adjacent
|
|
7259
|
+
lightness steps that measure only ~1.1-1.5:1 apart (both themes) -- too
|
|
7260
|
+
close to read as a distinct nesting depth by background tone alone.
|
|
7261
|
+
A hairline border is the same edge-definition device .panel itself
|
|
7262
|
+
already uses (see the top of this file) rather than a token-lightness
|
|
7263
|
+
change, which would risk the fg-3-on-panel-2 text contrast that is
|
|
7264
|
+
already right at its AA floor in the dark theme. */
|
|
7265
|
+
border: var(--bw-hair) solid var(--rule);
|
|
6359
7266
|
margin: calc(var(--space-5) * var(--density)) 0 var(--space-2);
|
|
6360
7267
|
box-shadow: var(--shadow-2, var(--shadow-1));
|
|
6361
7268
|
}
|
|
@@ -6401,13 +7308,37 @@
|
|
|
6401
7308
|
/* .ds-auth-field-label joins the kit small-label voice above, no overrides. */
|
|
6402
7309
|
.ds-247420 .ds-auth-field-input-row { position: relative; display: flex; align-items: center; }
|
|
6403
7310
|
/* Reserves room for the absolutely-positioned toggle: its --space-1 inset plus
|
|
6404
|
-
the --ds-icon-btn-sm 26px box, so the input text never sits under it.
|
|
7311
|
+
the --ds-icon-btn-sm 26px box, so the input text never sits under it. This
|
|
7312
|
+
only holds at the pointer:fine 26px box size, though -- the coarse-pointer
|
|
7313
|
+
touch-floor rule (states-interactions.css) grows .ds-icon-btn-sm to a
|
|
7314
|
+
min-width/height of 44px without this padding following it, so on a
|
|
7315
|
+
touchscreen the enlarged hit target actually overlapped 14px into the
|
|
7316
|
+
typed password text (44 + 4 inset > 34 reserved). Reserve for the coarse
|
|
7317
|
+
floor too, gated behind the same media query, so clearance holds at both
|
|
7318
|
+
sizes instead of only the desktop one. */
|
|
6405
7319
|
.ds-247420 .ds-auth-field-input-row .input { flex: 1 1 auto; padding-right: calc(26px + var(--space-2)); }
|
|
7320
|
+
@media (pointer: coarse) {
|
|
7321
|
+
.ds-247420 .ds-auth-field-input-row .input { padding-right: calc(44px + var(--space-2)); }
|
|
7322
|
+
}
|
|
6406
7323
|
.ds-247420 .ds-auth-pw-toggle { position: absolute; right: var(--space-1); }
|
|
6407
7324
|
.ds-247420 .ds-auth-row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
|
|
6408
7325
|
.ds-247420 .ds-auth-remember { display: flex; align-items: center; gap: var(--space-1-75); cursor: pointer; }
|
|
7326
|
+
/* The native checkbox is already re-tinted site-wide via `accent-color:
|
|
7327
|
+
var(--accent-ink)` in states-interactions.css (that rule's own comment
|
|
7328
|
+
names this exact control) -- reused here rather than hand-drawing a new
|
|
7329
|
+
checkbox component. What that global rule doesn't cover is size: the UA
|
|
7330
|
+
default box renders at ~13px, which is under the 24px comfortable-tap
|
|
7331
|
+
floor other controls in this row (the link text, the input fields) sit
|
|
7332
|
+
above. Sized up on the existing --space-2-5 token, no new primitive. */
|
|
7333
|
+
.ds-247420 .ds-auth-remember input[type="checkbox"] { width: var(--space-2-5); height: var(--space-2-5); margin: 0; }
|
|
6409
7334
|
.ds-247420 .ds-auth-remember-text { color: var(--panel-text-2); font-size: var(--fs-tiny); }
|
|
6410
|
-
|
|
7335
|
+
/* --accent-ink, not --accent, per the design system's text-vs-fill split
|
|
7336
|
+
(AGENTS.md): --accent is a background/border-color lead only, --accent-ink
|
|
7337
|
+
is the tone actually verified for text contrast. The link was previously
|
|
7338
|
+
unstyled prose color at --fs-tiny, reading as inert grey next to the
|
|
7339
|
+
checkbox label it shares a row with. */
|
|
7340
|
+
.ds-247420 .ds-auth-forgot { font-size: var(--fs-tiny); color: var(--accent-ink); font-weight: 500; }
|
|
7341
|
+
.ds-247420 .ds-auth-forgot:hover { text-decoration: underline; }
|
|
6411
7342
|
/* Error and status share layout but not color: a color-only distinction
|
|
6412
7343
|
between role="alert" (something is wrong) and role="status" (informational)
|
|
6413
7344
|
fails WCAG 1.4.1, so each also carries a distinct ASCII marker via ::before —
|
|
@@ -6417,6 +7348,28 @@
|
|
|
6417
7348
|
.ds-247420 .ds-auth-error::before { content: '[!]'; flex: none; }
|
|
6418
7349
|
.ds-247420 .ds-auth-status { color: var(--panel-text-2); }
|
|
6419
7350
|
.ds-247420 .ds-auth-status::before { content: '[i]'; flex: none; }
|
|
7351
|
+
/* The shared Divider() label defaults to --fs-tiny/--panel-text-3 (editor-
|
|
7352
|
+
primitives.css), tuned for a dense editor toolbar rule -- inside the auth
|
|
7353
|
+
form it sat at the same weight as fine print two rows below it and read
|
|
7354
|
+
as barely-there rather than a section break between the password form and
|
|
7355
|
+
the OAuth row. Scoped to this form only (never edit the shared component
|
|
7356
|
+
sheet for one consumer): borrows the kit small-label voice above (mono,
|
|
7357
|
+
--fs-nano, --tr-label, uppercase) at --panel-text-2 instead of the
|
|
7358
|
+
dimmer -3 tier, plus the ::before/::after rule lines pushed to full
|
|
7359
|
+
--panel-text opacity so the break itself, not just the label, is visible. */
|
|
7360
|
+
.ds-247420 .ds-auth-form .ds-ep-divider-labeled { margin: var(--space-1) 0; }
|
|
7361
|
+
.ds-247420 .ds-auth-form .ds-ep-divider-labeled::before,
|
|
7362
|
+
.ds-247420 .ds-auth-form .ds-ep-divider-labeled::after {
|
|
7363
|
+
border-top-color: var(--panel-text-3);
|
|
7364
|
+
}
|
|
7365
|
+
.ds-247420 .ds-auth-form .ds-ep-divider-label {
|
|
7366
|
+
font-family: var(--ff-mono);
|
|
7367
|
+
font-size: var(--fs-nano);
|
|
7368
|
+
font-weight: 600;
|
|
7369
|
+
letter-spacing: var(--tr-label);
|
|
7370
|
+
text-transform: uppercase;
|
|
7371
|
+
color: var(--panel-text-2);
|
|
7372
|
+
}
|
|
6420
7373
|
.ds-247420 .ds-auth-providers { display: flex; gap: var(--space-2); flex-wrap: wrap; }
|
|
6421
7374
|
.ds-247420 .ds-auth-provider-btn { flex: 1 1 100px; min-width: 0; display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-2-5); }
|
|
6422
7375
|
.ds-247420 .ds-auth-provider-btn--loading { opacity: 0.7; pointer-events: none; }
|
|
@@ -6483,6 +7436,14 @@
|
|
|
6483
7436
|
display: flex; flex-direction: column; gap: 0;
|
|
6484
7437
|
background: var(--ink); border-radius: var(--r-1);
|
|
6485
7438
|
font-family: var(--ff-mono); font-size: var(--fs-micro); line-height: 1.65;
|
|
7439
|
+
/* Responsive strategy for long logs: cap the scrollback height and scroll
|
|
7440
|
+
vertically rather than growing the page indefinitely; long command/output
|
|
7441
|
+
lines wrap (see .cli .cmd's overflow-wrap: anywhere below) instead of
|
|
7442
|
+
scrolling horizontally, so wrapping is the chosen default over
|
|
7443
|
+
horizontal scroll for this kit. */
|
|
7444
|
+
max-height: 60vh;
|
|
7445
|
+
overflow-y: auto;
|
|
7446
|
+
overflow-wrap: anywhere;
|
|
6486
7447
|
}
|
|
6487
7448
|
/* .cli is authored in hero-content.css as a STANDALONE hero code block --
|
|
6488
7449
|
20px/24px padding, --fs-lg type, --r-3 radius and its own --ink background
|
|
@@ -6584,6 +7545,7 @@
|
|
|
6584
7545
|
border-radius: 50%; background: var(--bg-3); color: var(--fg);
|
|
6585
7546
|
font-family: var(--ff-mono); font-weight: 600; text-transform: lowercase;
|
|
6586
7547
|
letter-spacing: 0.02em; user-select: none; flex-shrink: 0; object-fit: cover;
|
|
7548
|
+
box-shadow: inset 0 0 0 1px var(--rule);
|
|
6587
7549
|
}
|
|
6588
7550
|
.ds-247420 .ds-avatar-sm { width: 24px; height: 24px; font-size: var(--fs-pico); }
|
|
6589
7551
|
.ds-247420 .ds-avatar-md { width: 36px; height: 36px; font-size: var(--fs-micro); }
|
|
@@ -6711,6 +7673,7 @@
|
|
|
6711
7673
|
font-weight: 600;
|
|
6712
7674
|
line-height: 1;
|
|
6713
7675
|
user-select: none;
|
|
7676
|
+
box-shadow: inset 0 0 0 1px var(--rule);
|
|
6714
7677
|
}
|
|
6715
7678
|
|
|
6716
7679
|
/* Body stack — name + time on one baseline, text beneath. .chat-stack's
|
|
@@ -7102,12 +8065,16 @@
|
|
|
7102
8065
|
}
|
|
7103
8066
|
.ds-247420 .ds-plugins-version { font-size: var(--fs-micro); color: var(--fg-3); }
|
|
7104
8067
|
|
|
8068
|
+
/* Same track/knob proportions as the shared .ds-toggle primitive
|
|
8069
|
+
(states-interactions.css) -- kept as its own class since ds-plugins-toggle
|
|
8070
|
+
is a plain <button>+.on instead of .ds-toggle's [aria-checked] contract,
|
|
8071
|
+
but sized and colored to match it exactly rather than drifting. */
|
|
7105
8072
|
.ds-247420 .ds-plugins-toggle {
|
|
7106
|
-
flex: 0 0 auto; width: 40px; height: 22px; border-radius:
|
|
8073
|
+
flex: 0 0 auto; width: 40px; height: 22px; border-radius: var(--r-pill, 999px); border: none; padding: 0;
|
|
7107
8074
|
background: var(--rule); position: relative; cursor: pointer;
|
|
7108
8075
|
transition: background var(--dur-snap) var(--ease);
|
|
7109
8076
|
}
|
|
7110
|
-
.ds-247420 .ds-plugins-toggle.on { background: var(--accent); }
|
|
8077
|
+
.ds-247420 .ds-plugins-toggle.on { background: var(--accent-ink); }
|
|
7111
8078
|
.ds-247420 .ds-plugins-toggle[disabled] { cursor: wait; opacity: 0.65; }
|
|
7112
8079
|
.ds-247420 .ds-plugins-toggle-knob {
|
|
7113
8080
|
position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%;
|
|
@@ -7344,11 +8311,11 @@
|
|
|
7344
8311
|
.ds-247420 .ds-otp-box:focus-visible {
|
|
7345
8312
|
outline: none;
|
|
7346
8313
|
border-color: var(--accent);
|
|
7347
|
-
box-shadow:
|
|
8314
|
+
box-shadow: var(--focus-ring-inset);
|
|
7348
8315
|
}
|
|
7349
8316
|
.ds-247420 .ds-otp-box-filled { border-color: var(--rule-strong); background: var(--bg-3); }
|
|
7350
8317
|
.ds-247420 .ds-otp-box-error { border-color: var(--red); }
|
|
7351
|
-
.ds-247420 .ds-otp-box-error:focus-visible { box-shadow:
|
|
8318
|
+
.ds-247420 .ds-otp-box-error:focus-visible { box-shadow: var(--focus-ring-inset); }
|
|
7352
8319
|
.ds-247420 .ds-otp-box:disabled { opacity: 0.5; cursor: default; }
|
|
7353
8320
|
|
|
7354
8321
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -7612,6 +8579,11 @@
|
|
|
7612
8579
|
border-radius: var(--r-pill);
|
|
7613
8580
|
background: var(--bg-2);
|
|
7614
8581
|
}
|
|
8582
|
+
/* .ds-collab-chip-avatar (24px identity circle) and .ds-collab-chip-status
|
|
8583
|
+
(8px status dot) below are both circular via border-radius: 50% but are
|
|
8584
|
+
intentionally distinct: different sizes, different content (initial vs.
|
|
8585
|
+
plain fill), different positioning role (layout box vs. absolute badge).
|
|
8586
|
+
Not extracting a shared class -- there's nothing substantive to share. */
|
|
7615
8587
|
.ds-247420 .ds-collab-chip-avatar {
|
|
7616
8588
|
position: relative;
|
|
7617
8589
|
width: 24px;
|
|
@@ -7726,7 +8698,7 @@
|
|
|
7726
8698
|
justify-content: center;
|
|
7727
8699
|
font-family: var(--ff-body);
|
|
7728
8700
|
font-size: var(--fs-lg);
|
|
7729
|
-
font-weight:
|
|
8701
|
+
font-weight: var(--fw-medium);
|
|
7730
8702
|
letter-spacing: var(--tr-tight);
|
|
7731
8703
|
cursor: pointer;
|
|
7732
8704
|
overflow: hidden;
|
|
@@ -7776,11 +8748,14 @@
|
|
|
7776
8748
|
min-width: 18px;
|
|
7777
8749
|
height: 18px;
|
|
7778
8750
|
padding: 0 var(--space-1-5);
|
|
8751
|
+
/* --ink, not --paper: --paper is a fixed near-white, which measures ~3:1 on
|
|
8752
|
+
--warn (#FF5A52) -- below the 4.5:1 AA floor. --ink clears it (same fix
|
|
8753
|
+
as .btn-primary.danger in app-shell/files.css). */
|
|
7779
8754
|
background: var(--warn);
|
|
7780
|
-
color: var(--
|
|
8755
|
+
color: var(--ink);
|
|
7781
8756
|
font-family: var(--ff-mono);
|
|
7782
8757
|
font-size: var(--fs-micro);
|
|
7783
|
-
font-weight:
|
|
8758
|
+
font-weight: var(--fw-bold);
|
|
7784
8759
|
border-radius: var(--r-pill);
|
|
7785
8760
|
display: flex;
|
|
7786
8761
|
align-items: center;
|
|
@@ -7799,7 +8774,7 @@
|
|
|
7799
8774
|
align-items: center;
|
|
7800
8775
|
justify-content: center;
|
|
7801
8776
|
font-size: var(--fs-xl);
|
|
7802
|
-
font-weight:
|
|
8777
|
+
font-weight: var(--fw-regular);
|
|
7803
8778
|
cursor: pointer;
|
|
7804
8779
|
border: 0;
|
|
7805
8780
|
transition:
|
|
@@ -7845,7 +8820,7 @@
|
|
|
7845
8820
|
padding: var(--space-2-75) var(--space-3);
|
|
7846
8821
|
background: var(--bg-2);
|
|
7847
8822
|
box-shadow: 0 1px 0 color-mix(in oklab, var(--fg) 8%, transparent);
|
|
7848
|
-
font-weight:
|
|
8823
|
+
font-weight: var(--fw-medium);
|
|
7849
8824
|
font-size: var(--fs-sm);
|
|
7850
8825
|
letter-spacing: -0.01em;
|
|
7851
8826
|
/* No cursor:pointer, no :hover background, no user-select:none. This is a
|
|
@@ -7900,7 +8875,7 @@
|
|
|
7900
8875
|
padding: var(--space-1) var(--space-2);
|
|
7901
8876
|
font-family: var(--ff-body);
|
|
7902
8877
|
font-size: var(--fs-micro);
|
|
7903
|
-
font-weight:
|
|
8878
|
+
font-weight: var(--fw-medium);
|
|
7904
8879
|
color: var(--fg-3);
|
|
7905
8880
|
letter-spacing: var(--tr-caps);
|
|
7906
8881
|
text-transform: uppercase;
|
|
@@ -7939,7 +8914,7 @@
|
|
|
7939
8914
|
font-family: var(--ff-mono);
|
|
7940
8915
|
font-size: var(--fs-micro);
|
|
7941
8916
|
color: var(--fg-3);
|
|
7942
|
-
font-weight:
|
|
8917
|
+
font-weight: var(--fw-medium);
|
|
7943
8918
|
letter-spacing: 0;
|
|
7944
8919
|
text-transform: none;
|
|
7945
8920
|
}
|
|
@@ -8009,7 +8984,7 @@
|
|
|
8009
8984
|
.ds-247420 .cm-channel-item.active {
|
|
8010
8985
|
background: color-mix(in oklab, var(--fg) 10%, transparent);
|
|
8011
8986
|
color: var(--fg);
|
|
8012
|
-
font-weight:
|
|
8987
|
+
font-weight: var(--fw-medium);
|
|
8013
8988
|
}
|
|
8014
8989
|
.ds-247420 .cm-channel-item.active::before {
|
|
8015
8990
|
content: '';
|
|
@@ -8108,11 +9083,14 @@
|
|
|
8108
9083
|
min-width: 16px;
|
|
8109
9084
|
height: 16px;
|
|
8110
9085
|
padding: 0 var(--space-1-5);
|
|
9086
|
+
/* --ink, not --paper: --paper is a fixed near-white, which measures ~3:1 on
|
|
9087
|
+
--warn (#FF5A52) -- below the 4.5:1 AA floor. --ink clears it (same fix
|
|
9088
|
+
as .btn-primary.danger in app-shell/files.css). */
|
|
8111
9089
|
background: var(--warn);
|
|
8112
|
-
color: var(--
|
|
9090
|
+
color: var(--ink);
|
|
8113
9091
|
font-family: var(--ff-mono);
|
|
8114
9092
|
font-size: var(--fs-micro);
|
|
8115
|
-
font-weight:
|
|
9093
|
+
font-weight: var(--fw-bold);
|
|
8116
9094
|
border-radius: var(--r-pill);
|
|
8117
9095
|
display: inline-flex;
|
|
8118
9096
|
align-items: center;
|
|
@@ -8191,13 +9169,16 @@
|
|
|
8191
9169
|
height: 20px;
|
|
8192
9170
|
border-radius: 50%;
|
|
8193
9171
|
background: var(--avatar-bg, var(--bg-3));
|
|
8194
|
-
color: var(--fg-2);
|
|
9172
|
+
color: var(--avatar-fg, var(--fg-2));
|
|
8195
9173
|
display: inline-flex;
|
|
8196
9174
|
align-items: center;
|
|
8197
9175
|
justify-content: center;
|
|
8198
9176
|
font-size: var(--fs-pico);
|
|
8199
|
-
font-weight:
|
|
9177
|
+
font-weight: var(--fw-medium);
|
|
8200
9178
|
overflow: hidden;
|
|
9179
|
+
/* Depth over a flat solid-color disc: a hairline inset ring so avatars
|
|
9180
|
+
read as a real surface element, not a wireframe placeholder. */
|
|
9181
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fg) 10%, transparent);
|
|
8201
9182
|
transition: box-shadow var(--dur-snap) var(--ease);
|
|
8202
9183
|
}
|
|
8203
9184
|
.ds-247420 .cm-ch-voice-user-avatar img {
|
|
@@ -8235,7 +9216,7 @@
|
|
|
8235
9216
|
a pulsing dot and must read as the loudest thing in the strip). */
|
|
8236
9217
|
.ds-247420 .cm-vs-label {
|
|
8237
9218
|
color: var(--green);
|
|
8238
|
-
font-weight:
|
|
9219
|
+
font-weight: var(--fw-bold);
|
|
8239
9220
|
display: inline-flex;
|
|
8240
9221
|
align-items: center;
|
|
8241
9222
|
gap: var(--space-1-75);
|
|
@@ -8261,7 +9242,7 @@
|
|
|
8261
9242
|
|
|
8262
9243
|
.ds-247420 .cm-vs-channel {
|
|
8263
9244
|
font-size: var(--fs-sm);
|
|
8264
|
-
font-weight:
|
|
9245
|
+
font-weight: var(--fw-medium);
|
|
8265
9246
|
color: var(--fg);
|
|
8266
9247
|
overflow: hidden;
|
|
8267
9248
|
text-overflow: ellipsis;
|
|
@@ -8289,7 +9270,7 @@
|
|
|
8289
9270
|
border-radius: var(--r-1);
|
|
8290
9271
|
font-family: var(--ff-body);
|
|
8291
9272
|
font-size: var(--fs-xs);
|
|
8292
|
-
font-weight:
|
|
9273
|
+
font-weight: var(--fw-medium);
|
|
8293
9274
|
cursor: pointer;
|
|
8294
9275
|
transition: background var(--dur-snap) var(--ease), color var(--dur-snap) var(--ease);
|
|
8295
9276
|
}
|
|
@@ -8297,8 +9278,11 @@
|
|
|
8297
9278
|
background: color-mix(in oklab, var(--fg) 18%, transparent);
|
|
8298
9279
|
}
|
|
8299
9280
|
.ds-247420 .cm-vs-btn.danger {
|
|
9281
|
+
/* --ink, not --paper: --paper is a fixed near-white, which measures ~3:1 on
|
|
9282
|
+
--warn (#FF5A52) -- below the 4.5:1 AA floor. Same fix pattern as
|
|
9283
|
+
.btn-primary.danger in app-shell/files.css. */
|
|
8300
9284
|
background: var(--warn);
|
|
8301
|
-
color: var(--
|
|
9285
|
+
color: var(--ink);
|
|
8302
9286
|
}
|
|
8303
9287
|
.ds-247420 .cm-vs-btn.danger:hover {
|
|
8304
9288
|
background: color-mix(in oklab, var(--warn) 80%, var(--ink));
|
|
@@ -8323,13 +9307,14 @@
|
|
|
8323
9307
|
height: 32px;
|
|
8324
9308
|
border-radius: 50%;
|
|
8325
9309
|
background: var(--avatar-bg, var(--bg-3));
|
|
8326
|
-
color: var(--fg-2);
|
|
9310
|
+
color: var(--avatar-fg, var(--fg-2));
|
|
8327
9311
|
display: inline-flex;
|
|
8328
9312
|
align-items: center;
|
|
8329
9313
|
justify-content: center;
|
|
8330
9314
|
font-size: var(--fs-xs);
|
|
8331
|
-
font-weight:
|
|
9315
|
+
font-weight: var(--fw-medium);
|
|
8332
9316
|
overflow: hidden;
|
|
9317
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fg) 10%, transparent);
|
|
8333
9318
|
}
|
|
8334
9319
|
.ds-247420 .cm-user-avatar img {
|
|
8335
9320
|
width: 100%;
|
|
@@ -8358,7 +9343,7 @@
|
|
|
8358
9343
|
}
|
|
8359
9344
|
.ds-247420 .cm-user-name {
|
|
8360
9345
|
font-size: var(--fs-xs);
|
|
8361
|
-
font-weight:
|
|
9346
|
+
font-weight: var(--fw-medium);
|
|
8362
9347
|
color: var(--fg);
|
|
8363
9348
|
overflow: hidden;
|
|
8364
9349
|
text-overflow: ellipsis;
|
|
@@ -8439,7 +9424,7 @@
|
|
|
8439
9424
|
pinned weight/size/colour, but a bare h1 also brings a UA block margin
|
|
8440
9425
|
that would break this flex row — so the margin is zeroed explicitly. */
|
|
8441
9426
|
margin: 0;
|
|
8442
|
-
font-weight:
|
|
9427
|
+
font-weight: var(--fw-medium);
|
|
8443
9428
|
font-size: var(--fs-sm);
|
|
8444
9429
|
color: var(--fg);
|
|
8445
9430
|
letter-spacing: -0.01em;
|
|
@@ -8503,7 +9488,7 @@
|
|
|
8503
9488
|
padding: var(--space-2-75) var(--space-3) var(--space-1-75);
|
|
8504
9489
|
font-family: var(--ff-body);
|
|
8505
9490
|
font-size: var(--fs-micro);
|
|
8506
|
-
font-weight:
|
|
9491
|
+
font-weight: var(--fw-medium);
|
|
8507
9492
|
color: var(--fg-3);
|
|
8508
9493
|
letter-spacing: var(--tr-caps);
|
|
8509
9494
|
text-transform: uppercase;
|
|
@@ -8534,13 +9519,14 @@
|
|
|
8534
9519
|
height: 28px;
|
|
8535
9520
|
border-radius: 50%;
|
|
8536
9521
|
background: var(--avatar-bg, var(--bg-3));
|
|
8537
|
-
color: var(--fg-2);
|
|
9522
|
+
color: var(--avatar-fg, var(--fg-2));
|
|
8538
9523
|
display: inline-flex;
|
|
8539
9524
|
align-items: center;
|
|
8540
9525
|
justify-content: center;
|
|
8541
9526
|
font-size: var(--fs-micro);
|
|
8542
|
-
font-weight:
|
|
9527
|
+
font-weight: var(--fw-medium);
|
|
8543
9528
|
overflow: hidden;
|
|
9529
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fg) 10%, transparent);
|
|
8544
9530
|
}
|
|
8545
9531
|
.ds-247420 .cm-member-avatar img {
|
|
8546
9532
|
width: 100%;
|
|
@@ -8595,13 +9581,14 @@
|
|
|
8595
9581
|
height: 56px;
|
|
8596
9582
|
border-radius: 50%;
|
|
8597
9583
|
background: var(--avatar-bg, var(--bg-3));
|
|
8598
|
-
color: var(--fg-2);
|
|
9584
|
+
color: var(--avatar-fg, var(--fg-2));
|
|
8599
9585
|
display: inline-flex;
|
|
8600
9586
|
align-items: center;
|
|
8601
9587
|
justify-content: center;
|
|
8602
9588
|
font-size: var(--fs-lg);
|
|
8603
|
-
font-weight:
|
|
9589
|
+
font-weight: var(--fw-medium);
|
|
8604
9590
|
overflow: hidden;
|
|
9591
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fg) 10%, transparent);
|
|
8605
9592
|
}
|
|
8606
9593
|
.ds-247420 .cm-voice-user-avatar img {
|
|
8607
9594
|
width: 100%;
|
|
@@ -8616,7 +9603,7 @@
|
|
|
8616
9603
|
.ds-247420 .cm-voice-user-name {
|
|
8617
9604
|
font-size: var(--fs-xs);
|
|
8618
9605
|
color: var(--fg);
|
|
8619
|
-
font-weight:
|
|
9606
|
+
font-weight: var(--fw-medium);
|
|
8620
9607
|
max-width: 100px;
|
|
8621
9608
|
overflow: hidden;
|
|
8622
9609
|
text-overflow: ellipsis;
|
|
@@ -8811,7 +9798,7 @@
|
|
|
8811
9798
|
flex: 1 1 auto;
|
|
8812
9799
|
min-width: 0;
|
|
8813
9800
|
font-family: var(--font-mono, monospace);
|
|
8814
|
-
font-weight:
|
|
9801
|
+
font-weight: var(--fw-medium);
|
|
8815
9802
|
color: var(--fg);
|
|
8816
9803
|
white-space: nowrap;
|
|
8817
9804
|
overflow: hidden;
|
|
@@ -8834,7 +9821,7 @@
|
|
|
8834
9821
|
font-size: var(--fs-xs);
|
|
8835
9822
|
}
|
|
8836
9823
|
.ds-247420 .cm-rb-label { flex: none; color: var(--fg-2); }
|
|
8837
|
-
.ds-247420 .cm-rb-author { color: var(--accent); font-weight:
|
|
9824
|
+
.ds-247420 .cm-rb-author { color: var(--accent); font-weight: var(--fw-medium); }
|
|
8838
9825
|
.ds-247420 .cm-rb-preview {
|
|
8839
9826
|
flex: 1 1 auto;
|
|
8840
9827
|
min-width: 0;
|
|
@@ -8866,7 +9853,7 @@
|
|
|
8866
9853
|
width: 100%;
|
|
8867
9854
|
padding: var(--space-2) var(--space-3);
|
|
8868
9855
|
font-size: var(--fs-xs);
|
|
8869
|
-
font-weight:
|
|
9856
|
+
font-weight: var(--fw-medium);
|
|
8870
9857
|
}
|
|
8871
9858
|
.ds-247420 .cm-banner.clickable { cursor: pointer; }
|
|
8872
9859
|
.ds-247420 .cm-banner.clickable:hover { background: color-mix(in oklab, currentColor 10%, transparent); }
|
|
@@ -8877,7 +9864,7 @@
|
|
|
8877
9864
|
background: transparent;
|
|
8878
9865
|
color: inherit;
|
|
8879
9866
|
font: inherit;
|
|
8880
|
-
font-weight:
|
|
9867
|
+
font-weight: var(--fw-semibold);
|
|
8881
9868
|
padding: var(--space-hair) var(--space-2);
|
|
8882
9869
|
border-radius: var(--r-1);
|
|
8883
9870
|
cursor: pointer;
|
|
@@ -8939,7 +9926,7 @@
|
|
|
8939
9926
|
color: var(--fg);
|
|
8940
9927
|
font-family: var(--ff-body);
|
|
8941
9928
|
font-size: var(--fs-sm);
|
|
8942
|
-
font-weight:
|
|
9929
|
+
font-weight: var(--fw-medium);
|
|
8943
9930
|
cursor: pointer;
|
|
8944
9931
|
user-select: none;
|
|
8945
9932
|
-webkit-user-select: none;
|
|
@@ -9061,7 +10048,7 @@
|
|
|
9061
10048
|
color: var(--fg);
|
|
9062
10049
|
font-family: var(--ff-body);
|
|
9063
10050
|
font-size: var(--fs-sm);
|
|
9064
|
-
font-weight:
|
|
10051
|
+
font-weight: var(--fw-semibold);
|
|
9065
10052
|
cursor: pointer;
|
|
9066
10053
|
transition: background var(--dur-base) var(--ease);
|
|
9067
10054
|
}
|
|
@@ -9091,7 +10078,7 @@
|
|
|
9091
10078
|
padding: var(--space-3);
|
|
9092
10079
|
border-bottom: var(--bw-hair) solid var(--rule);
|
|
9093
10080
|
}
|
|
9094
|
-
.ds-247420 .vx-modal-title { margin: 0; font-size: var(--fs-lg); font-weight:
|
|
10081
|
+
.ds-247420 .vx-modal-title { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
|
|
9095
10082
|
.ds-247420 .vx-modal-x {
|
|
9096
10083
|
border: 0; background: transparent; color: var(--fg-3);
|
|
9097
10084
|
font-size: var(--fs-xl); line-height: 1; cursor: pointer; padding: 0 var(--space-1);
|
|
@@ -9115,7 +10102,7 @@
|
|
|
9115
10102
|
color: var(--fg);
|
|
9116
10103
|
font-family: var(--ff-body);
|
|
9117
10104
|
font-size: var(--fs-tiny);
|
|
9118
|
-
font-weight:
|
|
10105
|
+
font-weight: var(--fw-medium);
|
|
9119
10106
|
letter-spacing: var(--tr-caps);
|
|
9120
10107
|
cursor: pointer;
|
|
9121
10108
|
}
|
|
@@ -9128,6 +10115,9 @@
|
|
|
9128
10115
|
font-size: var(--fs-sm);
|
|
9129
10116
|
}
|
|
9130
10117
|
.ds-247420 .vx-toggle { accent-color: var(--accent); width: 18px; height: 18px; cursor: pointer; }
|
|
10118
|
+
@media (pointer: coarse) {
|
|
10119
|
+
.ds-247420 .vx-toggle { width: 24px; height: 24px; }
|
|
10120
|
+
}
|
|
9131
10121
|
|
|
9132
10122
|
.ds-247420 .vx-queue {
|
|
9133
10123
|
display: flex; align-items: center; gap: var(--space-2);
|
|
@@ -9170,13 +10160,13 @@
|
|
|
9170
10160
|
.ds-247420 .vx-chip-current { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 16%, var(--bg-3)); }
|
|
9171
10161
|
.ds-247420 .vx-chip-live { border-color: var(--green-2); }
|
|
9172
10162
|
.ds-247420 .vx-chip-dot { width: 8px; height: 8px; border-radius: var(--r-pill); background: var(--fg-3); flex-shrink: 0; }
|
|
9173
|
-
.ds-247420 .vx-chip-name { font-weight:
|
|
10163
|
+
.ds-247420 .vx-chip-name { font-weight: var(--fw-medium); }
|
|
9174
10164
|
.ds-247420 .vx-chip-dur { font-family: var(--ff-mono); color: var(--fg-3); }
|
|
9175
10165
|
/* Joins the small-label voice above. Deliberate overrides: --green + weight 700
|
|
9176
10166
|
because this is the "LIVE" badge on a session chip, same signal role as
|
|
9177
10167
|
.cm-vs-label. */
|
|
9178
10168
|
.ds-247420 .vx-chip-tag {
|
|
9179
|
-
color: var(--green); font-weight:
|
|
10169
|
+
color: var(--green); font-weight: var(--fw-bold);
|
|
9180
10170
|
}
|
|
9181
10171
|
|
|
9182
10172
|
/* VoiceControls — vx-vc-* */
|
|
@@ -9222,7 +10212,7 @@
|
|
|
9222
10212
|
display: flex; align-items: center; justify-content: space-between;
|
|
9223
10213
|
padding: var(--space-2); border-bottom: var(--bw-hair) solid var(--rule);
|
|
9224
10214
|
}
|
|
9225
|
-
.ds-247420 .cm-tp-title { font-weight:
|
|
10215
|
+
.ds-247420 .cm-tp-title { font-weight: var(--fw-bold); font-size: var(--fs-xs); }
|
|
9226
10216
|
.ds-247420 .cm-tp-head-actions { display: flex; gap: var(--space-1); }
|
|
9227
10217
|
.ds-247420 .cm-tp-new, .ds-247420 .cm-tp-close {
|
|
9228
10218
|
border: none; background: transparent; color: var(--fg-2, var(--fg));
|
|
@@ -9240,7 +10230,7 @@
|
|
|
9240
10230
|
}
|
|
9241
10231
|
.ds-247420 .cm-tp-item:hover { background: var(--bg-3); }
|
|
9242
10232
|
.ds-247420 .cm-tp-item.is-active { background: var(--bg-3); box-shadow: inset 3px 0 0 var(--accent); }
|
|
9243
|
-
.ds-247420 .cm-tp-item.is-unread .cm-tp-item-title { font-weight:
|
|
10233
|
+
.ds-247420 .cm-tp-item.is-unread .cm-tp-item-title { font-weight: var(--fw-bold); }
|
|
9244
10234
|
.ds-247420 .cm-tp-dot { position: absolute; left: 4px; top: 50%; transform: translateY(-50%); width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
|
|
9245
10235
|
.ds-247420 .cm-tp-item-title { font-size: var(--fs-xs); }
|
|
9246
10236
|
.ds-247420 .cm-tp-item-snippet { font-size: var(--fs-micro); color: var(--fg-2, var(--fg)); opacity: .8; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
@@ -9294,7 +10284,7 @@
|
|
|
9294
10284
|
.ds-247420 .cm-forum-item { display: flex; flex-direction: column; gap: var(--space-1); width: 100%; text-align: left; cursor: pointer; padding: var(--space-2) var(--space-3); border: none; background: transparent; border-bottom: var(--bw-hair) solid var(--rule); color: var(--fg); }
|
|
9295
10285
|
.ds-247420 .cm-forum-item:hover { background: var(--bg-3); }
|
|
9296
10286
|
.ds-247420 .cm-forum-item-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
|
|
9297
|
-
.ds-247420 .cm-forum-item-title { font-weight:
|
|
10287
|
+
.ds-247420 .cm-forum-item-title { font-weight: var(--fw-bold); font-size: var(--fs-xs); }
|
|
9298
10288
|
.ds-247420 .cm-forum-item-replies { font-size: var(--fs-micro); color: var(--fg-2, var(--fg)); opacity: .8; white-space: nowrap; }
|
|
9299
10289
|
.ds-247420 .cm-forum-item-snippet { font-size: var(--fs-micro); color: var(--fg-2, var(--fg)); opacity: .85; }
|
|
9300
10290
|
.ds-247420 .cm-forum-item-meta { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; font-size: var(--fs-micro); color: var(--fg-2, var(--fg)); opacity: .7; }
|
|
@@ -9306,10 +10296,14 @@
|
|
|
9306
10296
|
/* PageView — cm-page / cm-page-* */
|
|
9307
10297
|
.ds-247420 .cm-page { display: flex; flex-direction: column; height: 100%; min-height: 0; overflow-y: auto; background: var(--bg-1, var(--bg-2)); color: var(--fg); }
|
|
9308
10298
|
.ds-247420 .cm-page-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); padding: var(--space-3); border-bottom: var(--bw-hair) solid var(--rule); }
|
|
9309
|
-
.ds-247420 .cm-page-title {
|
|
10299
|
+
.ds-247420 .cm-page-head-title { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
|
|
10300
|
+
.ds-247420 .cm-page-title { margin: 0; font-size: var(--fs-xl); font-weight: var(--fw-bold); }
|
|
10301
|
+
.ds-247420 .cm-page-meta { display: flex; align-items: center; gap: var(--space-2); font-size: var(--fs-xs); color: var(--fg-2, var(--fg)); }
|
|
10302
|
+
.ds-247420 .cm-page-author { font-weight: var(--fw-medium); }
|
|
10303
|
+
.ds-247420 .cm-page-time { opacity: .75; }
|
|
9310
10304
|
.ds-247420 .cm-page-edit { padding: var(--space-1) var(--space-2); border: var(--bw-hair) solid var(--rule-strong); border-radius: var(--r-1); background: var(--bg-3); color: var(--fg); cursor: pointer; }
|
|
9311
10305
|
.ds-247420 .cm-page-body { padding: var(--space-3); line-height: 1.6; }
|
|
9312
|
-
.ds-247420 .cm-page-empty { color: var(--fg-2, var(--fg)); opacity: .
|
|
10306
|
+
.ds-247420 .cm-page-empty { color: var(--fg-2, var(--fg)); opacity: .82; }
|
|
9313
10307
|
|
|
9314
10308
|
/* ============================================================
|
|
9315
10309
|
freddie pages — layout for FREDDIE_PAGES renderers.
|
|
@@ -9319,12 +10313,15 @@
|
|
|
9319
10313
|
.ds-247420 .fd-page-inner { display: flex; flex-direction: column; gap: var(--space-3, 16px); padding: var(--space-3, 16px); max-width: 1100px; }
|
|
9320
10314
|
.ds-247420 .fd-page-inner > * { min-width: 0; }
|
|
9321
10315
|
.ds-247420 .fd-loading { display: flex; align-items: center; gap: var(--space-2, 10px); padding: var(--space-4, 24px); color: var(--fg-2, var(--fg)); }
|
|
9322
|
-
|
|
10316
|
+
/* Base layout shared with .ds-empty-state (primitives.css); overrides padding
|
|
10317
|
+
(--space-5, denser than the shared --space-6) and color for this context. */
|
|
10318
|
+
.ds-247420 .fd-empty { padding: var(--space-5, 32px) var(--space-3, 16px); color: var(--fg-2, var(--fg)); }
|
|
9323
10319
|
/* 28px is an ICON size (empty-state mark), not a type tier — the --fs-* ladder
|
|
9324
10320
|
tops out at --fs-xl (21px) before every remaining rung becomes a fluid
|
|
9325
|
-
heading clamp, so neither substitutes without visibly resizing the mark.
|
|
9326
|
-
|
|
9327
|
-
.ds-247420 .fd-
|
|
10321
|
+
heading clamp, so neither substitutes without visibly resizing the mark.
|
|
10322
|
+
--fs-2xl bridges that gap as a fixed 28px token. */
|
|
10323
|
+
.ds-247420 .fd-empty-glyph { font-size: var(--fs-2xl); opacity: .55; line-height: 1; }
|
|
10324
|
+
.ds-247420 .fd-pre { margin: 0; padding: var(--space-2, 10px); background: var(--bg-3, var(--panel-bg-2)); border: var(--bw-hair, 1px) solid var(--rule, var(--panel-accent)); border-radius: var(--r-1, 8px); overflow: auto; max-height: 460px; white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; font-family: var(--font-mono, ui-monospace, monospace); font-size: var(--fs-micro); line-height: 1.5; }
|
|
9328
10325
|
.ds-247420 .fd-skill-body { max-height: 320px; }
|
|
9329
10326
|
.ds-247420 .fd-row-actions { display: inline-flex; gap: var(--space-1, 6px); align-items: center; }
|
|
9330
10327
|
.ds-247420 .fd-chat { display: flex; flex-direction: column; gap: var(--space-2, 10px); height: 100%; min-height: 0; }
|
|
@@ -9341,9 +10338,105 @@
|
|
|
9341
10338
|
}
|
|
9342
10339
|
|
|
9343
10340
|
/* chat.css */
|
|
9344
|
-
/* chat.css — chat-specific styles
|
|
9345
|
-
|
|
9346
|
-
|
|
10341
|
+
/* chat.css — chat-specific styles, including the base .chat-* rules used by
|
|
10342
|
+
Chat()/ChatMessage() (chat/threads.js, chat/message.js): .chat, .chat-head,
|
|
10343
|
+
.chat-thread, .chat-msg, .chat-avatar, .chat-bubble, .chat-stack,
|
|
10344
|
+
.chat-empty. This file also carries the AgentChat kit styles (the reusable
|
|
10345
|
+
multi-agent orchestration chat surface, .agentchat-*). */
|
|
10346
|
+
|
|
10347
|
+
/* Base chat surface — the default (non-flat) messenger layout: left/right
|
|
10348
|
+
avatar-disc + colored-bubble turns. .chat-msg-flat further down overrides
|
|
10349
|
+
these to the claude.ai/code full-width turn style; these are the rules it
|
|
10350
|
+
overrides FROM, and were previously entirely undefined, so the default
|
|
10351
|
+
layout rendered on raw flex/browser defaults (unstyled bubble shape, no
|
|
10352
|
+
avatar depth, no defined thread padding) until a Chat() consumer supplied
|
|
10353
|
+
its own colliding class names. */
|
|
10354
|
+
.ds-247420 .chat {
|
|
10355
|
+
display: flex;
|
|
10356
|
+
flex-direction: column;
|
|
10357
|
+
flex: 1;
|
|
10358
|
+
min-height: 0;
|
|
10359
|
+
}
|
|
10360
|
+
.ds-247420 .chat-head {
|
|
10361
|
+
display: flex;
|
|
10362
|
+
align-items: center;
|
|
10363
|
+
gap: var(--space-2);
|
|
10364
|
+
padding: var(--space-2-75) var(--space-3);
|
|
10365
|
+
border-bottom: 1px solid var(--panel-3, color-mix(in oklab, var(--fg) 10%, transparent));
|
|
10366
|
+
flex-shrink: 0;
|
|
10367
|
+
}
|
|
10368
|
+
.ds-247420 .chat-head .ds-chat-title { font-size: var(--fs-sm); font-weight: var(--fw-medium); margin: 0; }
|
|
10369
|
+
.ds-247420 .chat-head .sub { font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
10370
|
+
.ds-247420 .chat-head .spread { flex: 1; }
|
|
10371
|
+
.ds-247420 .chat-thread {
|
|
10372
|
+
flex: 1;
|
|
10373
|
+
min-height: 0;
|
|
10374
|
+
overflow-y: auto;
|
|
10375
|
+
display: flex;
|
|
10376
|
+
flex-direction: column;
|
|
10377
|
+
gap: var(--space-3);
|
|
10378
|
+
padding: var(--space-3) var(--space-3) var(--space-4);
|
|
10379
|
+
/* A short thread must not stretch its one message across the whole
|
|
10380
|
+
viewport height — pack content to the bottom (where the composer is)
|
|
10381
|
+
instead of centering it in a sea of empty space above and below. */
|
|
10382
|
+
justify-content: flex-end;
|
|
10383
|
+
}
|
|
10384
|
+
.ds-247420 .chat-empty {
|
|
10385
|
+
margin: auto;
|
|
10386
|
+
max-width: var(--measure-narrow, 60ch);
|
|
10387
|
+
text-align: center;
|
|
10388
|
+
padding: var(--space-5) var(--space-3);
|
|
10389
|
+
color: var(--fg-3);
|
|
10390
|
+
}
|
|
10391
|
+
.ds-247420 .chat-empty-title { font-size: var(--fs-lg); font-weight: var(--fw-medium); color: var(--fg-2); margin: 0 0 var(--space-1); }
|
|
10392
|
+
.ds-247420 .chat-empty-sub { font-size: var(--fs-sm); margin: 0; }
|
|
10393
|
+
.ds-247420 .chat-msg {
|
|
10394
|
+
display: flex;
|
|
10395
|
+
gap: var(--space-2);
|
|
10396
|
+
align-items: flex-start;
|
|
10397
|
+
max-width: 100%;
|
|
10398
|
+
}
|
|
10399
|
+
.ds-247420 .chat-msg.you { flex-direction: row-reverse; }
|
|
10400
|
+
.ds-247420 .chat-msg.centered { justify-content: center; text-align: center; }
|
|
10401
|
+
.ds-247420 .chat-avatar {
|
|
10402
|
+
width: 32px;
|
|
10403
|
+
height: 32px;
|
|
10404
|
+
flex-shrink: 0;
|
|
10405
|
+
border-radius: 50%;
|
|
10406
|
+
background: var(--bg-3);
|
|
10407
|
+
color: var(--fg);
|
|
10408
|
+
display: inline-flex;
|
|
10409
|
+
align-items: center;
|
|
10410
|
+
justify-content: center;
|
|
10411
|
+
font-size: var(--fs-tiny);
|
|
10412
|
+
font-weight: var(--fw-medium);
|
|
10413
|
+
/* Depth over a flat solid-color disc: a hairline inset ring plus the same
|
|
10414
|
+
soft shadow --panel-shadow uses elsewhere, so avatars read as a real
|
|
10415
|
+
surface element instead of a wireframe placeholder. */
|
|
10416
|
+
box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--fg) 10%, transparent), 0 1px 2px color-mix(in oklab, var(--fg) 10%, transparent);
|
|
10417
|
+
}
|
|
10418
|
+
.ds-247420 .chat-stack {
|
|
10419
|
+
display: flex;
|
|
10420
|
+
flex-direction: column;
|
|
10421
|
+
gap: var(--space-1);
|
|
10422
|
+
max-width: 70%;
|
|
10423
|
+
min-width: 0;
|
|
10424
|
+
}
|
|
10425
|
+
.ds-247420 .chat-msg.you .chat-stack { align-items: flex-end; }
|
|
10426
|
+
.ds-247420 .chat-bubble {
|
|
10427
|
+
padding: var(--space-2) var(--space-2-75);
|
|
10428
|
+
background: var(--bg-2);
|
|
10429
|
+
color: var(--fg);
|
|
10430
|
+
/* r-2, not a pill — a pill-capsule bubble read as a generic chat-template
|
|
10431
|
+
shape inconsistent with every other rounded element in the app (which
|
|
10432
|
+
all use the r-0..r-3 scale, never 999px). */
|
|
10433
|
+
border-radius: var(--r-2);
|
|
10434
|
+
line-height: var(--lh-base, 1.5);
|
|
10435
|
+
word-break: break-word;
|
|
10436
|
+
font-size: var(--fs-sm);
|
|
10437
|
+
}
|
|
10438
|
+
.ds-247420 .chat-msg.you .chat-bubble { background: var(--accent); color: var(--accent-fg); }
|
|
10439
|
+
.ds-247420 .chat-meta { display: flex; gap: var(--space-1-5); font-size: var(--fs-nano); color: var(--fg-3); padding: 0 var(--space-1); }
|
|
9347
10440
|
|
|
9348
10441
|
.ds-247420 .agentchat {
|
|
9349
10442
|
display: flex;
|
|
@@ -9587,7 +10680,7 @@
|
|
|
9587
10680
|
.ds-247420 .chat-msg-action {
|
|
9588
10681
|
display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1);
|
|
9589
10682
|
min-width: 26px; height: 26px; padding: 0 var(--space-1-75); cursor: pointer;
|
|
9590
|
-
border: none; border-radius: var(--r-1,
|
|
10683
|
+
border: none; border-radius: var(--r-1, 8px); background: none; color: var(--fg-3);
|
|
9591
10684
|
font-family: var(--ff-body); font-size: var(--fs-tiny);
|
|
9592
10685
|
}
|
|
9593
10686
|
.ds-247420 .chat-msg-action-label { font-size: var(--fs-tiny); }
|
|
@@ -9655,7 +10748,7 @@
|
|
|
9655
10748
|
display: flex; align-items: center; gap: var(--space-2, 8px);
|
|
9656
10749
|
padding: var(--space-1, 4px) var(--space-2, 8px);
|
|
9657
10750
|
border: var(--bw-hair) solid var(--rule);
|
|
9658
|
-
border-radius: var(--r-1,
|
|
10751
|
+
border-radius: var(--r-1, 8px);
|
|
9659
10752
|
background: var(--bg-2);
|
|
9660
10753
|
}
|
|
9661
10754
|
.ds-247420 .agentchat-install-agent { flex: 0 0 auto; font-size: var(--fs-tiny); color: var(--fg-3); min-width: 8ch; }
|
|
@@ -9665,7 +10758,7 @@
|
|
|
9665
10758
|
}
|
|
9666
10759
|
.ds-247420 .agentchat-install-copy {
|
|
9667
10760
|
flex: 0 0 auto; cursor: pointer; padding: var(--space-hair) var(--space-2); min-height: 24px;
|
|
9668
|
-
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1,
|
|
10761
|
+
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1, 8px);
|
|
9669
10762
|
background: none; color: var(--fg-3);
|
|
9670
10763
|
font-family: var(--ff-body); font-size: var(--fs-tiny);
|
|
9671
10764
|
}
|
|
@@ -9676,7 +10769,7 @@
|
|
|
9676
10769
|
/* Host-supplied transcript export actions riding the controls row. */
|
|
9677
10770
|
.ds-247420 .agentchat-export-act {
|
|
9678
10771
|
cursor: pointer; padding: var(--space-1) var(--space-2-5); min-height: 32px;
|
|
9679
|
-
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1,
|
|
10772
|
+
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1, 8px);
|
|
9680
10773
|
background: none; color: var(--fg-3);
|
|
9681
10774
|
font-family: var(--ff-body); font-size: var(--fs-tiny);
|
|
9682
10775
|
}
|
|
@@ -9872,7 +10965,7 @@
|
|
|
9872
10965
|
.ds-247420 .ds-session-agent { font-size: var(--fs-tiny); color: var(--fg-3); }
|
|
9873
10966
|
/* New-activity cue is a hollow accent RING so it stays shape-distinct from the
|
|
9874
10967
|
running live disc (a solid pulsing accent dot) for colour-blind / reduced-motion users. */
|
|
9875
|
-
.ds-247420 .ds-session-unread { width: 8px; height: 8px; border-radius: 50%; background: var(--
|
|
10968
|
+
.ds-247420 .ds-session-unread { width: 8px; height: 8px; border-radius: 50%; background: transparent; box-shadow: inset 0 0 0 1.5px var(--accent); display: inline-block; flex: none; }
|
|
9876
10969
|
.ds-247420 .ds-session-state { padding: var(--space-5) var(--space-3); text-align: center; color: var(--fg-3); font-size: var(--fs-sm); }
|
|
9877
10970
|
.ds-247420 .ds-session-state-error { color: var(--flame); }
|
|
9878
10971
|
|
|
@@ -9909,7 +11002,7 @@
|
|
|
9909
11002
|
background: var(--bg); border: var(--border-w) solid var(--accent); border-radius: var(--r-1);
|
|
9910
11003
|
padding: var(--space-1) var(--space-2);
|
|
9911
11004
|
}
|
|
9912
|
-
.ds-247420 .ds-session-rename-input:focus { outline: none; }
|
|
11005
|
+
.ds-247420 .ds-session-rename-input:focus-visible { outline: none; box-shadow: var(--focus-ring-inset); }
|
|
9913
11006
|
|
|
9914
11007
|
/* Inline delete confirm — same row height, two flat buttons, no modal;
|
|
9915
11008
|
mirrors SessionDashboard's arm-then-confirm bulk-stop control. */
|
|
@@ -9951,7 +11044,7 @@
|
|
|
9951
11044
|
.ds-247420 .ds-dash-header .btn-primary.danger.is-armed { background: var(--warn); color: var(--ink); border-color: var(--warn); }
|
|
9952
11045
|
.ds-247420 .ds-dash-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-2); padding: var(--space-3); }
|
|
9953
11046
|
@media (min-width: 1500px) { .ds-247420 .ds-dash-grid { grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); } }
|
|
9954
|
-
.ds-247420 .ds-dash-card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-
|
|
11047
|
+
.ds-247420 .ds-dash-card { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-3); background: var(--bg-2); border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1); }
|
|
9955
11048
|
|
|
9956
11049
|
/* Compact density — one line per session. The comfortable card stacks title +
|
|
9957
11050
|
head + meta + actions as four flex rows and measured 208px tall on a real
|
|
@@ -10119,7 +11212,7 @@
|
|
|
10119
11212
|
position: absolute; top: 6px; right: 6px;
|
|
10120
11213
|
display: inline-flex; align-items: center; justify-content: center;
|
|
10121
11214
|
min-width: 48px; min-height: 24px; padding: var(--space-hair) var(--space-2);
|
|
10122
|
-
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1,
|
|
11215
|
+
border: var(--bw-hair) solid var(--bg-3); border-radius: var(--r-1, 8px);
|
|
10123
11216
|
background: var(--bg-2); color: var(--fg-2); cursor: pointer;
|
|
10124
11217
|
font-family: var(--ff-body); font-size: var(--fs-tiny);
|
|
10125
11218
|
opacity: 0; transition: opacity var(--dur-snap, .12s) var(--ease, ease);
|
|
@@ -10786,7 +11879,7 @@
|
|
|
10786
11879
|
/* Minimap internal order: centerline < viewport < dot < tooltip. All four
|
|
10787
11880
|
live inside the one raised widget, so they share its rung and differ
|
|
10788
11881
|
only by a local offset. */
|
|
10789
|
-
z-index:
|
|
11882
|
+
z-index: var(--z-raised-1);
|
|
10790
11883
|
}
|
|
10791
11884
|
.ds-247420 .chat-minimap-centerline {
|
|
10792
11885
|
position: absolute;
|
|
@@ -10806,7 +11899,7 @@
|
|
|
10806
11899
|
border-radius: var(--r-pill, 999px);
|
|
10807
11900
|
transform: translate(-50%, -50%) scale(1);
|
|
10808
11901
|
transition: transform 0.1s;
|
|
10809
|
-
z-index:
|
|
11902
|
+
z-index: var(--z-raised-2);
|
|
10810
11903
|
}
|
|
10811
11904
|
.ds-247420 .chat-minimap-dot.is-user {
|
|
10812
11905
|
background: color-mix(in oklab, var(--accent) 18%, transparent);
|
|
@@ -10831,7 +11924,7 @@
|
|
|
10831
11924
|
/* Top of the minimap's internal order. Deliberately NOT --z-tooltip: it is
|
|
10832
11925
|
clipped to the minimap rail rather than floating over the app, so it must
|
|
10833
11926
|
not outrank real overlays that may cover the rail. */
|
|
10834
|
-
z-index:
|
|
11927
|
+
z-index: var(--z-raised-3);
|
|
10835
11928
|
pointer-events: none;
|
|
10836
11929
|
opacity: 0.45;
|
|
10837
11930
|
font-size: var(--fs-tiny);
|
|
@@ -10913,7 +12006,7 @@
|
|
|
10913
12006
|
/* Buttons inside the dense strip shrink to fit the 26px band. */
|
|
10914
12007
|
.ds-247420 .ds-ep-statusbar button {
|
|
10915
12008
|
min-height: 0; height: 20px; padding: 0 var(--space-2);
|
|
10916
|
-
border-radius: var(--r-1,
|
|
12009
|
+
border-radius: var(--r-1, 8px);
|
|
10917
12010
|
font: var(--fs-micro, 11px)/1 var(--ff-mono, monospace);
|
|
10918
12011
|
}
|
|
10919
12012
|
|
|
@@ -10945,7 +12038,7 @@
|
|
|
10945
12038
|
border: 1px solid var(--rule);
|
|
10946
12039
|
color: var(--panel-text, var(--fg));
|
|
10947
12040
|
padding: var(--space-1-5, 5px) var(--space-2-5, 10px);
|
|
10948
|
-
border-radius: var(--r-1,
|
|
12041
|
+
border-radius: var(--r-1, 8px);
|
|
10949
12042
|
font-size: var(--fs-tiny, 12px);
|
|
10950
12043
|
font-family: inherit;
|
|
10951
12044
|
}
|
|
@@ -11063,7 +12156,7 @@
|
|
|
11063
12156
|
.ds-247420 .ds-ep-tree-row {
|
|
11064
12157
|
display: flex; align-items: center; gap: var(--space-1-75);
|
|
11065
12158
|
padding: var(--space-1) var(--space-2) var(--space-1) 0;
|
|
11066
|
-
border-radius: var(--r-1,
|
|
12159
|
+
border-radius: var(--r-1, 8px);
|
|
11067
12160
|
cursor: pointer;
|
|
11068
12161
|
color: var(--panel-text-2);
|
|
11069
12162
|
transition: background var(--dur-snap, 80ms) var(--ease, ease), color var(--dur-snap, 80ms) var(--ease, ease);
|
|
@@ -11125,7 +12218,7 @@
|
|
|
11125
12218
|
background: var(--panel-2);
|
|
11126
12219
|
color: var(--panel-text);
|
|
11127
12220
|
border: 1px solid var(--rule);
|
|
11128
|
-
border-radius: var(--r-1,
|
|
12221
|
+
border-radius: var(--r-1, 8px);
|
|
11129
12222
|
padding: var(--space-1) var(--space-2);
|
|
11130
12223
|
font: inherit;
|
|
11131
12224
|
min-width: 0; width: 100%;
|
|
@@ -11166,7 +12259,7 @@
|
|
|
11166
12259
|
.ds-247420 .ds-ep-propfield-value input,
|
|
11167
12260
|
.ds-247420 .ds-ep-propfield-value .ds-input-bare {
|
|
11168
12261
|
padding: var(--space-hair) var(--space-1-75);
|
|
11169
|
-
border-radius: var(--r-1,
|
|
12262
|
+
border-radius: var(--r-1, 8px);
|
|
11170
12263
|
font: var(--fs-tiny, 12px)/1.3 var(--ff-mono, monospace);
|
|
11171
12264
|
}
|
|
11172
12265
|
.ds-247420 .ds-input-bare {
|
|
@@ -11174,7 +12267,7 @@
|
|
|
11174
12267
|
background: var(--panel-2);
|
|
11175
12268
|
color: var(--panel-text);
|
|
11176
12269
|
border: 1px solid var(--rule);
|
|
11177
|
-
border-radius: var(--r-1,
|
|
12270
|
+
border-radius: var(--r-1, 8px);
|
|
11178
12271
|
padding: var(--space-hair) var(--space-1-75);
|
|
11179
12272
|
font: var(--fs-tiny, 12px)/1.3 var(--ff-mono, monospace);
|
|
11180
12273
|
min-width: 0;
|
|
@@ -11216,7 +12309,7 @@
|
|
|
11216
12309
|
border: 1px solid transparent;
|
|
11217
12310
|
color: inherit; font: inherit;
|
|
11218
12311
|
width: 100%;
|
|
11219
|
-
border-radius: var(--r-1,
|
|
12312
|
+
border-radius: var(--r-1, 8px);
|
|
11220
12313
|
padding: var(--space-hair, 2px) var(--space-1, 4px);
|
|
11221
12314
|
}
|
|
11222
12315
|
.ds-247420 .ds-ep-inline-input.ds-ep-inline-input:focus-visible {
|
|
@@ -11243,7 +12336,7 @@
|
|
|
11243
12336
|
width: 100%;
|
|
11244
12337
|
/* Snapped to --ctl-sm (was a lone 28px literal that happened to match). */
|
|
11245
12338
|
min-height: var(--ctl-sm); height: var(--ctl-sm); padding: 0 var(--space-2-5);
|
|
11246
|
-
border-radius: var(--r-1,
|
|
12339
|
+
border-radius: var(--r-1, 8px);
|
|
11247
12340
|
font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
|
|
11248
12341
|
}
|
|
11249
12342
|
|
|
@@ -11253,7 +12346,7 @@
|
|
|
11253
12346
|
.ds-247420 .ds-ep-tree-row button:not(.ds-ep-btngrp-btn),
|
|
11254
12347
|
.ds-247420 .ds-ep-toolbar button:not(.ds-ep-btngrp-btn) {
|
|
11255
12348
|
min-height: 24px; height: 24px; padding: 0 var(--space-2);
|
|
11256
|
-
border-radius: var(--r-1,
|
|
12349
|
+
border-radius: var(--r-1, 8px);
|
|
11257
12350
|
font: var(--fs-tiny, 12px)/1 var(--ff-mono, monospace);
|
|
11258
12351
|
}
|
|
11259
12352
|
@media (pointer: coarse) {
|
|
@@ -11280,7 +12373,7 @@
|
|
|
11280
12373
|
border: 1px solid var(--rule);
|
|
11281
12374
|
color: var(--panel-text, var(--fg));
|
|
11282
12375
|
padding: var(--space-half, 3px) var(--space-2-5, 10px);
|
|
11283
|
-
border-radius: var(--r-1,
|
|
12376
|
+
border-radius: var(--r-1, 8px);
|
|
11284
12377
|
font: inherit;
|
|
11285
12378
|
}
|
|
11286
12379
|
.ds-247420 .ds-ep-pager-btn:hover:not([disabled]) { background: color-mix(in oklab, var(--accent) 10%, transparent); }
|
|
@@ -11298,7 +12391,7 @@
|
|
|
11298
12391
|
computed to 23px -- just under the target floor. */
|
|
11299
12392
|
min-width: max(24px, 1.75em);
|
|
11300
12393
|
padding: var(--space-half, 3px) var(--space-1, 4px);
|
|
11301
|
-
border-radius: var(--r-1,
|
|
12394
|
+
border-radius: var(--r-1, 8px);
|
|
11302
12395
|
font: inherit;
|
|
11303
12396
|
text-align: center;
|
|
11304
12397
|
}
|
|
@@ -11377,7 +12470,7 @@
|
|
|
11377
12470
|
background: var(--panel-2, var(--bg-2));
|
|
11378
12471
|
color: var(--panel-text, var(--fg));
|
|
11379
12472
|
padding: var(--space-2, 8px);
|
|
11380
|
-
border-radius: var(--r-1,
|
|
12473
|
+
border-radius: var(--r-1, 8px);
|
|
11381
12474
|
max-height: 300px;
|
|
11382
12475
|
overflow-y: auto;
|
|
11383
12476
|
margin: 0;
|
|
@@ -11405,7 +12498,7 @@
|
|
|
11405
12498
|
.ds-247420 .ds-ep-json-sum {
|
|
11406
12499
|
cursor: pointer; user-select: none;
|
|
11407
12500
|
list-style: none;
|
|
11408
|
-
border-radius: var(--r-1,
|
|
12501
|
+
border-radius: var(--r-1, 8px);
|
|
11409
12502
|
}
|
|
11410
12503
|
.ds-247420 .ds-ep-json-sum::-webkit-details-marker { display: none; }
|
|
11411
12504
|
.ds-247420 .ds-ep-json-sum::before {
|
|
@@ -11435,7 +12528,7 @@
|
|
|
11435
12528
|
color: var(--panel-text-2, var(--fg-2));
|
|
11436
12529
|
font: var(--fs-micro, 11px)/1 var(--ff-mono, monospace);
|
|
11437
12530
|
padding: var(--space-half, 3px) var(--space-2, 8px);
|
|
11438
|
-
border-radius: var(--r-1,
|
|
12531
|
+
border-radius: var(--r-1, 8px);
|
|
11439
12532
|
opacity: 0.75;
|
|
11440
12533
|
}
|
|
11441
12534
|
.ds-247420 .ds-ep-json-copy:hover { opacity: 1; border-color: var(--accent); }
|
|
@@ -11482,7 +12575,7 @@
|
|
|
11482
12575
|
.ds-247420 .ds-ep-btngrp {
|
|
11483
12576
|
display: inline-flex;
|
|
11484
12577
|
border: 1px solid var(--rule);
|
|
11485
|
-
border-radius: var(--r-1,
|
|
12578
|
+
border-radius: var(--r-1, 8px);
|
|
11486
12579
|
overflow: hidden;
|
|
11487
12580
|
background: var(--panel-2);
|
|
11488
12581
|
}
|
|
@@ -11569,7 +12662,7 @@
|
|
|
11569
12662
|
padding: var(--space-2) var(--space-2-5);
|
|
11570
12663
|
background: transparent; border: 0;
|
|
11571
12664
|
color: inherit; font: inherit; text-align: left;
|
|
11572
|
-
border-radius: var(--r-1,
|
|
12665
|
+
border-radius: var(--r-1, 8px);
|
|
11573
12666
|
cursor: pointer;
|
|
11574
12667
|
}
|
|
11575
12668
|
.ds-247420 .ds-ep-ctxmenu-item:hover:not(.disabled),
|
|
@@ -11644,7 +12737,7 @@
|
|
|
11644
12737
|
min-height: var(--ctl-sm); padding: 0 var(--space-3);
|
|
11645
12738
|
display: inline-flex; align-items: center; justify-content: center;
|
|
11646
12739
|
border: 1px solid var(--rule);
|
|
11647
|
-
border-radius: var(--r-1,
|
|
12740
|
+
border-radius: var(--r-1, 8px);
|
|
11648
12741
|
background: var(--panel-2, transparent);
|
|
11649
12742
|
color: inherit; font: inherit; cursor: pointer;
|
|
11650
12743
|
}
|
|
@@ -11681,7 +12774,7 @@
|
|
|
11681
12774
|
.kind-error below recolour border-left-color and nothing else. Do not
|
|
11682
12775
|
demote to a hairline; that would erase the status signal. */
|
|
11683
12776
|
border-left: var(--bw-chunk) solid var(--accent);
|
|
11684
|
-
border-radius: var(--r-1,
|
|
12777
|
+
border-radius: var(--r-1, 8px);
|
|
11685
12778
|
padding: var(--space-2) var(--space-2-75);
|
|
11686
12779
|
box-shadow: var(--shadow-3);
|
|
11687
12780
|
min-width: 220px; max-width: 360px;
|
|
@@ -11704,7 +12797,7 @@
|
|
|
11704
12797
|
font: inherit;
|
|
11705
12798
|
font-weight: 600;
|
|
11706
12799
|
padding: var(--space-1) var(--space-1-75);
|
|
11707
|
-
border-radius: var(--r-1,
|
|
12800
|
+
border-radius: var(--r-1, 8px);
|
|
11708
12801
|
cursor: pointer;
|
|
11709
12802
|
}
|
|
11710
12803
|
.ds-247420 .ds-ep-toast-action:hover { background: var(--panel-2, var(--panel-bg)); }
|
|
@@ -11864,7 +12957,7 @@
|
|
|
11864
12957
|
outline: var(--focus-w) solid var(--focus-color);
|
|
11865
12958
|
outline-offset: var(--focus-offset);
|
|
11866
12959
|
}
|
|
11867
|
-
.ds-247420 .ds-toggle:disabled { cursor: not-allowed; }
|
|
12960
|
+
.ds-247420 .ds-toggle:disabled { cursor: not-allowed; opacity: 0.5; }
|
|
11868
12961
|
|
|
11869
12962
|
@media (prefers-reduced-motion: no-preference) {
|
|
11870
12963
|
.ds-247420 .ds-toggle { transition: background var(--dur-base, 160ms) var(--ease), border-color var(--dur-base, 160ms) var(--ease); }
|
|
@@ -11907,7 +13000,7 @@
|
|
|
11907
13000
|
background: var(--panel-1, var(--panel-bg));
|
|
11908
13001
|
color: var(--panel-text, var(--fg-text));
|
|
11909
13002
|
border: 1px solid var(--rule);
|
|
11910
|
-
border-radius: var(--r-1,
|
|
13003
|
+
border-radius: var(--r-1, 8px);
|
|
11911
13004
|
padding: var(--space-1-75) var(--space-2-5);
|
|
11912
13005
|
font-size: var(--fs-micro);
|
|
11913
13006
|
line-height: 1.4;
|
|
@@ -11960,7 +13053,7 @@
|
|
|
11960
13053
|
padding: var(--space-1-5) var(--space-2-75);
|
|
11961
13054
|
background: transparent; border: 0;
|
|
11962
13055
|
color: inherit; font: inherit; text-align: left;
|
|
11963
|
-
border-radius: var(--r-1,
|
|
13056
|
+
border-radius: var(--r-1, 8px);
|
|
11964
13057
|
cursor: pointer;
|
|
11965
13058
|
}
|
|
11966
13059
|
.ds-247420 .ds-dropdown-item:hover,
|
|
@@ -11989,7 +13082,7 @@
|
|
|
11989
13082
|
background: var(--panel-2, transparent);
|
|
11990
13083
|
color: inherit; font: inherit;
|
|
11991
13084
|
border: 1px solid var(--rule);
|
|
11992
|
-
border-radius: var(--r-1,
|
|
13085
|
+
border-radius: var(--r-1, 8px);
|
|
11993
13086
|
padding: 0 var(--space-2-75);
|
|
11994
13087
|
cursor: pointer;
|
|
11995
13088
|
/* Snapped to the --ctl-sm rung so this small control shares the height
|
|
@@ -12012,7 +13105,7 @@
|
|
|
12012
13105
|
padding: var(--space-1-5) var(--space-2-75);
|
|
12013
13106
|
background: transparent; border: 0;
|
|
12014
13107
|
color: inherit; font: inherit; text-align: left;
|
|
12015
|
-
border-radius: var(--r-1,
|
|
13108
|
+
border-radius: var(--r-1, 8px);
|
|
12016
13109
|
cursor: pointer;
|
|
12017
13110
|
width: 100%;
|
|
12018
13111
|
}
|
|
@@ -12039,7 +13132,7 @@
|
|
|
12039
13132
|
}
|
|
12040
13133
|
.ds-247420 .ov-menubutton-retry {
|
|
12041
13134
|
appearance: none; background: transparent; border: 1px solid var(--rule);
|
|
12042
|
-
border-radius: var(--r-1,
|
|
13135
|
+
border-radius: var(--r-1, 8px); color: inherit; font: inherit; font-size: var(--fs-sm);
|
|
12043
13136
|
padding: var(--space-hair) var(--space-1-5); cursor: pointer;
|
|
12044
13137
|
}
|
|
12045
13138
|
.ds-247420 .ov-menubutton-retry:hover, .ds-247420 .ov-menubutton-retry:focus-visible { background: var(--panel-2, var(--rule)); outline: none; }
|
|
@@ -12048,7 +13141,7 @@
|
|
|
12048
13141
|
background: var(--panel-2, transparent);
|
|
12049
13142
|
color: inherit; font: inherit;
|
|
12050
13143
|
border: 1px solid var(--rule);
|
|
12051
|
-
border-radius: var(--r-1,
|
|
13144
|
+
border-radius: var(--r-1, 8px);
|
|
12052
13145
|
padding: 0 var(--space-2-75);
|
|
12053
13146
|
cursor: pointer;
|
|
12054
13147
|
min-height: var(--ctl-sm); height: var(--ctl-sm);
|
|
@@ -12066,7 +13159,7 @@
|
|
|
12066
13159
|
.ds-247420 .ds-ep-diagnostics-title { margin: 0; font-size: var(--fs-lg); }
|
|
12067
13160
|
.ds-247420 .ds-ep-diagnostics-refresh {
|
|
12068
13161
|
appearance: none; background: var(--panel-2, transparent); color: inherit; font: inherit;
|
|
12069
|
-
border: 1px solid var(--rule); border-radius: var(--r-1,
|
|
13162
|
+
border: 1px solid var(--rule); border-radius: var(--r-1, 8px);
|
|
12070
13163
|
padding: var(--space-1) var(--space-2-75); cursor: pointer;
|
|
12071
13164
|
}
|
|
12072
13165
|
.ds-247420 .ds-ep-diagnostics-refresh:disabled { opacity: 0.6; cursor: not-allowed; }
|
|
@@ -12088,7 +13181,7 @@
|
|
|
12088
13181
|
.ds-247420 .ds-reorderable-horizontal { flex-direction: row; }
|
|
12089
13182
|
.ds-247420 .ds-reorder-item {
|
|
12090
13183
|
display: flex; align-items: center; gap: var(--space-2, 8px);
|
|
12091
|
-
padding: var(--space-1, 4px); border-radius: var(--r-1,
|
|
13184
|
+
padding: var(--space-1, 4px); border-radius: var(--r-1, 8px);
|
|
12092
13185
|
background: var(--panel-1); color: var(--panel-text);
|
|
12093
13186
|
transition: transform var(--dur-snap, 120ms) var(--ease, ease), opacity var(--dur-snap, 120ms) var(--ease, ease);
|
|
12094
13187
|
}
|
|
@@ -12096,7 +13189,7 @@
|
|
|
12096
13189
|
min-width: 44px; min-height: 44px;
|
|
12097
13190
|
display: inline-flex; align-items: center; justify-content: center;
|
|
12098
13191
|
appearance: none; background: transparent; color: var(--panel-text-2, var(--panel-text));
|
|
12099
|
-
border: 0; border-radius: var(--r-1,
|
|
13192
|
+
border: 0; border-radius: var(--r-1, 8px);
|
|
12100
13193
|
cursor: grab; font: 14px/1 var(--ff-mono, monospace); letter-spacing: -2px;
|
|
12101
13194
|
touch-action: none; user-select: none;
|
|
12102
13195
|
}
|
|
@@ -12120,7 +13213,7 @@
|
|
|
12120
13213
|
display: inline-block; font: 0.85em/1 var(--ff-mono, monospace);
|
|
12121
13214
|
padding: var(--space-1, 4px) calc(var(--space-1, 4px) * 1.5);
|
|
12122
13215
|
border: 1px solid var(--rule, var(--panel-text-3));
|
|
12123
|
-
border-radius: var(--r-1,
|
|
13216
|
+
border-radius: var(--r-1, 8px);
|
|
12124
13217
|
background: var(--panel-2, var(--panel-1)); color: var(--panel-text);
|
|
12125
13218
|
}
|
|
12126
13219
|
.ds-247420 .ds-kbd-group { margin: var(--space-3, 16px) 0; }
|
|
@@ -12174,7 +13267,7 @@
|
|
|
12174
13267
|
padding: var(--space-2, 8px) var(--space-3, 16px);
|
|
12175
13268
|
background: transparent; border: 0;
|
|
12176
13269
|
color: var(--fg); font: inherit; text-align: left;
|
|
12177
|
-
border-radius: var(--r-1,
|
|
13270
|
+
border-radius: var(--r-1, 8px); cursor: pointer;
|
|
12178
13271
|
}
|
|
12179
13272
|
.ds-247420 .ov-cmd-item:hover { background: var(--panel-2, var(--rule)); }
|
|
12180
13273
|
.ds-247420 .ov-cmd-item.is-active { background: var(--accent); color: var(--accent-fg); }
|
|
@@ -12202,6 +13295,14 @@
|
|
|
12202
13295
|
box-shadow: var(--shadow-3);
|
|
12203
13296
|
outline: none; overflow: hidden;
|
|
12204
13297
|
}
|
|
13298
|
+
.ds-247420 .ov-emoji-search {
|
|
13299
|
+
flex-shrink: 0; margin: var(--space-2, 8px); margin-bottom: 0;
|
|
13300
|
+
padding: var(--space-1-5, 6px) var(--space-2, 8px);
|
|
13301
|
+
border: 1px solid var(--rule); border-radius: var(--r-1, 8px);
|
|
13302
|
+
background: var(--bg-1, var(--bg-3)); color: var(--fg);
|
|
13303
|
+
font: inherit; font-size: var(--fs-sm, 13px);
|
|
13304
|
+
}
|
|
13305
|
+
.ds-247420 .ov-emoji-search:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; }
|
|
12205
13306
|
.ds-247420 .ov-emoji-tabs {
|
|
12206
13307
|
display: flex; flex-shrink: 0;
|
|
12207
13308
|
border-bottom: 1px solid var(--rule);
|
|
@@ -12214,16 +13315,21 @@
|
|
|
12214
13315
|
}
|
|
12215
13316
|
.ds-247420 .ov-emoji-tab:hover { background: var(--bg-2); }
|
|
12216
13317
|
.ds-247420 .ov-emoji-tab[aria-selected="true"] { border-bottom-color: var(--accent); background: var(--bg-2); }
|
|
13318
|
+
.ds-247420 .ov-emoji-tab:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: -2px; }
|
|
12217
13319
|
.ds-247420 .ov-emoji-grid { overflow: auto; max-height: 220px; padding: var(--space-2, 8px); }
|
|
12218
13320
|
.ds-247420 .ov-emoji-grid-inner { display: grid; grid-template-columns: repeat(8, 1fr); gap: var(--space-1, 4px); }
|
|
12219
13321
|
.ds-247420 .ov-emoji-cell {
|
|
12220
13322
|
appearance: none; border: 0; background: transparent;
|
|
12221
13323
|
aspect-ratio: 1; font-size: var(--fs-lg, 18px);
|
|
12222
|
-
border-radius: var(--r-1,
|
|
13324
|
+
border-radius: var(--r-1, 8px); cursor: pointer;
|
|
12223
13325
|
display: inline-flex; align-items: center; justify-content: center;
|
|
12224
13326
|
}
|
|
12225
|
-
.ds-247420 .ov-emoji-cell:hover
|
|
12226
|
-
background: color-mix(in oklab, var(--accent) 18%, transparent);
|
|
13327
|
+
.ds-247420 .ov-emoji-cell:hover {
|
|
13328
|
+
background: color-mix(in oklab, var(--accent) 18%, transparent);
|
|
13329
|
+
}
|
|
13330
|
+
.ds-247420 .ov-emoji-cell:focus-visible {
|
|
13331
|
+
background: color-mix(in oklab, var(--accent) 18%, transparent);
|
|
13332
|
+
outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px;
|
|
12227
13333
|
}
|
|
12228
13334
|
|
|
12229
13335
|
/* ---------------------------------------------------------------
|
|
@@ -12309,16 +13415,19 @@
|
|
|
12309
13415
|
.ds-247420 .ov-set-control {
|
|
12310
13416
|
appearance: none; flex-shrink: 0; max-width: 55%;
|
|
12311
13417
|
background: var(--bg-3); color: var(--fg);
|
|
12312
|
-
border: 1px solid var(--rule); border-radius: var(--r-1,
|
|
13418
|
+
border: 1px solid var(--rule); border-radius: var(--r-1, 8px);
|
|
12313
13419
|
padding: var(--space-1, 4px) var(--space-2, 8px); font: inherit;
|
|
12314
13420
|
}
|
|
12315
13421
|
.ds-247420 .ov-set-control:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 1px; border-color: var(--accent-ink); }
|
|
12316
13422
|
.ds-247420 input.ov-set-control[type="range"] { padding: 0; accent-color: var(--accent); }
|
|
12317
13423
|
.ds-247420 .ov-set-toggle { width: 18px; height: 18px; accent-color: var(--accent); flex-shrink: 0; cursor: pointer; }
|
|
13424
|
+
@media (pointer: coarse) {
|
|
13425
|
+
.ds-247420 .ov-set-toggle { width: 24px; height: 24px; }
|
|
13426
|
+
}
|
|
12318
13427
|
.ds-247420 .ov-set-btn {
|
|
12319
13428
|
width: 100%; appearance: none; cursor: pointer;
|
|
12320
13429
|
background: var(--accent); color: var(--accent-fg);
|
|
12321
|
-
border: 0; border-radius: var(--r-1,
|
|
13430
|
+
border: 0; border-radius: var(--r-1, 8px);
|
|
12322
13431
|
padding: var(--space-2, 8px); font: inherit;
|
|
12323
13432
|
}
|
|
12324
13433
|
|
|
@@ -12360,7 +13469,7 @@
|
|
|
12360
13469
|
.ds-247420 .ov-lightbox-x { position: absolute; top: 16px; right: 16px; width: 40px; height: 40px; border: none; border-radius: 50%; background: color-mix(in oklab, var(--on-color) 12%, transparent); color: var(--on-color); font-size: 24px; line-height: 1; cursor: pointer; }
|
|
12361
13470
|
.ds-247420 .ov-lightbox-x:hover { background: color-mix(in oklab, var(--on-color) 24%, transparent); }
|
|
12362
13471
|
.ds-247420 .ov-lightbox-stage { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); max-width: 92vw; max-height: 90vh; }
|
|
12363
|
-
.ds-247420 .ov-lightbox-video { max-width: 92vw; max-height: 82vh; border-radius: var(--r-1); background:
|
|
13472
|
+
.ds-247420 .ov-lightbox-video { max-width: 92vw; max-height: 82vh; border-radius: var(--r-1); background: var(--media-letterbox); /* true black media letterbox, intentional */ }
|
|
12364
13473
|
.ds-247420 .ov-lightbox-label { color: var(--on-color); font-size: var(--fs-tiny); opacity: .85; }
|
|
12365
13474
|
|
|
12366
13475
|
/* ---------------------------------------------------------------
|
|
@@ -12404,7 +13513,7 @@
|
|
|
12404
13513
|
.ds-247420 .ds-input-color {
|
|
12405
13514
|
appearance: none; -webkit-appearance: none;
|
|
12406
13515
|
width: 28px; height: 22px; padding: 0;
|
|
12407
|
-
border: 1px solid var(--rule); border-radius: var(--r-1,
|
|
13516
|
+
border: 1px solid var(--rule); border-radius: var(--r-1, 8px);
|
|
12408
13517
|
background: var(--panel-2); cursor: pointer; flex-shrink: 0;
|
|
12409
13518
|
}
|
|
12410
13519
|
.ds-247420 .ds-input-color::-webkit-color-swatch-wrapper { padding: var(--space-hair); }
|
|
@@ -12413,7 +13522,7 @@
|
|
|
12413
13522
|
.ds-247420 .ds-input-check {
|
|
12414
13523
|
appearance: none; -webkit-appearance: none;
|
|
12415
13524
|
width: 16px; height: 16px; flex-shrink: 0;
|
|
12416
|
-
border: 1px solid var(--rule); border-radius: var(--r-1,
|
|
13525
|
+
border: 1px solid var(--rule); border-radius: var(--r-1, 8px);
|
|
12417
13526
|
background: var(--panel-2); cursor: pointer; position: relative;
|
|
12418
13527
|
}
|
|
12419
13528
|
.ds-247420 .ds-input-check:checked { background: var(--accent); border-color: var(--accent); }
|
|
@@ -12499,7 +13608,7 @@
|
|
|
12499
13608
|
/* Collapse / CollapseGroup — progressive-disclosure toggle panel. */
|
|
12500
13609
|
.ds-247420 .ds-ep-collapse {
|
|
12501
13610
|
border: 1px solid var(--rule);
|
|
12502
|
-
border-radius: var(--r-1,
|
|
13611
|
+
border-radius: var(--r-1, 8px);
|
|
12503
13612
|
background: var(--panel-2, var(--bg-2));
|
|
12504
13613
|
}
|
|
12505
13614
|
.ds-247420 .ds-ep-collapse + .ds-ep-collapse { margin-top: var(--space-1, 4px); }
|
|
@@ -12562,7 +13671,7 @@
|
|
|
12562
13671
|
padding: var(--space-2, 8px) var(--space-3, 16px);
|
|
12563
13672
|
background: transparent; border: 0;
|
|
12564
13673
|
color: var(--fg); font: inherit; text-align: left;
|
|
12565
|
-
border-radius: var(--r-1,
|
|
13674
|
+
border-radius: var(--r-1, 8px); cursor: pointer;
|
|
12566
13675
|
}
|
|
12567
13676
|
.ds-247420 .ov-perm-item:hover { background: var(--panel-2, var(--rule)); }
|
|
12568
13677
|
.ds-247420 .ov-perm-item[aria-checked="true"] { color: var(--accent-ink); }
|
|
@@ -12577,7 +13686,7 @@
|
|
|
12577
13686
|
.ds-247420 .ov-perm-action {
|
|
12578
13687
|
flex: 1; appearance: none; border: 1px solid var(--rule); background: transparent;
|
|
12579
13688
|
color: var(--fg-2); font: inherit; font-size: var(--fs-tiny, 12px);
|
|
12580
|
-
padding: var(--space-1) var(--space-2); border-radius: var(--r-1,
|
|
13689
|
+
padding: var(--space-1) var(--space-2); border-radius: var(--r-1, 8px); cursor: pointer;
|
|
12581
13690
|
}
|
|
12582
13691
|
.ds-247420 .ov-perm-action:hover { background: var(--panel-2, var(--rule)); }
|
|
12583
13692
|
|
|
@@ -12600,14 +13709,14 @@
|
|
|
12600
13709
|
.ds-247420 .ov-approval-cat { color: var(--fg-3); font-weight: 400; }
|
|
12601
13710
|
.ds-247420 .ov-approval-args {
|
|
12602
13711
|
margin: 0; padding: var(--space-2, 8px);
|
|
12603
|
-
background: var(--panel-2, var(--rule)); border-radius: var(--r-1,
|
|
13712
|
+
background: var(--panel-2, var(--rule)); border-radius: var(--r-1, 8px);
|
|
12604
13713
|
font: var(--fs-tiny, 12px)/1.4 var(--ff-mono, monospace);
|
|
12605
13714
|
color: var(--fg-3); max-height: 100px; overflow: auto; white-space: pre-wrap; word-break: break-all;
|
|
12606
13715
|
}
|
|
12607
13716
|
.ds-247420 .ov-approval-note {
|
|
12608
13717
|
width: 100%; min-height: 48px; resize: vertical;
|
|
12609
13718
|
padding: var(--space-2, 8px) var(--space-2-75, 12px);
|
|
12610
|
-
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1,
|
|
13719
|
+
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1, 8px);
|
|
12611
13720
|
background: var(--bg); color: var(--fg); font: inherit; box-sizing: border-box;
|
|
12612
13721
|
}
|
|
12613
13722
|
.ds-247420 .ov-approval-note:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
|
|
@@ -12691,6 +13800,48 @@
|
|
|
12691
13800
|
padding: 0;
|
|
12692
13801
|
}
|
|
12693
13802
|
|
|
13803
|
+
/* app topbar — mountCommunityApp's own sole chrome above the chat-head; had
|
|
13804
|
+
no rules anywhere (relying on raw flex defaults), which read as unaligned
|
|
13805
|
+
default spacing rather than a designed header row. */
|
|
13806
|
+
.ds-247420.ds-247420 .app-topbar {
|
|
13807
|
+
display: flex;
|
|
13808
|
+
align-items: center;
|
|
13809
|
+
gap: var(--space-3);
|
|
13810
|
+
height: 48px;
|
|
13811
|
+
flex-shrink: 0;
|
|
13812
|
+
padding: 0 var(--space-3);
|
|
13813
|
+
background: var(--bg-2);
|
|
13814
|
+
border-bottom: 1px solid var(--panel-3, color-mix(in oklab, var(--fg) 10%, transparent));
|
|
13815
|
+
}
|
|
13816
|
+
.ds-247420.ds-247420 .app-topbar .brand {
|
|
13817
|
+
display: flex;
|
|
13818
|
+
align-items: baseline;
|
|
13819
|
+
gap: var(--space-1);
|
|
13820
|
+
min-width: 0;
|
|
13821
|
+
font-weight: var(--fw-medium, 500);
|
|
13822
|
+
font-size: var(--fs-sm);
|
|
13823
|
+
color: var(--fg);
|
|
13824
|
+
overflow: hidden;
|
|
13825
|
+
white-space: nowrap;
|
|
13826
|
+
text-overflow: ellipsis;
|
|
13827
|
+
}
|
|
13828
|
+
.ds-247420.ds-247420 .app-topbar .brand .slash { color: var(--fg-3); }
|
|
13829
|
+
.ds-247420.ds-247420 .app-topbar nav {
|
|
13830
|
+
display: flex;
|
|
13831
|
+
align-items: center;
|
|
13832
|
+
gap: var(--space-2);
|
|
13833
|
+
}
|
|
13834
|
+
.ds-247420.ds-247420 .app-topbar nav a {
|
|
13835
|
+
color: var(--fg-2);
|
|
13836
|
+
font-size: var(--fs-tiny);
|
|
13837
|
+
text-decoration: none;
|
|
13838
|
+
padding: var(--space-1) var(--space-1-5);
|
|
13839
|
+
border-radius: var(--r-1);
|
|
13840
|
+
transition: background var(--dur-snap, .12s) var(--ease, ease), color var(--dur-snap, .12s) var(--ease, ease);
|
|
13841
|
+
}
|
|
13842
|
+
.ds-247420.ds-247420 .app-topbar nav a:hover { color: var(--fg); background: color-mix(in oklab, var(--fg) 8%, transparent); }
|
|
13843
|
+
.ds-247420.ds-247420 .app-topbar nav a:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: 2px; }
|
|
13844
|
+
|
|
12694
13845
|
/* server + channel rail */
|
|
12695
13846
|
.ds-247420.ds-247420 .ca-rail {
|
|
12696
13847
|
display: flex;
|
|
@@ -12706,7 +13857,7 @@
|
|
|
12706
13857
|
}
|
|
12707
13858
|
.ds-247420.ds-247420 .ca-rail .group {
|
|
12708
13859
|
font-size: 11px;
|
|
12709
|
-
font-weight: 600;
|
|
13860
|
+
font-weight: var(--fw-semibold, 600);
|
|
12710
13861
|
letter-spacing: 0.04em;
|
|
12711
13862
|
text-transform: uppercase;
|
|
12712
13863
|
color: var(--fg-3, color-mix(in oklab, var(--fg) 55%, transparent));
|
|
@@ -12766,7 +13917,7 @@
|
|
|
12766
13917
|
background: var(--accent);
|
|
12767
13918
|
color: var(--on-accent);
|
|
12768
13919
|
font-size: 11px;
|
|
12769
|
-
font-weight: 600;
|
|
13920
|
+
font-weight: var(--fw-semibold, 600);
|
|
12770
13921
|
text-align: center;
|
|
12771
13922
|
}
|
|
12772
13923
|
.ds-247420.ds-247420 .ca-rail .rail-empty {
|
|
@@ -12977,7 +14128,7 @@
|
|
|
12977
14128
|
.ds-247420 .health-summary { display: flex; flex-wrap: wrap; gap: .4em; margin: .6em 0; }
|
|
12978
14129
|
.ds-247420 .health-chip {
|
|
12979
14130
|
font-family: var(--ff-mono, ui-monospace, monospace);
|
|
12980
|
-
font-size: .8rem; padding: .15em .55em; border-radius: var(--r-1,
|
|
14131
|
+
font-size: .8rem; padding: .15em .55em; border-radius: var(--r-1, 8px);
|
|
12981
14132
|
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
|
12982
14133
|
color: var(--fg-2);
|
|
12983
14134
|
border: var(--bw-hair, 1px) solid color-mix(in srgb, var(--fg) 12%, transparent);
|
|
@@ -12995,7 +14146,7 @@
|
|
|
12995
14146
|
.ds-247420 .ds-status-chip {
|
|
12996
14147
|
display: inline-flex; align-items: center; gap: .35em;
|
|
12997
14148
|
font-family: var(--ff-mono, ui-monospace, monospace);
|
|
12998
|
-
font-size: .8rem; padding: .15em .55em; border-radius: var(--r-1,
|
|
14149
|
+
font-size: .8rem; padding: .15em .55em; border-radius: var(--r-1, 8px);
|
|
12999
14150
|
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
|
13000
14151
|
color: var(--fg-2);
|
|
13001
14152
|
border: var(--bw-hair, 1px) solid color-mix(in srgb, var(--fg) 12%, transparent);
|
|
@@ -13023,7 +14174,7 @@
|
|
|
13023
14174
|
}
|
|
13024
14175
|
.ds-247420 .cwd-bar-btn {
|
|
13025
14176
|
cursor: pointer; font: inherit; line-height: 1.3;
|
|
13026
|
-
padding: .15em .55em; border-radius: var(--r-1,
|
|
14177
|
+
padding: .15em .55em; border-radius: var(--r-1, 8px);
|
|
13027
14178
|
background: color-mix(in srgb, var(--fg) 8%, transparent);
|
|
13028
14179
|
border: var(--bw-hair, 1px) solid color-mix(in srgb, var(--fg) 14%, transparent);
|
|
13029
14180
|
color: var(--fg-2);
|
|
@@ -13111,7 +14262,7 @@
|
|
|
13111
14262
|
/* Re-assert the paper-tuned signal tokens so token-derived foregrounds
|
|
13112
14263
|
(status discs, error text, tool cards) print with light-theme colours
|
|
13113
14264
|
rather than the dark-theme-derived values inherited under auto-dark. */
|
|
13114
|
-
.ds-247420 { --flame:#C53E00; --amber:#7C570F; --warn:#
|
|
14265
|
+
.ds-247420 { --flame:#C53E00; --amber:#7C570F; --warn:#C41C0C; --sky:#3A6EFF; --bg:var(--paper); --fg:var(--ink); }
|
|
13115
14266
|
.ds-247420 #app { min-height: auto; display: block; height: auto; }
|
|
13116
14267
|
.ds-247420 .skip-link, .ds-247420 .status-dot, .ds-247420 .history-actions, .ds-247420 .chat-composer { display: none !important; }
|
|
13117
14268
|
.ds-247420 .app, .ds-247420 .app-main, .ds-247420 .panel, .ds-247420 .chat, .ds-247420 .chat-thread {
|
|
@@ -13143,20 +14294,12 @@
|
|
|
13143
14294
|
.ds-247420 .fd-page-error { max-height: 60vh; overflow: auto; white-space: pre-wrap; word-break: break-all; }
|
|
13144
14295
|
|
|
13145
14296
|
/* gm-prose.css */
|
|
13146
|
-
/* ============================================================
|
|
13147
|
-
gm-prose -- long-form article + doc-site prose surfaces
|
|
13148
|
-
Extracted-article host, sticky table-of-contents rail, CLI
|
|
13149
|
-
transcript block, definition-panel rows, repo cards, tag
|
|
13150
|
-
chips, and attributed callouts. Consumed pro-rata by doc
|
|
13151
|
-
sites (the gm paper) that mount the SDK and inject a flatspace
|
|
13152
|
-
article into #ds-article-host. Every color is a token from
|
|
13153
|
-
colors_and_type.css; no raw literals.
|
|
13154
|
-
============================================================ */
|
|
13155
|
-
|
|
13156
14297
|
.ds-247420 .ds-prose { line-height: 1.65; }
|
|
13157
14298
|
.ds-247420 .ds-prose a { color: var(--panel-accent); }
|
|
13158
14299
|
.ds-247420 .ds-prose a:hover { background: none; color: var(--panel-accent); text-decoration-color: transparent; }
|
|
13159
14300
|
.ds-247420 .ds-prose pre, .ds-247420 .ds-prose table { overflow-x: auto; max-width: 100%; }
|
|
14301
|
+
.ds-247420 .ds-prose .mermaid { max-width: 100%; }
|
|
14302
|
+
.ds-247420 .ds-prose .mermaid svg { max-width: 100%; height: auto; cursor: zoom-in; }
|
|
13160
14303
|
.ds-247420 .ds-prose canvas {
|
|
13161
14304
|
display: block;
|
|
13162
14305
|
width: 100%;
|
|
@@ -13172,33 +14315,33 @@
|
|
|
13172
14315
|
min-height: 0;
|
|
13173
14316
|
}
|
|
13174
14317
|
|
|
14318
|
+
.ds-247420 {
|
|
14319
|
+
--article-toc-rail-w: 256px;
|
|
14320
|
+
--article-toc-gutter-nonrhythm: 44px;
|
|
14321
|
+
--article-toc-header-gap: 16px;
|
|
14322
|
+
}
|
|
13175
14323
|
.ds-247420 #ds-article-host.has-toc {
|
|
13176
14324
|
display: flex;
|
|
13177
14325
|
align-items: flex-start;
|
|
13178
|
-
|
|
13179
|
-
|
|
13180
|
-
|
|
13181
|
-
would silently change the host's computed max-width unless the calc were
|
|
13182
|
-
re-derived, so the literal and the calc stay coupled and explicit. */
|
|
13183
|
-
column-gap: 44px;
|
|
13184
|
-
gap: 44px;
|
|
13185
|
-
max-width: calc(256px + 44px + var(--measure-narrow));
|
|
14326
|
+
column-gap: var(--article-toc-gutter-nonrhythm);
|
|
14327
|
+
gap: var(--article-toc-gutter-nonrhythm);
|
|
14328
|
+
max-width: calc(var(--article-toc-rail-w) + var(--article-toc-gutter-nonrhythm) + var(--measure));
|
|
13186
14329
|
margin-left: auto;
|
|
13187
14330
|
margin-right: auto;
|
|
13188
14331
|
}
|
|
13189
14332
|
.ds-247420 #ds-article-host.has-toc > .article-col {
|
|
13190
14333
|
flex: 1 1 0;
|
|
13191
14334
|
min-width: 0;
|
|
13192
|
-
max-width: var(--measure
|
|
14335
|
+
max-width: var(--measure);
|
|
13193
14336
|
}
|
|
13194
14337
|
.ds-247420 #ds-article-host.has-toc > .toc {
|
|
13195
|
-
flex: 0 0
|
|
14338
|
+
flex: 0 0 var(--article-toc-rail-w);
|
|
13196
14339
|
align-self: flex-start;
|
|
13197
14340
|
position: sticky;
|
|
13198
|
-
top:
|
|
14341
|
+
top: calc(var(--article-header-h, calc(var(--app-topbar-h, 0px) + var(--app-crumb-h, 0px))) + var(--article-toc-header-gap));
|
|
13199
14342
|
align-self: start;
|
|
13200
|
-
max-height: calc(100vh -
|
|
13201
|
-
max-height: calc(100dvh -
|
|
14343
|
+
max-height: calc(100vh - var(--article-header-h, calc(var(--app-topbar-h, 0px) + var(--app-crumb-h, 0px))) - 32px);
|
|
14344
|
+
max-height: calc(100dvh - var(--article-header-h, calc(var(--app-topbar-h, 0px) + var(--app-crumb-h, 0px))) - 32px);
|
|
13202
14345
|
overflow-y: auto;
|
|
13203
14346
|
overscroll-behavior: contain;
|
|
13204
14347
|
margin: 0;
|
|
@@ -13222,15 +14365,6 @@
|
|
|
13222
14365
|
background: var(--panel-text-3);
|
|
13223
14366
|
background-clip: padding-box;
|
|
13224
14367
|
}
|
|
13225
|
-
/* Small-label voice — the local composition of the house `.t-label` recipe
|
|
13226
|
-
(src/css/app-shell/base.css). This sheet is a standalone published export
|
|
13227
|
-
with its own <link>, so it cannot join the `.t-label` selector list; it
|
|
13228
|
-
composes by referencing the identical token set. Both members are gm-
|
|
13229
|
-
generated markup (injected into #ds-article-host), so the class list is not
|
|
13230
|
-
reachable from src/ — the rule, not the markup, does the composing.
|
|
13231
|
-
Deliberate override for both: --panel-text-2, because prose surfaces use the
|
|
13232
|
-
panel text ramp rather than the app --fg ramp. Sized at --fs-nano: these
|
|
13233
|
-
labels ride above dense article chrome, not UI text. */
|
|
13234
14368
|
.ds-247420 #ds-article-host .toc .toc-title,
|
|
13235
14369
|
.ds-247420 .ds-prose .gm-callout .who {
|
|
13236
14370
|
font-family: var(--ff-mono);
|
|
@@ -13244,10 +14378,37 @@
|
|
|
13244
14378
|
margin: 0 0 var(--space-3) 0;
|
|
13245
14379
|
}
|
|
13246
14380
|
.ds-247420 #ds-article-host .toc ol { margin: 0; padding-left: var(--space-3-5); }
|
|
13247
|
-
.ds-247420 #ds-article-host .toc li {
|
|
14381
|
+
.ds-247420 #ds-article-host .toc li {
|
|
14382
|
+
font-size: var(--fs-tiny);
|
|
14383
|
+
line-height: 1.85;
|
|
14384
|
+
color: var(--panel-text);
|
|
14385
|
+
min-height: 1.85em;
|
|
14386
|
+
}
|
|
14387
|
+
.ds-247420 #ds-article-host .toc li:nth-child(5n) { margin-bottom: var(--space-2); }
|
|
13248
14388
|
.ds-247420 #ds-article-host .toc li::marker { color: var(--panel-text-3); font-variant-numeric: tabular-nums; }
|
|
13249
14389
|
.ds-247420 #ds-article-host .toc a { color: var(--panel-text-2); text-decoration: none; transition: color .12s ease; }
|
|
13250
14390
|
.ds-247420 #ds-article-host .toc a:hover { color: var(--panel-accent); }
|
|
14391
|
+
.ds-247420 #ds-article-host .toc li.toc-group {
|
|
14392
|
+
margin-top: var(--space-3);
|
|
14393
|
+
padding-top: var(--space-2);
|
|
14394
|
+
border-top: 1px solid var(--panel-3);
|
|
14395
|
+
list-style: none;
|
|
14396
|
+
font-family: var(--ff-mono);
|
|
14397
|
+
font-size: var(--fs-nano);
|
|
14398
|
+
text-transform: uppercase;
|
|
14399
|
+
letter-spacing: var(--tr-label);
|
|
14400
|
+
color: var(--panel-text-3);
|
|
14401
|
+
}
|
|
14402
|
+
.ds-247420 #ds-article-host .toc li.toc-group > ol {
|
|
14403
|
+
margin-top: var(--space-1-5);
|
|
14404
|
+
padding-left: var(--space-3);
|
|
14405
|
+
}
|
|
14406
|
+
.ds-247420 #ds-article-host .toc li.toc-group li {
|
|
14407
|
+
font-size: var(--fs-nano);
|
|
14408
|
+
line-height: 1.7;
|
|
14409
|
+
min-height: 1.7em;
|
|
14410
|
+
}
|
|
14411
|
+
.ds-247420 #ds-article-host .toc li.toc-group li:nth-child(5n) { margin-bottom: 0; }
|
|
13251
14412
|
.ds-247420 #ds-article-host.has-toc > .article-col > * { min-width: 0; }
|
|
13252
14413
|
@media (max-width: 900px) {
|
|
13253
14414
|
.ds-247420 #ds-article-host.has-toc { display: block; }
|
|
@@ -13260,28 +14421,15 @@
|
|
|
13260
14421
|
}
|
|
13261
14422
|
}
|
|
13262
14423
|
|
|
13263
|
-
/* .ds-cli-block — the multi-row article/transcript container (CliBlock()'s
|
|
13264
|
-
outer wrapper holding stacked .ds-cli-row / .ds-cli-comment children).
|
|
13265
|
-
Distinct from the bare `.cli` single prompt+cmd row primitive owned by
|
|
13266
|
-
app-shell.css (Install(), HeroFromPageData(), terminal/site quickstart
|
|
13267
|
-
lines) — the two used to share the `.cli` selector with incompatible
|
|
13268
|
-
display models (flex row vs block transcript), so whichever stylesheet
|
|
13269
|
-
loaded last silently won for both consumers. Renamed here to remove the
|
|
13270
|
-
collision; see content.js CliBlock(). */
|
|
13271
14424
|
.ds-247420 .ds-cli-block {
|
|
14425
|
+
--ds-cli-block-fs-mono-halfrung: 12.5px;
|
|
13272
14426
|
display: block;
|
|
13273
14427
|
background: var(--panel-1);
|
|
13274
14428
|
border-radius: var(--r-0);
|
|
13275
14429
|
padding: var(--space-3) var(--space-3-5);
|
|
13276
14430
|
margin: var(--space-3) 0 var(--space-5) 0;
|
|
13277
14431
|
font-family: var(--ff-mono);
|
|
13278
|
-
|
|
13279
|
-
in the mono face, which runs optically ~1 rung larger than the system
|
|
13280
|
-
stack at the same px. --fs-micro (12) reads thin against the surrounding
|
|
13281
|
-
prose and --fs-tiny (13) reads heavy; 12.5 is the tuned midpoint. There is
|
|
13282
|
-
no half-rung on the --fs-* ladder and one must not be invented for a
|
|
13283
|
-
single block, so this literal stays. */
|
|
13284
|
-
font-size: 12.5px;
|
|
14432
|
+
font-size: var(--ds-cli-block-fs-mono-halfrung);
|
|
13285
14433
|
line-height: 1.6;
|
|
13286
14434
|
color: var(--panel-text);
|
|
13287
14435
|
box-shadow: var(--panel-shadow);
|
|
@@ -13354,18 +14502,11 @@
|
|
|
13354
14502
|
color: var(--panel-text-2);
|
|
13355
14503
|
border: 1px solid var(--panel-3);
|
|
13356
14504
|
font-size: 0.7rem;
|
|
13357
|
-
|
|
13358
|
-
|
|
13359
|
-
when a doc site scales root font-size. A px rung would decouple them. */
|
|
13360
|
-
padding: 0.15rem 0.5rem;
|
|
14505
|
+
--tag-inset-rem-coupled-to-root-fontsize: 0.15rem 0.5rem;
|
|
14506
|
+
padding: var(--tag-inset-rem-coupled-to-root-fontsize);
|
|
13361
14507
|
border-radius: var(--r-hair);
|
|
13362
14508
|
font-family: var(--ff-mono);
|
|
13363
14509
|
}
|
|
13364
|
-
/* Attributed callout — an editorial pull-quote (it carries a .who byline), so
|
|
13365
|
-
the left accent is DELIBERATE, not the generic alert stripe. Expressed via
|
|
13366
|
-
the house .panel-spine idiom (absolute ::before rail at --bw-chunk, squared
|
|
13367
|
-
leading corners) instead of a raw 3px border-left, so it stays on the border
|
|
13368
|
-
scale and matches the spine primitive in panel-row.css. */
|
|
13369
14510
|
.ds-247420 .ds-prose .gm-callout {
|
|
13370
14511
|
position: relative;
|
|
13371
14512
|
margin: var(--space-3-5) 0;
|
|
@@ -13380,23 +14521,11 @@
|
|
|
13380
14521
|
width: var(--bw-chunk); background: var(--panel-accent);
|
|
13381
14522
|
border-radius: var(--bw-chunk) 0 0 var(--bw-chunk);
|
|
13382
14523
|
}
|
|
13383
|
-
/* Joins the small-label voice above; only its own box properties here. */
|
|
13384
14524
|
.ds-247420 .ds-prose .gm-callout .who {
|
|
13385
14525
|
display: block;
|
|
13386
14526
|
margin-bottom: var(--space-1);
|
|
13387
14527
|
}
|
|
13388
14528
|
|
|
13389
|
-
/* .ds-prose-endnote — the closing line of an article ("end. reply by opening a
|
|
13390
|
-
pr."), set off from the body it terminates. Quieter and smaller than prose:
|
|
13391
|
-
it takes the mono face and the --panel-text-2 tone that this sheet's other
|
|
13392
|
-
ancillary voices use (.toc a, .gm-callout .who, .card .desc), so the endnote
|
|
13393
|
-
reads as chrome around the article rather than a final paragraph of it. The
|
|
13394
|
-
generous --space-5 lead is what does the "set off" — it breaks the paragraph
|
|
13395
|
-
rhythm so the eye registers the piece has ended before reading the words.
|
|
13396
|
-
Sized at --fs-xs rather than the --fs-nano label rung: this is a readable
|
|
13397
|
-
sentence with a link in it, not an uppercase micro-label.
|
|
13398
|
-
Replaces the inline style ui_kits/blog carried before the inline-style
|
|
13399
|
-
sweep, which named this class without ever defining it. */
|
|
13400
14529
|
.ds-247420 .ds-prose .ds-prose-endnote,
|
|
13401
14530
|
.ds-247420 .ds-prose-endnote {
|
|
13402
14531
|
margin-top: var(--space-5);
|
|
@@ -13406,9 +14535,6 @@
|
|
|
13406
14535
|
line-height: 1.6;
|
|
13407
14536
|
color: var(--panel-text-2);
|
|
13408
14537
|
}
|
|
13409
|
-
/* The endnote's link keeps the prose accent but stays in the quiet register —
|
|
13410
|
-
--panel-accent is the panel-ramp counterpart of --accent-ink (a readable
|
|
13411
|
-
TEXT tone), never the bare --accent fill, which is ~1.07:1 on paper. */
|
|
13412
14538
|
.ds-247420 .ds-prose-endnote a { color: var(--panel-accent); text-decoration: none; }
|
|
13413
14539
|
.ds-247420 .ds-prose-endnote a:hover { text-decoration: underline; }
|
|
13414
14540
|
|
|
@@ -13419,14 +14545,14 @@
|
|
|
13419
14545
|
* prefixer leaves it untouched (consumers mount on <html class="ds-247420">).
|
|
13420
14546
|
* All values read kit tokens — no hardcoded hex, no inline design in the app. */
|
|
13421
14547
|
|
|
13422
|
-
.ds-247420 .site-panel { margin: var(--space-2); }
|
|
14548
|
+
.ds-247420 .site-panel { margin: var(--space-2); max-width: 1100px; padding: var(--space-3, 16px); }
|
|
13423
14549
|
|
|
13424
14550
|
/* Hero block */
|
|
13425
14551
|
.ds-247420 .site-hero { padding: var(--space-4); }
|
|
13426
14552
|
.ds-247420 .site-hero-h { margin: 0 0 var(--space-2); }
|
|
13427
14553
|
.ds-247420 .site-hero-body { margin: var(--space-2) 0 var(--space-3); color: var(--fg-2); max-width: 64ch; }
|
|
13428
|
-
.ds-247420 .site-chip-row { display: flex; gap: 6px; flex-wrap: wrap; margin: 0 0 var(--space-3); }
|
|
13429
|
-
.ds-247420 .site-cta-row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
|
|
14554
|
+
.ds-247420 .site-chip-row { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin: 0 0 var(--space-3); }
|
|
14555
|
+
.ds-247420 .site-cta-row { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
|
|
13430
14556
|
|
|
13431
14557
|
/* Quickstart CLI block — these .cli/.prompt/.cmd nodes were previously unstyled. */
|
|
13432
14558
|
.ds-247420 .site-cli { padding: var(--space-3); background: var(--bg); border: var(--bw-hair, 1px) solid var(--rule); border-radius: var(--r-1); }
|
|
@@ -13594,8 +14720,8 @@
|
|
|
13594
14720
|
width: min(360px, 88vw);
|
|
13595
14721
|
display: flex;
|
|
13596
14722
|
flex-direction: column;
|
|
13597
|
-
gap:
|
|
13598
|
-
padding:
|
|
14723
|
+
gap: var(--space-2-75);
|
|
14724
|
+
padding: var(--space-4);
|
|
13599
14725
|
background: var(--bg-2);
|
|
13600
14726
|
border: 1px solid var(--bw-rule, var(--rule));
|
|
13601
14727
|
border-radius: var(--r-2, 10px);
|
|
@@ -13624,7 +14750,7 @@
|
|
|
13624
14750
|
font-family: var(--ff-mono);
|
|
13625
14751
|
font-size: var(--fs-body);
|
|
13626
14752
|
padding: 10px 14px;
|
|
13627
|
-
border-radius: var(--r-1,
|
|
14753
|
+
border-radius: var(--r-1, 8px);
|
|
13628
14754
|
cursor: pointer;
|
|
13629
14755
|
}
|
|
13630
14756
|
.ds-247420 .sp-lobby-btn:hover { background: var(--bg-2); }
|
|
@@ -13641,12 +14767,12 @@
|
|
|
13641
14767
|
background: var(--bg);
|
|
13642
14768
|
color: var(--fg);
|
|
13643
14769
|
border: 1px solid var(--bw-rule, var(--rule));
|
|
13644
|
-
border-radius: var(--r-1,
|
|
13645
|
-
padding:
|
|
14770
|
+
border-radius: var(--r-1, 8px);
|
|
14771
|
+
padding: var(--space-2) var(--space-2-5);
|
|
13646
14772
|
font: var(--fs-body) var(--ff-mono);
|
|
13647
14773
|
outline: none;
|
|
13648
14774
|
}
|
|
13649
|
-
.ds-247420 .sp-lobby-input:focus { border-color: var(--accent); }
|
|
14775
|
+
.ds-247420 .sp-lobby-input:focus-visible { border-color: var(--accent); box-shadow: var(--focus-ring-inset); }
|
|
13650
14776
|
.ds-247420 .sp-lobby-link { font-size: var(--fs-small, 11px); }
|
|
13651
14777
|
.ds-247420 .sp-lobby-code {
|
|
13652
14778
|
font-family: var(--ff-display);
|
|
@@ -13656,7 +14782,7 @@
|
|
|
13656
14782
|
color: var(--accent);
|
|
13657
14783
|
padding: 8px;
|
|
13658
14784
|
background: var(--bg);
|
|
13659
|
-
border-radius: var(--r-1,
|
|
14785
|
+
border-radius: var(--r-1, 8px);
|
|
13660
14786
|
}
|
|
13661
14787
|
.ds-247420 .sp-lobby-err { min-height: 16px; color: var(--danger); font-size: var(--fs-small, 11px); }
|
|
13662
14788
|
.ds-247420 .sp-lobby-close {
|