@fasl-work/caos-app-shell 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -14
- package/bin/caos-shell-gate.mjs +5 -2
- package/dist/chart.d.ts +28 -3
- package/dist/chart.js +59 -23
- package/dist/{chunk-LOSSTLPP.js → chunk-ZLJCB7DD.js} +43 -4
- package/dist/index.d.ts +248 -111
- package/dist/index.js +308 -22
- package/dist/{tokens-CSV0MOgR.d.ts → tokens-DkyEXX5g.d.ts} +21 -4
- package/gate/inpage.mjs +280 -9
- package/gate/run.mjs +126 -9
- package/package.json +1 -1
- package/reserved-classes.json +239 -3
- package/styles.css +445 -367
package/styles.css
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
@import "katex/dist/katex.min.css";
|
|
2
2
|
|
|
3
|
-
/* @fasl-work/caos-app-shell
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
/* @fasl-work/caos-app-shell: the design system of every CAOS / Faena app (ADR-0016, ADR-0017, ADR-0071, ADR-0078).
|
|
4
|
+
* Import once per app: import "@fasl-work/caos-app-shell/styles.css";
|
|
5
|
+
*
|
|
6
|
+
* The stylesheet is written in ordered layers, and each class is defined in ONE place (layer 6 once defined
|
|
7
|
+
* `.tablist` twice and `.subtablist` wrapping and then forced to one row; the later rule always won):
|
|
8
|
+
* 1 tokens colours per theme, fonts, type, space, radii, layout sizes, icon sizes, z-order
|
|
9
|
+
* 2 base reset, document, links, focus, reduced motion
|
|
10
|
+
* 3 frame .app-shell, header, main, footer, skip link; the modes default, fixed and contain
|
|
11
|
+
* 4 routes the three route bodies: document (.page-body), workbench (.caos-wb), surface (.caos-surface)
|
|
12
|
+
* 5 navigation every row of links or tabs: one line, never shrinking, faded ends when it scrolls
|
|
13
|
+
* 6 content prose, page head, reading measure, grids, callouts, equations, figures, references, diagrams
|
|
14
|
+
* 7 controls buttons, selects, ranges, chips, knobs, native controls, icons
|
|
15
|
+
* 8 case the case selector
|
|
16
|
+
* 9 workbench rail, instrument, groups, variants, readouts, gauges, verdicts, plot cards, stages, tables
|
|
17
|
+
* 10 frames the focus frame (ADR-0070), the authenticated console frame, the architecture modal
|
|
18
|
+
*
|
|
19
|
+
* Breakpoints are one set, used everywhere: 480 px (phone), 760 px (compact header, single columns), 900 px (the
|
|
20
|
+
* workbench stacks and the document scrolls). The gate's large screen is 1280 px (ADR-0071 Verification). A product
|
|
21
|
+
* composes these classes and never redefines them (reserved-classes.json, ADR-0078). */
|
|
22
|
+
|
|
23
|
+
/* == 1 tokens =================================================================================================== */
|
|
7
24
|
|
|
8
25
|
:root,
|
|
9
26
|
[data-theme="dark"] {
|
|
@@ -13,7 +30,7 @@
|
|
|
13
30
|
--color-border: #30363d;
|
|
14
31
|
--color-fg: #c9d1d9;
|
|
15
32
|
--color-fg-subtle: #9aa6b2;
|
|
16
|
-
--color-fg-faint: #
|
|
33
|
+
--color-fg-faint: #828b97;
|
|
17
34
|
--color-accent: #58a6ff;
|
|
18
35
|
--color-accent-fg: #0d1117;
|
|
19
36
|
--color-accent-soft: #132036;
|
|
@@ -23,10 +40,6 @@
|
|
|
23
40
|
--color-warn: #d29922;
|
|
24
41
|
--color-bad: #f85149;
|
|
25
42
|
--color-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 16px rgba(0, 0, 0, 0.45);
|
|
26
|
-
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
27
|
-
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
28
|
-
--maxw: 1200px; /* reading width, for PROSE pages */
|
|
29
|
-
--maxw-wide: 100%; /* instrument width, for workbench pages */
|
|
30
43
|
color-scheme: dark;
|
|
31
44
|
}
|
|
32
45
|
|
|
@@ -38,22 +51,73 @@
|
|
|
38
51
|
--color-border: #d0d7de;
|
|
39
52
|
--color-fg: #1f2328;
|
|
40
53
|
--color-fg-subtle: #57606a;
|
|
41
|
-
--color-fg-faint: #
|
|
54
|
+
--color-fg-faint: #656d77;
|
|
42
55
|
--color-accent: #0969da;
|
|
43
56
|
--color-accent-fg: #ffffff;
|
|
44
57
|
--color-accent-soft: #ddf4ff;
|
|
45
|
-
--color-accent-2: #
|
|
58
|
+
--color-accent-2: #0a7886;
|
|
46
59
|
--color-magenta: #bf3989;
|
|
47
60
|
--color-good: #1a7f37;
|
|
48
|
-
--color-warn: #
|
|
61
|
+
--color-warn: #946300;
|
|
49
62
|
--color-bad: #cf222e;
|
|
50
63
|
--color-shadow: 0 1px 2px rgba(31, 35, 40, 0.06), 0 4px 10px rgba(31, 35, 40, 0.04);
|
|
51
64
|
}
|
|
52
65
|
|
|
66
|
+
/* Theme-independent tokens. A product reads them (`var(--rail-w)`) instead of writing the numbers again. */
|
|
67
|
+
:root {
|
|
68
|
+
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
69
|
+
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
70
|
+
/* type scale */
|
|
71
|
+
--text-xs: 0.74rem;
|
|
72
|
+
--text-sm: 0.84rem;
|
|
73
|
+
--text-md: 0.92rem;
|
|
74
|
+
--text-base: 0.98rem;
|
|
75
|
+
--text-lg: 1.08rem;
|
|
76
|
+
--text-xl: 1.3rem;
|
|
77
|
+
--text-2xl: 1.7rem;
|
|
78
|
+
/* spacing */
|
|
79
|
+
--space-1: 0.25rem;
|
|
80
|
+
--space-2: 0.5rem;
|
|
81
|
+
--space-3: 0.75rem;
|
|
82
|
+
--space-4: 1rem;
|
|
83
|
+
--space-5: 1.5rem;
|
|
84
|
+
--space-6: 2.25rem;
|
|
85
|
+
/* radii */
|
|
86
|
+
--radius-sm: 6px;
|
|
87
|
+
--radius-md: 8px;
|
|
88
|
+
--radius-lg: 10px;
|
|
89
|
+
--radius-pill: 999px;
|
|
90
|
+
/* layout */
|
|
91
|
+
--maxw: 1200px; /* the document width (ADR-0017 s1) */
|
|
92
|
+
--maxw-wide: 100%; /* the workbench and surface width (ADR-0071 rule 2) */
|
|
93
|
+
--measure: 70ch; /* the narrow column (.measure) and the lede */
|
|
94
|
+
--measure-text: 78ch; /* the longest line of a text block inside a document */
|
|
95
|
+
--header-h: 56px;
|
|
96
|
+
--rail-w: clamp(248px, 19vw, 340px);
|
|
97
|
+
--fade: 28px; /* the faded end of a scrolling row (lib/overflow.ts reveals an item this far inside) */
|
|
98
|
+
/* icons: lucide's svg.lucide is sized by its context, so a product never passes a size */
|
|
99
|
+
--icon-sm: 14px;
|
|
100
|
+
--icon-md: 16px;
|
|
101
|
+
--icon-lg: 18px;
|
|
102
|
+
/* z-order */
|
|
103
|
+
--z-header: 50;
|
|
104
|
+
--z-focus: 100;
|
|
105
|
+
--z-modal: 1000;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* == 2 base ===================================================================================================== */
|
|
109
|
+
|
|
53
110
|
* { box-sizing: border-box; }
|
|
54
111
|
/* Known shell defect 1 (fixed 0.7.0): `height: 100%` with `overflow-x: hidden` made html and body scroll containers
|
|
55
112
|
pinned to the viewport, so a tall page could not scroll by script or anchor. Content-height documents. */
|
|
56
113
|
html, body, #root { height: auto; min-height: 100%; }
|
|
114
|
+
/* The contained layout: a `nowrap` row sizes its container to its intrinsic width unless every ancestor may shrink;
|
|
115
|
+
the document never scrolls sideways (measured on ChargeCascade: scrollWidth 1817 on a 1600 viewport).
|
|
116
|
+
`clip`, not `hidden` (known shell defect 26, 0.8.0): `overflow-x: hidden` on body computes its overflow-y to auto,
|
|
117
|
+
so body became a scroll container that never scrolls, and nothing in a scrolling document could stick to the
|
|
118
|
+
viewport: not the site header, not the vertical sub-tab list (found by G12 at 768 px). `hidden` stays as the
|
|
119
|
+
fallback for a browser without `clip`. */
|
|
120
|
+
html, body { overflow-x: hidden; overflow-x: clip; }
|
|
57
121
|
/* Known shell defect 2 (fixed 0.7.0): any author `display` un-hid a `[hidden]` panel. */
|
|
58
122
|
[hidden] { display: none !important; }
|
|
59
123
|
body {
|
|
@@ -70,168 +134,272 @@ a:hover { text-decoration: underline; }
|
|
|
70
134
|
button { font: inherit; cursor: pointer; color: inherit; }
|
|
71
135
|
h1, h2, h3, h4 { line-height: 1.2; font-weight: 650; letter-spacing: -0.01em; }
|
|
72
136
|
code, kbd { font-family: var(--font-mono); }
|
|
137
|
+
:where(a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])):focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; border-radius: 4px; }
|
|
138
|
+
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
|
|
73
139
|
|
|
74
|
-
|
|
75
|
-
.app-shell { min-height: 100vh; display: flex; flex-direction: column; background: var(--color-bg); color: var(--color-fg); }
|
|
76
|
-
.container { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: 1.5rem; }
|
|
77
|
-
.page { flex: 1 1 auto; width: 100%; }
|
|
78
|
-
.page-body { width: 100%; max-width: var(--maxw); margin-inline: auto; padding: 2.25rem 1.5rem 3rem; }
|
|
79
|
-
/* A WORKBENCH is not prose. Capping an instrument at a 1200px reading measure wastes every pixel beyond
|
|
80
|
-
it, which is why the App surfaces across the line render their visualization as a thumbnail on a wide
|
|
81
|
-
display. Prose pages keep the reading width; the App route opts into the full viewport. */
|
|
82
|
-
.page-body.wide { max-width: var(--maxw-wide); padding-inline: 1.25rem; }
|
|
140
|
+
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
|
|
83
141
|
.muted { color: var(--color-fg-subtle); }
|
|
84
142
|
.faint { color: var(--color-fg-faint); }
|
|
85
143
|
.mono { font-family: var(--font-mono); font-size: 0.9em; }
|
|
86
|
-
.small { font-size:
|
|
87
|
-
.
|
|
88
|
-
.
|
|
144
|
+
.small { font-size: var(--text-sm); }
|
|
145
|
+
.container { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--space-5); }
|
|
146
|
+
.card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 1.25rem 1.5rem; box-shadow: var(--color-shadow); }
|
|
147
|
+
.badge { display: inline-flex; align-items: center; gap: 0.35rem; font-size: 0.78rem; padding: 0.15rem 0.55rem; border-radius: var(--radius-pill); border: 1px solid var(--color-border); background: var(--color-surface-2); color: var(--color-fg-subtle); white-space: nowrap; }
|
|
89
148
|
.badge.live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
|
|
90
149
|
.badge.precomputed, .badge.accent { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
|
|
91
150
|
.badge.warn { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
|
|
92
151
|
|
|
93
|
-
/*
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
152
|
+
/* == 3 frame ==================================================================================================== */
|
|
153
|
+
|
|
154
|
+
/* Three modes. Default: the document scrolls. `fixed` (ShellConfig.fixed or fixedRoutes): the route is the viewport.
|
|
155
|
+
`contain` (the template's configuration): every route is the viewport; a workbench or a surface fills it, a
|
|
156
|
+
document scrolls inside it, so the header and the footer stay in view (ADR-0071 rule 1, amended 2026-10-04). */
|
|
157
|
+
.app-shell { min-height: 100vh; display: flex; flex-direction: column; background: var(--color-bg); color: var(--color-fg); }
|
|
158
|
+
.page { flex: 1 1 auto; width: 100%; }
|
|
159
|
+
.page:focus { outline: none; }
|
|
160
|
+
|
|
161
|
+
/* The skip link: the first stop of the keyboard, visible only when focused. */
|
|
162
|
+
.skip-link { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
|
|
163
|
+
.skip-link:focus { position: fixed; top: var(--space-2); left: var(--space-2); z-index: var(--z-modal); width: auto; height: auto; margin: 0; padding: 0.4rem 0.8rem; clip: auto; overflow: visible; background: var(--color-surface); color: var(--color-accent); border: 1px solid var(--color-accent); border-radius: var(--radius-md); }
|
|
164
|
+
|
|
165
|
+
/* Header: brand, the route row, icon links, language and theme on ONE row at every width. */
|
|
166
|
+
.site-header { position: sticky; top: 0; z-index: var(--z-header); border-bottom: 1px solid var(--color-border); background: color-mix(in oklab, var(--color-bg) 82%, transparent); backdrop-filter: blur(8px); }
|
|
167
|
+
.header-inner { max-width: var(--maxw); margin-inline: auto; height: var(--header-h); padding-inline: var(--space-5); display: flex; align-items: center; gap: var(--space-4); }
|
|
168
|
+
.brand { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: 700; letter-spacing: -0.02em; color: var(--color-fg); flex: none; }
|
|
97
169
|
.brand:hover { text-decoration: none; }
|
|
98
170
|
.brand .brand-mark { color: var(--color-accent); display: inline-flex; flex: none; }
|
|
99
|
-
.
|
|
100
|
-
.
|
|
101
|
-
.main-nav .nav-link { flex: none; }
|
|
102
|
-
.brand, .header-actions { flex: none; }
|
|
103
|
-
.nav-link { padding: 0.4rem 0.7rem; border-radius: 6px; font-size: 0.9rem; color: var(--color-fg-subtle); transition: color 0.15s, background-color 0.15s; }
|
|
104
|
-
.nav-link:hover { text-decoration: none; color: var(--color-fg); }
|
|
105
|
-
.nav-link.active { color: var(--color-accent); background: var(--color-accent-soft); font-weight: 600; }
|
|
106
|
-
.header-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 0.15rem; }
|
|
107
|
-
.icon-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem; padding: 0.4rem 0.5rem; border-radius: 6px; background: transparent; border: none; color: var(--color-fg-subtle); opacity: 0.85; transition: opacity 0.15s, color 0.15s; }
|
|
171
|
+
.header-actions { margin-left: auto; display: inline-flex; align-items: center; gap: 0.15rem; flex: none; }
|
|
172
|
+
.icon-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.3rem; padding: 0.4rem 0.5rem; border-radius: var(--radius-sm); background: transparent; border: none; color: var(--color-fg-subtle); opacity: 0.85; transition: opacity 0.15s, color 0.15s; }
|
|
108
173
|
.icon-btn:hover { opacity: 1; color: var(--color-fg); text-decoration: none; }
|
|
109
174
|
.icon-btn svg { display: block; flex: none; }
|
|
110
175
|
.lang-code { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
|
|
111
176
|
.header-sep { width: 1px; height: 20px; margin-inline: 0.4rem; background: var(--color-border); }
|
|
112
177
|
|
|
113
|
-
/*
|
|
178
|
+
/* Footer: ADR-0016 s2, one compact line of provenance and honesty. */
|
|
114
179
|
.site-footer { border-top: 1px solid var(--color-border); margin-top: 3rem; background: var(--color-surface); }
|
|
115
|
-
.footer-inner { max-width: var(--maxw); margin-inline: auto; padding:
|
|
180
|
+
.footer-inner { max-width: var(--maxw); margin-inline: auto; padding: var(--space-5); display: flex; flex-direction: column; gap: 0.9rem; font-size: 0.85rem; color: var(--color-fg-faint); }
|
|
116
181
|
.footer-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
|
|
117
182
|
.footer-build { margin-left: auto; font-family: var(--font-mono); font-size: 0.72rem; color: var(--color-fg-faint); display: inline-flex; gap: 0.6rem; flex-wrap: wrap; }
|
|
118
183
|
|
|
119
|
-
/*
|
|
120
|
-
|
|
121
|
-
|
|
184
|
+
/* NO MAGIC CHROME NUMBER. A surface that fills the viewport lets flex distribute the height, never a guess at the
|
|
185
|
+
header and footer (measured on ChargeCascade: guess 150px, real 175px, so 25px of scroll and a 48px gap). */
|
|
186
|
+
.app-shell.fixed { height: 100dvh; min-height: 100dvh; overflow: hidden; }
|
|
187
|
+
.app-shell.fixed > .page { flex: 1 1 auto; min-height: 0; display: flex; }
|
|
188
|
+
/* A viewport-filling app carries no prose footer margin (measured on ChargeCascade as exactly 48px of dead space),
|
|
189
|
+
and its footer is compact: with provenance and a disclaimer it wrapped into 178px at 1600x900 and the instrument
|
|
190
|
+
fell from 56 to 42 percent of the viewport. */
|
|
191
|
+
.app-shell.fixed .site-footer { margin-top: 0; }
|
|
192
|
+
.app-shell.fixed .site-footer .footer-inner { padding: 0.45rem 1.5rem; gap: 0.4rem; font-size: 0.74rem; line-height: 1.3; }
|
|
193
|
+
.app-shell.fixed.contain > .page { display: flex; flex-direction: column; overflow: hidden; }
|
|
194
|
+
/* A document route scrolls inside the main container; a workbench or a surface fills it. */
|
|
195
|
+
.app-shell.fixed.contain > .page:has(> .page-body:not(.caos-wb):not(.caos-surface)) { display: block; overflow-y: auto; overscroll-behavior: contain; }
|
|
196
|
+
/* The chrome of a contained app spans the instrument's width with its inset, so at 2560 px the header and footer do
|
|
197
|
+
not float in a 1200 px column above a full-width workbench. */
|
|
198
|
+
.app-shell.fixed.contain .header-inner, .app-shell.fixed.contain .site-footer .footer-inner { max-width: var(--maxw-wide); padding-inline: var(--space-4); }
|
|
199
|
+
|
|
200
|
+
@media (max-width: 900px) {
|
|
201
|
+
/* A phone or a tablet stacks the rail over the instrument and lets the document scroll: the viewport rule is
|
|
202
|
+
measured at 1280x800 and above (ADR-0071 Verification). */
|
|
203
|
+
.app-shell.fixed.contain { height: auto; min-height: 100dvh; overflow: visible; }
|
|
204
|
+
/* Both forms of the rule above are released: the `:has()` form outranked a plain `> .page` and kept a document's
|
|
205
|
+
`.page` a scroll container that never scrolls, so nothing in it could be sticky (G12, 0.8.0). */
|
|
206
|
+
.app-shell.fixed.contain > .page, .app-shell.fixed.contain > .page:has(> .page-body:not(.caos-wb):not(.caos-surface)) { display: block; overflow: visible; }
|
|
207
|
+
}
|
|
122
208
|
@media (max-width: 760px) {
|
|
123
|
-
/* ADR-0071: route
|
|
124
|
-
|
|
209
|
+
/* ADR-0071: the route row shares the header row and owns the horizontal scroll; no second row above the
|
|
210
|
+
instrument. */
|
|
125
211
|
.header-inner { height: 52px; min-height: 0; flex-wrap: nowrap; gap: 0.3rem; padding-inline: 0.55rem; }
|
|
126
|
-
.brand
|
|
127
|
-
.
|
|
128
|
-
.header-actions
|
|
129
|
-
.header-actions .icon-btn { padding: 0.25rem; }
|
|
212
|
+
.brand { gap: var(--space-1); font-size: 0.8rem; white-space: nowrap; }
|
|
213
|
+
.header-actions { margin-left: 0; gap: 0; white-space: nowrap; }
|
|
214
|
+
.header-actions .icon-btn { padding: var(--space-1); }
|
|
130
215
|
.header-sep { margin-inline: 0.15rem; }
|
|
131
|
-
|
|
132
|
-
.
|
|
133
|
-
.
|
|
216
|
+
/* The phone footer of a contained surface stays one row and says that it scrolls (useOverflowFade). */
|
|
217
|
+
.app-shell.fixed .site-footer .footer-inner { padding: 0.35rem 0.55rem; }
|
|
218
|
+
.app-shell.fixed .footer-meta { flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
|
|
219
|
+
.app-shell.fixed .footer-meta::-webkit-scrollbar { display: none; }
|
|
220
|
+
.app-shell.fixed .footer-meta > * { flex: none; }
|
|
134
221
|
}
|
|
135
222
|
@media (max-width: 480px) {
|
|
223
|
+
/* The route row needs the room on every phone: on Linux fonts "Implementation" is about 100 px, and the row was
|
|
224
|
+
about 90 px at 320 px. The brand keeps its mark and its accessible name; the toggle keeps its icon and label. */
|
|
136
225
|
.brand span:last-child { display: none; }
|
|
137
|
-
/* The route row needs the room on every phone: on Linux fonts "Implementation" is about 100 px, and the row was about
|
|
138
|
-
90 px at 320 px and narrower than the link at 390 px, so a route could not be shown whole (shell CI and its gate
|
|
139
|
-
self-test, 2026-10-05). The brand keeps its mark and its accessible name; the toggle keeps its icon and its label. */
|
|
140
226
|
.header-sep, .lang-code { display: none; }
|
|
141
227
|
.header-actions .icon-btn { padding: 0.2rem; }
|
|
142
228
|
}
|
|
143
|
-
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
|
|
144
229
|
|
|
145
|
-
/*
|
|
146
|
-
|
|
230
|
+
/* == 4 routes =================================================================================================== */
|
|
231
|
+
|
|
232
|
+
/* Document: a centred reading width (ADR-0017 s1). The width is defined HERE ONLY: a later unscoped `.page-body`
|
|
233
|
+
rule once removed the 1200px cap from every product (test/layout-primitives.test.ts guards it). */
|
|
234
|
+
.page-body { width: 100%; max-width: var(--maxw); margin-inline: auto; padding: 2.25rem 1.5rem 3rem; min-width: 0; }
|
|
235
|
+
/* A WORKBENCH or a SURFACE is not prose: capping an instrument at the reading width wastes every pixel beyond it. */
|
|
236
|
+
.page-body.wide { max-width: var(--maxw-wide); padding-inline: 1.25rem; }
|
|
237
|
+
.app-shell.fixed .page-body.wide { flex: 1 1 auto; min-height: 0; padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
238
|
+
|
|
239
|
+
/* Workbench (WorkbenchLayout): a sized rail beside the instrument, on the full viewport. */
|
|
240
|
+
.caos-wb { display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr); gap: 0.9rem; align-items: stretch; min-width: 0; padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
241
|
+
.page-body.wide.caos-wb { padding-inline: var(--space-4); }
|
|
242
|
+
.caos-wb > * { min-width: 0; }
|
|
243
|
+
.app-shell.fixed.contain > .page > .caos-wb { flex: 1 1 auto; min-height: 0; }
|
|
244
|
+
|
|
245
|
+
/* Surface (SurfacePage): a tab App that fills the viewport; its head and tab row hold their height and the open
|
|
246
|
+
panel scrolls. The containment 15 to 19 products wrote for themselves (audit 2026-10-07, section 3). */
|
|
247
|
+
.caos-surface { display: flex; flex-direction: column; min-width: 0; min-height: 0; gap: var(--space-3); }
|
|
248
|
+
.page-body.wide.caos-surface { padding-inline: var(--space-4); }
|
|
249
|
+
.app-shell.fixed.contain > .page > .caos-surface { flex: 1 1 auto; min-height: 0; }
|
|
250
|
+
.caos-surface-head { flex: none; display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2) var(--space-4); min-width: 0; }
|
|
251
|
+
.caos-surface-heading { min-width: 0; }
|
|
252
|
+
.caos-surface-title { margin: 0; font-size: var(--text-xl); }
|
|
253
|
+
.caos-surface-actions { display: inline-flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
|
|
254
|
+
.caos-surface-lede { margin: 0; color: var(--color-fg-subtle); font-size: var(--text-md); max-width: var(--measure-text); }
|
|
255
|
+
.caos-surface-body { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; flex-direction: column; }
|
|
256
|
+
.caos-surface-body > .tabs { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
|
|
257
|
+
.caos-surface-body > .tabs > .tabpanel:not([hidden]) { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; gap: 0.6rem; }
|
|
258
|
+
@media (max-width: 900px) {
|
|
259
|
+
.caos-wb { grid-template-columns: minmax(0, 1fr); }
|
|
260
|
+
.caos-surface-body > .tabs > .tabpanel:not([hidden]) { overflow: visible; }
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* == 5 navigation =============================================================================================== */
|
|
264
|
+
|
|
265
|
+
/* Every row of links or tabs is ONE line that scrolls when it does not fit (ADR-0071 rule 4) and never shrinks in a
|
|
266
|
+
flex column (known shell defect 16, generalised: 16 to 24 products had to say so themselves). Its scrollbar is
|
|
267
|
+
hidden; wheel, trackpad, drag and keyboard still scroll it, and a hidden end fades (known shell defect 11). */
|
|
268
|
+
.main-nav { display: flex; align-items: center; gap: 0.15rem; flex: 1 1 auto; min-width: 0; overflow-x: auto; overflow-y: hidden; white-space: nowrap; scrollbar-width: none; }
|
|
269
|
+
.main-nav::-webkit-scrollbar { display: none; }
|
|
270
|
+
.main-nav .nav-link { flex: none; }
|
|
271
|
+
.nav-link { padding: 0.4rem 0.7rem; border-radius: var(--radius-sm); font-size: 0.9rem; color: var(--color-fg-subtle); transition: color 0.15s, background-color 0.15s; }
|
|
272
|
+
.nav-link:hover { text-decoration: none; color: var(--color-fg); }
|
|
273
|
+
.nav-link.active { color: var(--color-accent); background: var(--color-accent-soft); font-weight: 600; }
|
|
274
|
+
@media (max-width: 760px) {
|
|
275
|
+
.main-nav { flex: 1 1 0; padding: 2px 0; }
|
|
276
|
+
.main-nav .nav-link { padding: 0.3rem 0.3rem; font-size: 0.7rem; }
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Tabs: the first level. */
|
|
280
|
+
.tabs, .tabpanel, .subtabs, .subtabpanels, .subtabpanel { min-width: 0; max-width: 100%; }
|
|
281
|
+
.tablist { display: flex; gap: 0.35rem; flex: none; flex-wrap: nowrap !important; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; -ms-overflow-style: none; scroll-behavior: smooth; width: 100%; min-width: 0; max-width: 100%; padding-bottom: 0.4rem; margin-bottom: 0.9rem; border-bottom: 1px solid var(--color-border); }
|
|
282
|
+
.tablist::-webkit-scrollbar { display: none; }
|
|
283
|
+
.tablist .tab, .tablist button { flex: 0 0 auto; white-space: nowrap; }
|
|
284
|
+
.tab { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0.5rem 1rem; border: 1px solid transparent; border-radius: var(--radius-md); background: transparent; color: var(--color-fg-subtle); font-size: var(--text-md); font-weight: 550; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
285
|
+
.tab:hover { color: var(--color-fg); background: var(--color-surface-2); }
|
|
286
|
+
.tab.active { color: var(--color-accent); background: var(--color-accent-soft); border-color: color-mix(in oklab, var(--color-accent) 35%, transparent); font-weight: 650; }
|
|
287
|
+
.tabpanel:focus, .subtabpanel:focus { outline: none; }
|
|
288
|
+
|
|
289
|
+
/* Sub-tabs: the second level, lighter pills; or a vertical list beside the panel for a deep document. */
|
|
290
|
+
.subtabs { margin-block: 1rem; }
|
|
291
|
+
.subtablist { display: flex; gap: 0.3rem; flex: none; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; min-width: 0; margin-bottom: 1.1rem; }
|
|
292
|
+
.subtablist::-webkit-scrollbar { display: none; }
|
|
293
|
+
.subtablist .subtab { flex: none; white-space: nowrap; }
|
|
294
|
+
.subtab { display: inline-flex; align-items: center; gap: 0.3rem; padding: 0.32rem 0.8rem; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-fg-subtle); font-size: var(--text-sm); font-weight: 500; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
295
|
+
.subtab:hover { color: var(--color-fg); border-color: var(--color-fg-faint); }
|
|
296
|
+
.subtab.active { color: var(--color-accent); background: var(--color-accent-soft); border-color: color-mix(in oklab, var(--color-accent) 40%, transparent); font-weight: 600; }
|
|
297
|
+
/* `minmax(0, 1fr)`, NOT `1fr`: a bare `1fr` track is `minmax(auto, 1fr)`, so a wide table in a sub-tab panel sized
|
|
298
|
+
the whole grid to the table (measured on Porvenir's Datasets tab at 1280x800: 1380px on a 1280px viewport). */
|
|
299
|
+
.subtabs-vertical { display: grid; grid-template-columns: minmax(180px, 240px) minmax(0, 1fr); gap: 1.5rem; align-items: start; }
|
|
300
|
+
/* The vertical list stays in view while a long section scrolls (known shell defect 24, #55). Under contain the
|
|
301
|
+
header is outside the scroll container, so `top: 0`; in a scrolling document it clears the sticky header. */
|
|
302
|
+
.subtabs-vertical > .subtablist { flex-direction: column; overflow: visible; margin-bottom: 0; position: sticky; top: calc(var(--header-h) + var(--space-3)); align-self: start; }
|
|
303
|
+
.app-shell.fixed.contain .subtabs-vertical > .subtablist { top: var(--space-3); }
|
|
304
|
+
.subtabs-vertical .subtab { text-align: left; border-radius: var(--radius-md); white-space: normal; }
|
|
305
|
+
@media (max-width: 900px) {
|
|
306
|
+
/* Here the contained document scrolls as a whole under the sticky header: the list clears the header (G12 found
|
|
307
|
+
it hidden under the header at 768 px). */
|
|
308
|
+
.app-shell.fixed.contain .subtabs-vertical > .subtablist { top: calc(var(--header-h) + var(--space-3)); }
|
|
309
|
+
}
|
|
310
|
+
@media (max-width: 760px) {
|
|
311
|
+
.subtabs-vertical { grid-template-columns: minmax(0, 1fr); }
|
|
312
|
+
.subtabs-vertical > .subtablist { flex-direction: row; overflow-x: auto; position: static; }
|
|
313
|
+
.subtabs-vertical .subtab { white-space: nowrap; }
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Chip rows: a one-of-N choice on one row (ADR-0071 rule 4). */
|
|
317
|
+
.caos-chip-row { display: flex; flex-wrap: nowrap; gap: 0.35rem; overflow-x: auto; overflow-y: hidden; min-width: 0; scrollbar-width: none; padding-bottom: 2px; }
|
|
318
|
+
.caos-chip-row::-webkit-scrollbar { display: none; }
|
|
319
|
+
.caos-chip-row > * { flex: 0 0 auto; }
|
|
320
|
+
|
|
321
|
+
/* The rail's section row (WorkbenchLayout): one row like every other; a hidden end fades (found on CAOS_Fragmenta
|
|
322
|
+
and CAOS_Contraste, whose labels were shortened by hand to fit). */
|
|
323
|
+
.caos-wb-rail-sections { display: flex; flex-wrap: nowrap; gap: 0.3rem; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; flex: none; min-width: 0; }
|
|
324
|
+
.caos-wb-rail-sections::-webkit-scrollbar { display: none; }
|
|
325
|
+
.caos-wb-rail-sections > * { flex: none; }
|
|
326
|
+
|
|
327
|
+
/* A scrolling row says that it scrolls (known shell defect 11): the hidden end fades. */
|
|
328
|
+
:is(.main-nav, .tablist, .subtablist, .caos-chip-row, .caos-wb-rail-sections, .footer-meta)[data-fade-end="1"] { mask-image: linear-gradient(to right, #000 calc(100% - var(--fade)), transparent); }
|
|
329
|
+
:is(.main-nav, .tablist, .subtablist, .caos-chip-row, .caos-wb-rail-sections, .footer-meta)[data-fade-start="1"] { mask-image: linear-gradient(to left, #000 calc(100% - var(--fade)), transparent); }
|
|
330
|
+
:is(.main-nav, .tablist, .subtablist, .caos-chip-row, .caos-wb-rail-sections, .footer-meta)[data-fade-start="1"][data-fade-end="1"] { mask-image: linear-gradient(to right, transparent, #000 var(--fade), #000 calc(100% - var(--fade)), transparent); }
|
|
331
|
+
|
|
332
|
+
/* == 6 content ================================================================================================== */
|
|
333
|
+
|
|
334
|
+
/* Fill a document's width with grids, figure rows, definition grids and sub-tab lists, never with stretched text:
|
|
335
|
+
every text block keeps a readable line (--measure-text), a figure or a table takes the width (ADR-0017 s1). */
|
|
336
|
+
.prose { font-size: var(--text-base); }
|
|
147
337
|
.prose section { margin-block: 1.75rem; }
|
|
148
|
-
.
|
|
338
|
+
.prose h2 { font-size: var(--text-xl); margin-block: 1.4rem 0.6rem; }
|
|
339
|
+
.prose h3 { font-size: 1.06rem; margin-block: 1.1rem 0.4rem; }
|
|
340
|
+
.prose p { margin-block: 0.6rem; }
|
|
341
|
+
.prose ul, .prose ol { margin-block: 0.5rem; padding-left: 1.3rem; }
|
|
342
|
+
.prose li { margin-block: 0.35rem; }
|
|
343
|
+
.prose :where(p, li, blockquote, dd, .callout) { max-width: var(--measure-text); }
|
|
344
|
+
.prose :where(.equation-caption, .figure-caption, .fig-cap) { max-width: var(--measure-text); margin-inline: auto; }
|
|
345
|
+
.measure { max-width: var(--measure); }
|
|
346
|
+
.page-head { border-bottom: 1px solid var(--color-border); padding-bottom: 1rem; margin-bottom: 1.25rem; }
|
|
347
|
+
.page-head h1 { font-size: var(--text-2xl); margin: 0 0 0.4rem; }
|
|
348
|
+
.lede { color: var(--color-fg-subtle); font-size: var(--text-lg); margin: 0; max-width: var(--measure); }
|
|
349
|
+
.caos-doc-section { margin-block: 1.75rem; }
|
|
350
|
+
/* Wide content in a document scrolls inside its own box; the contained page never cuts it (G5). */
|
|
351
|
+
.prose table { display: block; max-width: 100%; overflow-x: auto; }
|
|
352
|
+
.prose pre { max-width: 100%; overflow-x: auto; }
|
|
353
|
+
.prose img, .prose svg, .prose video { max-width: 100%; height: auto; }
|
|
354
|
+
|
|
149
355
|
.fig-row { display: grid; grid-template-columns: 1.1fr 1fr; gap: 1.5rem; align-items: center; margin-block: 1.5rem; }
|
|
150
356
|
.fig-row.rev { grid-template-columns: 1fr 1.1fr; }
|
|
151
|
-
|
|
357
|
+
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-block: 1.5rem; }
|
|
152
358
|
.def-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin-block: 1.25rem; }
|
|
153
|
-
.def { background: var(--color-surface); border: 1px solid var(--color-border); border-radius:
|
|
359
|
+
.def { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.9rem 1.1rem; }
|
|
154
360
|
.def h4 { margin: 0 0 0.3rem; color: var(--color-accent); font-size: 0.95rem; }
|
|
155
361
|
.def p { margin: 0; font-size: 0.9rem; color: var(--color-fg-subtle); }
|
|
156
|
-
.assume { margin-block: 1rem; padding: 0.85rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius:
|
|
362
|
+
.assume { margin-block: 1rem; padding: 0.85rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
|
|
157
363
|
.assume-title { margin: 0 0 0.4rem; font-size: 0.76rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); }
|
|
158
364
|
.assume ul { margin: 0; padding-left: 1.2rem; color: var(--color-fg-subtle); }
|
|
159
365
|
.assume li { margin-block: 0.3rem; font-size: 0.92rem; }
|
|
160
|
-
.references { margin-top: 2.5rem; border-top: 1px solid var(--color-border); padding-top: 1rem; }
|
|
161
|
-
.reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
|
|
162
|
-
.reference-list li { margin-block: 0.5rem; }
|
|
163
|
-
.cite-inline { font-style: normal; font-size: 0.92em; color: var(--color-fg-subtle); }
|
|
164
|
-
.th-refs { margin-top: 1.25rem; padding-top: 0.6rem; border-top: 1px dashed var(--color-border); font-size: 0.85rem; color: var(--color-fg-subtle); }
|
|
165
|
-
.th-refs-label { font-weight: 650; color: var(--color-fg-faint); }
|
|
166
|
-
.prose h2 { font-size: 1.3rem; margin-block: 1.4rem 0.6rem; }
|
|
167
|
-
.prose h3 { font-size: 1.06rem; margin-block: 1.1rem 0.4rem; }
|
|
168
|
-
.prose p { margin-block: 0.6rem; }
|
|
169
|
-
.prose ul, .prose ol { margin-block: 0.5rem; padding-left: 1.3rem; }
|
|
170
|
-
.prose li { margin-block: 0.35rem; }
|
|
171
|
-
.page-head { border-bottom: 1px solid var(--color-border); padding-bottom: 1rem; margin-bottom: 1.25rem; }
|
|
172
|
-
.page-head h1 { font-size: 1.7rem; margin: 0 0 0.4rem; }
|
|
173
|
-
.lede { color: var(--color-fg-subtle); font-size: 1.08rem; margin: 0; max-width: 70ch; }
|
|
174
|
-
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-block: 1.5rem; }
|
|
175
|
-
@media (max-width: 760px) { .two-col { grid-template-columns: 1fr; } }
|
|
176
366
|
.tick-list, .cross-list { list-style: none; padding-left: 0; margin: 0.4rem 0 0; }
|
|
177
367
|
.tick-list li, .cross-list li { position: relative; padding-left: 1.5rem; margin-block: 0.5rem; }
|
|
178
368
|
.tick-list li::before { content: "✓"; position: absolute; left: 0; color: var(--color-good); font-weight: 700; }
|
|
179
369
|
.cross-list li::before { content: "✕"; position: absolute; left: 0; color: var(--color-fg-faint); font-weight: 700; }
|
|
370
|
+
@media (max-width: 900px) { .fig-row, .fig-row.rev { grid-template-columns: 1fr; } }
|
|
371
|
+
@media (max-width: 760px) { .two-col { grid-template-columns: 1fr; } }
|
|
180
372
|
|
|
181
|
-
/*
|
|
182
|
-
.callout { margin-block: 1rem; padding: 0.8rem 1.1rem; border-left: 3px solid var(--color-border); background: var(--color-surface-2); border-radius: 0
|
|
373
|
+
/* Callouts. */
|
|
374
|
+
.callout { margin-block: 1rem; padding: 0.8rem 1.1rem; border-left: 3px solid var(--color-border); background: var(--color-surface-2); border-radius: 0 var(--radius-md) var(--radius-md) 0; }
|
|
183
375
|
.callout-honest { border-left-color: var(--color-warn); }
|
|
184
376
|
.callout-strong { border-left-color: var(--color-accent); background: var(--color-accent-soft); }
|
|
185
377
|
.callout-note { border-left-color: var(--color-fg-faint); }
|
|
186
|
-
.callout-title { font-weight: 650; margin: 0 0 0.4rem; color: var(--color-fg); }
|
|
378
|
+
.callout-title { display: flex; align-items: center; gap: 0.4rem; font-weight: 650; margin: 0 0 0.4rem; color: var(--color-fg); }
|
|
187
379
|
.callout-body { color: var(--color-fg-subtle); }
|
|
188
380
|
.callout-body p:first-child { margin-top: 0; }
|
|
189
381
|
.callout-body p:last-child { margin-bottom: 0; }
|
|
382
|
+
.banner { padding: 0.6rem 0.9rem; border-radius: var(--radius-md); font-size: 0.85rem; margin-block: 0.6rem; border-left: 3px solid var(--color-border); background: var(--color-surface-2); }
|
|
383
|
+
.banner.warn { border-left-color: var(--color-warn); color: var(--color-warn); }
|
|
384
|
+
.banner.error { border-left-color: var(--color-bad); color: var(--color-bad); }
|
|
385
|
+
.hint { font-size: 0.8rem; color: var(--color-fg-faint); margin: 0; }
|
|
190
386
|
|
|
191
|
-
/*
|
|
192
|
-
.
|
|
193
|
-
/* SINGLE-LINE TAB BAR.
|
|
194
|
-
`flex-wrap: wrap` lets a 14-to-18 tab bar spill onto a second and third row, and every extra row is
|
|
195
|
-
vertical space taken from the instrument below it, permanently, on every render. A tab bar is
|
|
196
|
-
navigation chrome: it gets ONE row and scrolls horizontally when it does not fit.
|
|
197
|
-
Scrollbar is hidden but the row stays scrollable by wheel, trackpad, drag and keyboard. */
|
|
198
|
-
.tablist { flex-wrap: nowrap !important; overflow-x: auto; overflow-y: hidden;
|
|
199
|
-
scrollbar-width: none; -ms-overflow-style: none; padding-bottom: 0.4rem; margin-bottom: 0.9rem;
|
|
200
|
-
scroll-behavior: smooth; }
|
|
201
|
-
.tablist::-webkit-scrollbar { display: none; }
|
|
202
|
-
.tablist .tab, .tablist button { flex: 0 0 auto; white-space: nowrap; }
|
|
203
|
-
|
|
204
|
-
.tab { padding: 0.5rem 1rem; border: 1px solid transparent; border-radius: 8px; background: transparent; color: var(--color-fg-subtle); font-size: 0.92rem; font-weight: 550; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
205
|
-
.tab:hover { color: var(--color-fg); background: var(--color-surface-2); }
|
|
206
|
-
.tab.active { color: var(--color-accent); background: var(--color-accent-soft); border-color: color-mix(in oklab, var(--color-accent) 35%, transparent); font-weight: 650; }
|
|
207
|
-
.tabpanel:focus, .subtabpanel:focus { outline: none; }
|
|
208
|
-
.subtabs { margin-block: 1rem; }
|
|
209
|
-
.subtablist { display: flex; gap: 0.3rem; flex-wrap: wrap; margin-bottom: 1.1rem; }
|
|
210
|
-
.subtab { padding: 0.32rem 0.8rem; border: 1px solid var(--color-border); border-radius: 999px; background: var(--color-surface); color: var(--color-fg-subtle); font-size: 0.84rem; font-weight: 500; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
211
|
-
.subtab:hover { color: var(--color-fg); border-color: var(--color-fg-faint); }
|
|
212
|
-
.subtab.active { color: var(--color-accent); background: var(--color-accent-soft); border-color: color-mix(in oklab, var(--color-accent) 40%, transparent); font-weight: 600; }
|
|
213
|
-
/* `minmax(0, 1fr)`, NOT `1fr`. A bare `1fr` track is `minmax(auto, 1fr)`, and `auto` is the
|
|
214
|
-
min-content width of the panel, so a wide table in a sub-tab panel sized the whole grid to
|
|
215
|
-
the table and pushed the page past the viewport instead of scrolling inside its wrapper
|
|
216
|
-
(ADR-0071 rule 3). Measured on Porvenir's Datasets tab at 1280x800: the panel column
|
|
217
|
-
rendered 1380px wide on a 1280px viewport. */
|
|
218
|
-
.subtabs-vertical { display: grid; grid-template-columns: minmax(180px, 240px) minmax(0, 1fr); gap: 1.5rem; align-items: start; }
|
|
219
|
-
.subtabs-vertical .subtablist { flex-direction: column; margin-bottom: 0; }
|
|
220
|
-
.subtabs-vertical .subtab { text-align: left; border-radius: 8px; }
|
|
221
|
-
@media (max-width: 760px) { .subtabs-vertical { grid-template-columns: 1fr; } .subtabs-vertical .subtablist { flex-direction: row; } }
|
|
222
|
-
|
|
223
|
-
/* ── Equations / figures ── */
|
|
224
|
-
.equation { margin: 1rem 0; padding: 0.9rem 1rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 8px; overflow-x: auto; }
|
|
225
|
-
/* Wide content in a document scrolls inside its own box; the contained page never cuts it (G5). */
|
|
226
|
-
.prose table { display: block; max-width: 100%; overflow-x: auto; }
|
|
227
|
-
.prose pre { max-width: 100%; overflow-x: auto; }
|
|
228
|
-
.prose img, .prose svg, .prose video { max-width: 100%; height: auto; }
|
|
387
|
+
/* Equations and figures. */
|
|
388
|
+
.equation { margin: 1rem 0; padding: 0.9rem 1rem; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow-x: auto; }
|
|
229
389
|
.equation-caption { margin-top: 0.5rem; font-size: 0.82rem; color: var(--color-fg-faint); text-align: center; }
|
|
230
390
|
.katex { color: var(--color-fg); }
|
|
231
391
|
.figure { margin: 1.5rem 0; }
|
|
232
|
-
.figure-caption, .fig-cap { text-align: center; font-size:
|
|
392
|
+
.figure-caption, .fig-cap { text-align: center; font-size: var(--text-sm); color: var(--color-fg-faint); margin-top: 0.6rem; font-style: italic; }
|
|
233
393
|
|
|
234
|
-
/*
|
|
394
|
+
/* References: at the end of each section (ADR-0017 s4). */
|
|
395
|
+
.references { margin-top: 2.5rem; border-top: 1px solid var(--color-border); padding-top: 1rem; }
|
|
396
|
+
.reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
|
|
397
|
+
.reference-list li { margin-block: 0.5rem; }
|
|
398
|
+
.cite-inline { font-style: normal; font-size: 0.92em; color: var(--color-fg-subtle); }
|
|
399
|
+
.th-refs { margin-top: 1.25rem; padding-top: 0.6rem; border-top: 1px dashed var(--color-border); font-size: 0.85rem; color: var(--color-fg-subtle); }
|
|
400
|
+
.th-refs-label { font-weight: 650; color: var(--color-fg-faint); }
|
|
401
|
+
|
|
402
|
+
/* Theme-aware inline SVG diagrams (teaching figures). An <img> of an SVG cannot read these tokens. */
|
|
235
403
|
.fig-svg { width: 100%; max-width: 560px; height: auto; display: block; margin-inline: auto; }
|
|
236
404
|
.fig-svg.wide { max-width: 760px; }
|
|
237
405
|
.dg-axis { stroke: var(--color-fg-faint); stroke-width: 1.3; }
|
|
@@ -262,19 +430,40 @@ code, kbd { font-family: var(--font-mono); }
|
|
|
262
430
|
.dg-bar-2 { fill: var(--color-magenta); }
|
|
263
431
|
.dg-bar-label { fill: var(--color-fg-subtle); font: 11px var(--font-sans); }
|
|
264
432
|
|
|
265
|
-
/*
|
|
266
|
-
|
|
433
|
+
/* == 7 controls ================================================================================================= */
|
|
434
|
+
|
|
435
|
+
.btn { border: 1px solid var(--color-border); background: var(--color-surface-2); color: var(--color-fg); padding: 0.4rem 0.9rem; border-radius: var(--radius-md); font-weight: 600; font-size: 0.88rem; display: inline-flex; align-items: center; gap: 0.35rem; }
|
|
267
436
|
.btn:hover { border-color: var(--color-fg-faint); }
|
|
268
437
|
.btn.primary { background: var(--color-accent); color: var(--color-accent-fg); border-color: var(--color-accent); }
|
|
269
438
|
.btn:disabled { opacity: 0.5; cursor: default; }
|
|
270
|
-
.select { background: var(--color-surface-2); color: var(--color-fg); border: 1px solid var(--color-border); border-radius:
|
|
271
|
-
.hint { font-size: 0.8rem; color: var(--color-fg-faint); margin: 0; }
|
|
272
|
-
.banner { padding: 0.6rem 0.9rem; border-radius: 8px; font-size: 0.85rem; margin-block: 0.6rem; border-left: 3px solid var(--color-border); background: var(--color-surface-2); }
|
|
273
|
-
.banner.warn { border-left-color: var(--color-warn); color: var(--color-warn); }
|
|
274
|
-
.banner.error { border-left-color: var(--color-bad); color: var(--color-bad); }
|
|
439
|
+
.select { background: var(--color-surface-2); color: var(--color-fg); border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: 0.35rem 0.5rem; font-size: 0.85rem; }
|
|
275
440
|
.range { width: 100%; accent-color: var(--color-accent); }
|
|
441
|
+
/* Native controls follow the theme (S2; known shell defect 13). */
|
|
442
|
+
.app-shell select, .app-shell textarea, .app-shell input:not([type="range"]):not([type="checkbox"]):not([type="radio"]) { background: var(--color-surface-2); color: var(--color-fg); border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
|
|
443
|
+
.app-shell button { color: inherit; }
|
|
444
|
+
|
|
445
|
+
/* Chips: a one-of-N choice rendered as pills; `.on` is the selected state. */
|
|
446
|
+
.chip { display: inline-flex; align-items: center; gap: 0.35rem; background: var(--color-surface); border: 1px solid var(--color-border); color: var(--color-fg-subtle); border-radius: var(--radius-pill); padding: 0.3rem 0.72rem; font-size: 0.82rem; font-weight: 500; white-space: nowrap; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
447
|
+
.chip:hover:not(:disabled) { color: var(--color-fg); border-color: var(--color-fg-faint); }
|
|
448
|
+
.chip.on { background: var(--color-accent); color: var(--color-accent-fg); border-color: transparent; font-weight: 600; }
|
|
449
|
+
.chip:disabled { opacity: 0.45; cursor: default; }
|
|
450
|
+
|
|
451
|
+
/* Registered controls (Knob, ChipGroup). */
|
|
452
|
+
.caos-knob { display: flex; flex-direction: column; gap: var(--space-1); }
|
|
453
|
+
.caos-knob-head { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 0.8rem; color: var(--color-fg-subtle); }
|
|
454
|
+
.caos-knob-value { font-family: var(--font-mono); color: var(--color-fg); font-weight: 600; white-space: nowrap; }
|
|
455
|
+
.caos-chipgroup { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
|
|
456
|
+
.caos-chipgroup-label { font-size: 0.8rem; color: var(--color-fg-subtle); }
|
|
457
|
+
.caos-field { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
|
|
458
|
+
|
|
459
|
+
/* Icons: lucide renders `svg.lucide`; its size follows the place it is in, so products pass no size and every app
|
|
460
|
+
draws the same icon at the same size. An icon beside text takes the text's size. */
|
|
461
|
+
svg.lucide { flex: none; }
|
|
462
|
+
.icon-btn svg.lucide, .brand-mark svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
|
|
463
|
+
:is(.tab, .subtab, .chip, .btn, .nav-link, .badge, .callout-title, .caos-plot-head, .cs-chip, .caos-wb-rail-sections) svg.lucide { width: 1.15em; height: 1.15em; }
|
|
464
|
+
|
|
465
|
+
/* == 8 case selector ============================================================================================ */
|
|
276
466
|
|
|
277
|
-
/* ── CaseSelector v2 (shared source + case picker) ── */
|
|
278
467
|
.cs { display: flex; flex-direction: column; gap: 0.7rem; }
|
|
279
468
|
.cs-source { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
|
|
280
469
|
.cs-source-label { font-size: 0.78rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
|
|
@@ -283,166 +472,64 @@ code, kbd { font-family: var(--font-mono); }
|
|
|
283
472
|
.cs-group { display: flex; flex-direction: column; gap: 0.35rem; }
|
|
284
473
|
.cs-group-label { font-size: 0.76rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
|
|
285
474
|
.cs-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
|
|
286
|
-
.cs-chip { display: inline-flex; align-items: baseline; gap: 0.4rem; padding: 0.32rem 0.6rem; border: 1px solid var(--color-border); border-radius:
|
|
475
|
+
.cs-chip { display: inline-flex; align-items: baseline; gap: 0.4rem; padding: 0.32rem 0.6rem; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-fg-subtle); font-size: var(--text-sm); font-weight: 500; transition: color 0.15s, background-color 0.15s, border-color 0.15s; }
|
|
287
476
|
.cs-chip:hover:not(:disabled) { color: var(--color-fg); background: var(--color-surface-2); }
|
|
288
477
|
.cs-chip.on { color: var(--color-accent); background: var(--color-accent-soft); border-color: color-mix(in oklab, var(--color-accent) 40%, transparent); font-weight: 600; }
|
|
289
478
|
.cs-chip:disabled { opacity: 0.45; cursor: default; }
|
|
290
479
|
.cs-chip-id { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.76rem; font-weight: 600; opacity: 0.85; }
|
|
291
|
-
.cs-chip-name { }
|
|
292
480
|
.cs-kind { font-size: 0.62rem; font-weight: 700; line-height: 1; padding: 0.12rem 0.28rem; border-radius: 4px; border: 1px solid var(--color-border); color: var(--color-fg-faint); background: var(--color-surface-2); align-self: center; }
|
|
293
481
|
.cs-kind-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 40%, transparent); }
|
|
294
482
|
.cs-kind-uploaded { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 40%, transparent); }
|
|
295
483
|
.cs-modified { display: flex; align-items: center; gap: 0.35rem 0.5rem; flex-wrap: wrap; min-width: 0; }
|
|
296
484
|
.cs-modified .badge { white-space: normal; max-width: 100%; }
|
|
297
485
|
.cs-reset { border: none; background: transparent; color: var(--color-accent); font-size: 0.8rem; font-weight: 600; padding: 0.1rem 0.2rem; text-decoration: underline; text-underline-offset: 2px; }
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
the responsive navigation/layout contract and keeps route/content landmarks consistent. */
|
|
301
|
-
.caos-workbench-shell { min-height: 100vh; display: grid; grid-template-columns: 238px minmax(0, 1fr); }
|
|
302
|
-
.caos-workbench-sidebar { position: fixed; inset: 0 auto 0 0; z-index: 20; width: 238px; display: flex; flex-direction: column; padding: 1.25rem 0.875rem; border-right: 1px solid var(--color-border); background: var(--color-surface); }
|
|
303
|
-
.caos-workbench-sidebar nav { display: grid; gap: 0.25rem; }
|
|
304
|
-
.caos-workbench-sidebar nav a { display: flex; align-items: center; gap: 0.75rem; padding: 0.625rem 0.7rem; border: 1px solid transparent; border-radius: 0.7rem; color: var(--color-fg-subtle); font-size: 0.9rem; font-weight: 650; }
|
|
305
|
-
.caos-workbench-sidebar nav a:hover { color: var(--color-fg); background: var(--color-surface-2); text-decoration: none; }
|
|
306
|
-
.caos-workbench-sidebar nav a.active { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 24%, transparent); background: var(--color-accent-soft); }
|
|
307
|
-
.caos-workbench-main { grid-column: 2; min-width: 0; }
|
|
308
|
-
.caos-workbench-header { position: sticky; top: 0; z-index: 15; min-height: 64px; display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0 2rem; border-bottom: 1px solid var(--color-border); background: color-mix(in oklab, var(--color-bg) 88%, transparent); backdrop-filter: blur(12px); }
|
|
309
|
-
.caos-workbench-content { width: min(1540px, 100%); margin: 0 auto; padding: 2.25rem 2rem 4rem; }
|
|
310
|
-
|
|
311
|
-
@media (max-width: 760px) {
|
|
312
|
-
.caos-workbench-shell { display: block; padding-bottom: 66px; }
|
|
313
|
-
.caos-workbench-sidebar { inset: auto 0 0; width: auto; height: 62px; display: block; border: 0; border-top: 1px solid var(--color-border); padding: 5px 8px; }
|
|
314
|
-
.caos-workbench-sidebar > :not(nav) { display: none; }
|
|
315
|
-
.caos-workbench-sidebar nav { grid-template-columns: repeat(var(--caos-workbench-route-count, 5), minmax(0, 1fr)); }
|
|
316
|
-
.caos-workbench-sidebar nav a { display: grid; justify-items: center; gap: 2px; overflow: hidden; padding: 5px; font-size: 0.7rem; text-overflow: ellipsis; white-space: nowrap; }
|
|
317
|
-
.caos-workbench-main { min-width: 0; }
|
|
318
|
-
.caos-workbench-header { min-height: 58px; padding: 0 1rem; }
|
|
319
|
-
.caos-workbench-content { padding: 1.5rem 1rem 2.5rem; }
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
/* CONTAINED LAYOUT. A `nowrap` tab bar sizes its container to its intrinsic width unless every
|
|
323
|
-
ancestor is allowed to shrink: a flex/grid item defaults to `min-width: auto`. Without this, making
|
|
324
|
-
the tab bar a single scrollable row pushes the whole page wider than the viewport and the user has to
|
|
325
|
-
drag sideways to reach the right edge. Measured on ChargeCascade: scrollWidth 1817 on a 1600 viewport. */
|
|
326
|
-
html, body { overflow-x: hidden; }
|
|
327
|
-
/* `min-width: 0`, NOT `max-width: 100%`. Containment is about letting a box SHRINK below its
|
|
328
|
-
content; capping it at 100% does nothing for that and, because this rule comes after the
|
|
329
|
-
`.page-body` definition above, it silently OVERRODE `max-width: var(--maxw)` and removed the
|
|
330
|
-
1200px reading cap from every prose page in every product on this shell. Measured on Porvenir at
|
|
331
|
-
1600x900: doc routes rendered 1600px wide instead of 1200px centered, so body text ran the full
|
|
332
|
-
width of the display, which is the opposite of what ADR-0017 s1.1 specifies. The wide workbench
|
|
333
|
-
opt-in is `.page-body.wide`; a prose page must keep the measure. */
|
|
334
|
-
.page-body { min-width: 0; }
|
|
335
|
-
.tabs, .tabpanel, .subtabs, .subtabpanels, .subtabpanel { min-width: 0; max-width: 100%; }
|
|
336
|
-
.tablist { min-width: 0; max-width: 100%; width: 100%; }
|
|
337
|
-
|
|
338
|
-
/* NO MAGIC CHROME NUMBER. An app surface must not compute its height from a hardcoded guess at the
|
|
339
|
-
header and footer: the guess drifts the moment either changes, leaving either a dead gap above the
|
|
340
|
-
footer or a few pixels of scroll. Measured on ChargeCascade: guess 150px, real 175px (header 57 +
|
|
341
|
-
footer 70 + 48px body padding), so 25px of scroll and a 48px gap. Apps that fill the viewport add
|
|
342
|
-
`.app-shell.fixed` and let flex distribute the height. */
|
|
343
|
-
.app-shell.fixed { height: 100dvh; min-height: 100dvh; overflow: hidden; }
|
|
344
|
-
.app-shell.fixed > .page { flex: 1 1 auto; min-height: 0; display: flex; }
|
|
345
|
-
.app-shell.fixed .page-body.wide { flex: 1 1 auto; min-height: 0; padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
346
|
-
|
|
347
|
-
/* A viewport-filling app must not carry the prose footer margin: it becomes dead space between the
|
|
348
|
-
content and the chrome. Measured on ChargeCascade as exactly 48px (3rem). */
|
|
349
|
-
.app-shell.fixed .site-footer { margin-top: 0; }
|
|
350
|
-
/* On a contained surface the footer competes with the instrument for a fixed height. With a
|
|
351
|
-
product's provenance and disclaimer it wrapped into 178px at 1600x900 (five lines), and the
|
|
352
|
-
instrument fell from 56 to 42 percent of the viewport, under the ADR-0071 rule 8 floor. The
|
|
353
|
-
text stays (ADR-0016 s2: provenance and the honest disclaimer are the footer's job); it is set
|
|
354
|
-
compact, so it takes two to three lines, not five. */
|
|
355
|
-
.app-shell.fixed .site-footer .footer-inner { padding: 0.45rem 1.5rem; gap: 0.4rem; font-size: 0.74rem; line-height: 1.3; }
|
|
356
|
-
@media (max-width: 760px) {
|
|
357
|
-
/* A long, correctly attributed provenance must not consume the instrument.
|
|
358
|
-
Footer metadata remains accessible by horizontal scroll and keyboard focus. */
|
|
359
|
-
.app-shell.fixed .site-footer .footer-inner { padding: 0.35rem 0.55rem; }
|
|
360
|
-
.app-shell.fixed .footer-meta { flex-wrap: nowrap; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
|
|
361
|
-
.app-shell.fixed .footer-meta::-webkit-scrollbar { display: none; }
|
|
362
|
-
.app-shell.fixed .footer-meta > * { flex: none; }
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/* ADR-0058 diagram i18n. A hand-authored architecture SVG carries BOTH languages inside ONE file,
|
|
366
|
-
and the modal wrapper picks one. Two files would be two things to keep in step, and the one not
|
|
367
|
-
on screen is the one that goes stale. The rules are scoped to [data-arch-lang] so the short class
|
|
368
|
-
names cannot collide with an app's own styles. */
|
|
369
|
-
[data-arch-lang] .l-es { display: none; }
|
|
370
|
-
[data-arch-lang="es"] .l-en { display: none; }
|
|
371
|
-
[data-arch-lang="es"] .l-es { display: inline; }
|
|
372
|
-
.caos-architecture-diagram > svg { display: block; width: 100%; height: auto; max-width: none; }
|
|
373
|
-
|
|
374
|
-
/* The compact one-of-N case picker (ADR-0071 rule 7). Ten cases in four categories
|
|
375
|
-
cost a 308px chip block, 21% of a 2560x1440 viewport, and one row as a dropdown. */
|
|
486
|
+
/* The compact one-of-N case picker (ADR-0071 rule 7): ten cases in four categories cost a 308px chip block, 21% of a
|
|
487
|
+
2560x1440 viewport, and one row as a dropdown. */
|
|
376
488
|
.cs-select { width: 100%; max-width: 460px; }
|
|
377
489
|
|
|
378
|
-
/*
|
|
379
|
-
.caos-focus-shell { position: fixed; inset: 0; z-index: 100; display: grid; grid-template-columns: minmax(0,1fr) clamp(248px,19vw,340px); min-width: 0; height: 100dvh; background: var(--color-bg); color: var(--color-fg); }
|
|
380
|
-
.caos-focus-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--color-bg); }
|
|
381
|
-
.caos-focus-instrument { position: absolute; inset: 0; min-width: 0; min-height: 0; }
|
|
382
|
-
.caos-focus-label, .caos-focus-hud > div { background: color-mix(in oklab,var(--color-surface) 82%,transparent); backdrop-filter: blur(6px); border: 1px solid var(--color-border); border-radius: 6px; }
|
|
383
|
-
.caos-focus-label { position: absolute; top: 14px; left: 14px; max-width: min(46ch,calc(100% - 230px)); display: grid; gap: 4px; padding: 10px 12px; pointer-events: none; }
|
|
384
|
-
.caos-focus-label strong { font-size: 0.96rem; line-height: 1.2; }
|
|
385
|
-
.caos-focus-label span { font-size: 0.78rem; line-height: 1.4; color: var(--color-fg-subtle); }
|
|
386
|
-
.caos-focus-hud { position: absolute; left: 14px; top: 104px; display: grid; gap: 6px; pointer-events: none; }
|
|
387
|
-
.caos-focus-hud > div { display: grid; gap: 1px; padding: 7px 10px; min-width: 120px; }
|
|
388
|
-
.caos-focus-hud strong { font: 700 1rem var(--font-mono,monospace); }
|
|
389
|
-
.caos-focus-hud span { color: var(--color-fg-subtle); font-size: 0.61rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; }
|
|
390
|
-
.caos-focus-actions { position: absolute; top: 12px; right: 12px; display: flex; gap: 6px; align-items: center; padding: 4px; border: 1px solid var(--color-border); border-radius: 6px; background: color-mix(in oklab,var(--color-surface) 90%,transparent); backdrop-filter: blur(6px); }
|
|
391
|
-
.caos-focus-actions button { border: 0; border-radius: 4px; padding: 6px 9px; background: var(--color-surface-2); color: var(--color-fg); font-size: 0.75rem; font-weight: 700; cursor: pointer; }
|
|
392
|
-
.caos-focus-rail { min-width: 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; border-left: 1px solid var(--color-border); background: var(--color-surface); }
|
|
393
|
-
@media (max-width: 860px) {
|
|
394
|
-
.caos-focus-shell { grid-template-columns: minmax(0,1fr); grid-template-rows: minmax(0,54dvh) minmax(0,46dvh); }
|
|
395
|
-
.caos-focus-rail { border-left: 0; border-top: 1px solid var(--color-border); }
|
|
396
|
-
.caos-focus-label { max-width: calc(100% - 16px); top: 49px; left: 8px; padding: 6px 8px; }
|
|
397
|
-
.caos-focus-hud { top: auto; bottom: 8px; left: 8px; right: 8px; display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 4px; }
|
|
398
|
-
.caos-focus-hud > div { min-width: 0; padding: 5px; }
|
|
399
|
-
.caos-focus-hud strong { font-size: 0.72rem; white-space: nowrap; }
|
|
400
|
-
.caos-focus-hud span { font-size: 0.48rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
401
|
-
.caos-focus-actions { top: 7px; right: 7px; }
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* == Workbench primitives (0.7.0) ==============================================================================
|
|
405
|
-
The App route of every product: WorkbenchLayout, CaseWorkbench, VariantBar, LaneBadge, Readout, Gauge, Verdict,
|
|
406
|
-
PlotCard; and DocPage/DocSection for documentation routes. Owned here so products compose them and never
|
|
407
|
-
redefine them (ADR-0016 s9, ADR-0017, ADR-0071, as amended 2026-10-04). */
|
|
490
|
+
/* == 9 workbench ================================================================================================ */
|
|
408
491
|
|
|
409
|
-
/*
|
|
410
|
-
.
|
|
411
|
-
.
|
|
412
|
-
.chip.on { background: var(--color-accent); color: var(--color-accent-fg); border-color: transparent; font-weight: 600; }
|
|
413
|
-
.chip:disabled { opacity: 0.45; cursor: default; }
|
|
414
|
-
/* ONE row of chips (ADR-0071 rule 4): it scrolls horizontally instead of wrapping into more rows. */
|
|
415
|
-
.caos-chip-row { display: flex; flex-wrap: nowrap; gap: 0.35rem; overflow-x: auto; overflow-y: hidden; min-width: 0; scrollbar-width: none; padding-bottom: 2px; }
|
|
416
|
-
.caos-chip-row::-webkit-scrollbar { display: none; }
|
|
417
|
-
.caos-chip-row > * { flex: 0 0 auto; }
|
|
418
|
-
|
|
419
|
-
/* WorkbenchLayout: a sized rail beside the instrument, on the full viewport. */
|
|
420
|
-
.caos-wb { display: grid; grid-template-columns: clamp(248px, 19vw, 340px) minmax(0, 1fr); gap: 0.9rem; align-items: stretch; min-width: 0; padding-top: 0.75rem; padding-bottom: 0.75rem; }
|
|
421
|
-
.caos-wb > * { min-width: 0; }
|
|
422
|
-
.caos-wb-rail { display: flex; flex-direction: column; gap: 0.75rem; min-height: 0; overflow-y: auto; overflow-x: hidden; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 10px; padding: 0.85rem; }
|
|
423
|
-
.caos-wb-rail-sections { display: flex; flex-wrap: nowrap; gap: 0.3rem; overflow-x: auto; scrollbar-width: none; flex: 0 0 auto; }
|
|
424
|
-
.caos-wb-rail-sections::-webkit-scrollbar { display: none; }
|
|
492
|
+
/* The rail: sized, never scrolled when sections are used (ADR-0071 rule 6). */
|
|
493
|
+
.caos-wb-rail { display: flex; flex-direction: column; gap: var(--space-3); min-height: 0; overflow-y: auto; overflow-x: hidden; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.85rem; }
|
|
494
|
+
.caos-wb-rail-head { display: flex; flex-direction: column; gap: var(--space-3); padding-bottom: var(--space-3); border-bottom: 1px solid var(--color-border); }
|
|
425
495
|
.caos-wb-rail-panel { display: flex; flex-direction: column; gap: 0.8rem; min-height: 0; }
|
|
426
|
-
.caos-wb-rail label
|
|
496
|
+
.caos-wb-rail label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
|
|
427
497
|
.caos-wb-rail .select, .caos-wb-rail .range { width: 100%; }
|
|
498
|
+
/* The variants wrap in the rail instead of scrolling. */
|
|
499
|
+
.caos-wb-rail .caos-variant-bar { margin-bottom: 0; }
|
|
500
|
+
.caos-wb-rail .caos-chip-row { flex-wrap: wrap; overflow: visible; }
|
|
501
|
+
.caos-wb-rail .caos-variant-note { font-size: 0.8rem; }
|
|
428
502
|
.caos-wb-main { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
|
|
429
503
|
|
|
430
|
-
/* CaseWorkbench:
|
|
504
|
+
/* CaseWorkbench: ONE row of at most six question groups; the open panel takes the height the row leaves and owns its
|
|
505
|
+
scroll (failure class 4: drawings at zero or at a guessed size). */
|
|
431
506
|
.caos-cw { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1 1 auto; }
|
|
432
507
|
.caos-cw > .tabs { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
|
|
433
|
-
.caos-cw > .tabs > .
|
|
434
|
-
.caos-cw
|
|
508
|
+
.caos-cw > .tabs > .tablist { margin-bottom: 0.5rem; padding-bottom: var(--space-1); }
|
|
509
|
+
.caos-cw > .tabs > .tablist .tab { padding: 0.38rem 0.85rem; }
|
|
510
|
+
.caos-cw > .tabs > .tabpanel:not([hidden]) { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
|
|
511
|
+
.caos-cw-panel { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; flex: 1 1 auto; min-height: 0; }
|
|
435
512
|
.caos-cw-panel-head { display: flex; justify-content: flex-end; }
|
|
513
|
+
.caos-cw-panel > .subtabs { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-block: 0; }
|
|
514
|
+
.caos-cw-panel > .subtabs > .subtablist { margin-bottom: 0.45rem; }
|
|
515
|
+
.caos-cw-panel > .subtabs > .subtabpanels, .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
516
|
+
.caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { gap: 0.6rem; }
|
|
436
517
|
.caos-cw-context { max-width: 92ch; }
|
|
518
|
+
|
|
519
|
+
/* VariantBar. */
|
|
437
520
|
.caos-variant-bar { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.7rem; min-width: 0; }
|
|
438
521
|
.caos-variant-head { display: flex; align-items: center; gap: 0.4rem 0.6rem; flex-wrap: wrap; }
|
|
439
|
-
.caos-variant-title { font-size:
|
|
522
|
+
.caos-variant-title { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 600; }
|
|
440
523
|
.caos-variant-note { margin: 0; font-size: 0.88rem; color: var(--color-fg-subtle); font-style: italic; }
|
|
441
524
|
|
|
442
|
-
/* LaneBadge: which lane produced the values on screen. */
|
|
525
|
+
/* LaneBadge and provenance badges: which lane produced the values on screen, and on what data. */
|
|
526
|
+
.caos-badges { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
|
|
443
527
|
.caos-lane-live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
|
|
444
528
|
.caos-lane-replay { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
|
|
445
529
|
.caos-lane-offline { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
|
|
530
|
+
.caos-prov-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 45%, transparent); }
|
|
531
|
+
.caos-prov-synthetic { color: var(--color-magenta); border-color: color-mix(in oklab, var(--color-magenta) 45%, transparent); }
|
|
532
|
+
.caos-prov-published { color: var(--color-fg-subtle); }
|
|
446
533
|
|
|
447
534
|
/* Tones shared by readouts, gauges and verdicts. */
|
|
448
535
|
.tone-good { --tone: var(--color-good); }
|
|
@@ -453,9 +540,10 @@ html, body { overflow-x: hidden; }
|
|
|
453
540
|
|
|
454
541
|
/* Readout: labelled live values with units. */
|
|
455
542
|
.caos-readout { display: flex; flex-direction: column; gap: 0.35rem; }
|
|
456
|
-
.caos-readout-
|
|
457
|
-
.caos-readout
|
|
458
|
-
.caos-readout
|
|
543
|
+
.caos-readout-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
|
|
544
|
+
.caos-readout-title, .caos-gauge-title, .caos-verdict-title { margin: 0; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 600; }
|
|
545
|
+
.caos-readout dl { margin: 0; display: grid; gap: var(--space-1); }
|
|
546
|
+
.caos-readout-row { display: flex; justify-content: space-between; gap: var(--space-3); font-size: var(--text-sm); border-left: 3px solid var(--tone); padding-left: var(--space-2); }
|
|
459
547
|
.caos-readout-row dt { color: var(--color-fg-subtle); }
|
|
460
548
|
.caos-readout-row dd { margin: 0; text-align: right; }
|
|
461
549
|
.caos-readout-value { font-family: var(--font-mono); font-weight: 650; color: var(--color-fg); }
|
|
@@ -467,133 +555,123 @@ html, body { overflow-x: hidden; }
|
|
|
467
555
|
.caos-gauge-needle { position: absolute; top: 0; width: 3px; height: 100%; background: var(--color-fg); transform: translateX(-1px); }
|
|
468
556
|
.caos-gauge-scale { display: flex; justify-content: space-between; font-size: 0.72rem; color: var(--color-fg-faint); margin-top: 0.2rem; }
|
|
469
557
|
.caos-gauge-value { color: var(--color-fg); font-weight: 700; font-family: var(--font-mono); }
|
|
470
|
-
.caos-gauge-legend { display: flex; flex-wrap: wrap; gap:
|
|
471
|
-
.caos-gauge-
|
|
558
|
+
.caos-gauge-legend { display: flex; flex-wrap: wrap; gap: var(--space-2); font-size: 0.72rem; color: var(--color-fg-subtle); margin-top: var(--space-1); }
|
|
559
|
+
.caos-gauge-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: var(--space-1); background: var(--tone); }
|
|
472
560
|
|
|
473
561
|
/* Verdict: the current diagnosis, coloured by its tone. */
|
|
474
|
-
.caos-verdict { border: 1px solid var(--color-border); border-left: 4px solid var(--tone); border-radius:
|
|
562
|
+
.caos-verdict { border: 1px solid var(--color-border); border-left: 4px solid var(--tone); border-radius: var(--radius-md); padding: 0.7rem 0.85rem; background: var(--color-surface-2); }
|
|
475
563
|
.caos-verdict-text { margin: 0.2rem 0 0; font-weight: 650; color: var(--color-fg); }
|
|
476
564
|
.caos-verdict.compact { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.15rem 0.6rem; padding: 0.4rem 0.7rem; }
|
|
477
565
|
.caos-verdict.compact .caos-verdict-text { margin: 0; }
|
|
478
566
|
|
|
479
567
|
/* PlotCard: the frame every chart or table sits in. */
|
|
480
|
-
.caos-plot { margin: 0; background: var(--color-surface); border: 1px solid var(--color-border); border-radius:
|
|
481
|
-
.caos-plot-head { display: flex; justify-content: space-between; align-items: center; gap:
|
|
568
|
+
.caos-plot { margin: 0; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.45rem 0.6rem 0.4rem; min-width: 0; }
|
|
569
|
+
.caos-plot-head { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); margin-bottom: 0.2rem; font-style: normal; text-align: left; min-height: 1.5rem; }
|
|
482
570
|
.caos-plot-head .badge { font-size: 0.68rem; padding: 0.05rem 0.45rem; }
|
|
483
|
-
.caos-plot-title { font-size:
|
|
571
|
+
.caos-plot-title { font-size: var(--text-sm); color: var(--color-fg-subtle); font-weight: 600; }
|
|
484
572
|
.caos-plot-actions { display: inline-flex; gap: 0.3rem; }
|
|
485
573
|
.caos-plot-body { position: relative; min-width: 0; overflow-x: auto; }
|
|
486
574
|
.caos-plot-note { margin: 0.4rem 0 0; font-size: 0.78rem; color: var(--color-fg-faint); }
|
|
575
|
+
.caos-plot.fill { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
576
|
+
.caos-plot.fill > .caos-plot-body { flex: 1 1 0; min-height: 0; overflow: hidden; }
|
|
487
577
|
|
|
488
|
-
/*
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
inside it, so the header and footer stay in view and the document never scrolls (ADR-0071 rule 1). */
|
|
493
|
-
.app-shell.fixed.contain > .page { display: flex; flex-direction: column; overflow: hidden; }
|
|
494
|
-
.app-shell.fixed.contain > .page > .caos-wb { flex: 1 1 auto; min-height: 0; }
|
|
495
|
-
/* The chrome of a contained app spans the instrument's width with its inset, so at 2560 px the header and footer
|
|
496
|
-
do not float in a 1200 px column above a full-width workbench (found by the template capture review). */
|
|
497
|
-
.app-shell.fixed.contain .header-inner, .app-shell.fixed.contain .site-footer .footer-inner { max-width: var(--maxw-wide); padding-inline: 1rem; }
|
|
498
|
-
.app-shell.fixed.contain > .page:has(> .page-body:not(.caos-wb)) { display: block; overflow-y: auto; overscroll-behavior: contain; }
|
|
499
|
-
@media (max-width: 900px) {
|
|
500
|
-
/* A phone stacks the rail over the instrument and lets the document scroll: the viewport rule is measured at
|
|
501
|
-
1280x800 and above (ADR-0071 Verification). */
|
|
502
|
-
.caos-wb { grid-template-columns: minmax(0, 1fr); }
|
|
503
|
-
.app-shell.fixed.contain { height: auto; min-height: 100dvh; overflow: visible; }
|
|
504
|
-
.app-shell.fixed.contain > .page { display: block; overflow: visible; }
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/* == 0.7.0: closed known defects and the new primitives ======================================================== */
|
|
508
|
-
|
|
509
|
-
/* Native controls follow the theme (S2; known shell defect 13). */
|
|
510
|
-
.app-shell select, .app-shell textarea, .app-shell input:not([type="range"]):not([type="checkbox"]):not([type="radio"]) { background: var(--color-surface-2); color: var(--color-fg); border: 1px solid var(--color-border); border-radius: 6px; }
|
|
511
|
-
.app-shell button { color: inherit; }
|
|
512
|
-
.caos-arch-toggle { margin: 0 0 8px; font-size: 12px; padding: 5px 10px; color: var(--color-fg); background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: 6px; cursor: pointer; }
|
|
513
|
-
|
|
514
|
-
/* A scrolling row says that it scrolls (known shell defect 11): the hidden end fades. */
|
|
515
|
-
.main-nav[data-fade-end="1"], .tablist[data-fade-end="1"], .subtablist[data-fade-end="1"] { mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
|
|
516
|
-
.main-nav[data-fade-start="1"], .tablist[data-fade-start="1"], .subtablist[data-fade-start="1"] { mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent); }
|
|
517
|
-
.main-nav[data-fade-start="1"][data-fade-end="1"], .tablist[data-fade-start="1"][data-fade-end="1"], .subtablist[data-fade-start="1"][data-fade-end="1"] { mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent); }
|
|
518
|
-
.subtablist:not([aria-orientation="vertical"]) { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
|
|
519
|
-
.subtablist::-webkit-scrollbar { display: none; }
|
|
520
|
-
.subtablist .subtab { flex: none; white-space: nowrap; }
|
|
521
|
-
/* The phone footer of a contained surface stays one row (the instrument keeps the viewport) and says that it
|
|
522
|
-
scrolls: its hidden end fades, and a focused link is scrolled into view (useOverflowFade). */
|
|
523
|
-
.app-shell.fixed .footer-meta[data-fade-end="1"] { mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
|
|
524
|
-
.app-shell.fixed .footer-meta[data-fade-start="1"] { mask-image: linear-gradient(to left, #000 calc(100% - 28px), transparent); }
|
|
525
|
-
.app-shell.fixed .footer-meta[data-fade-start="1"][data-fade-end="1"] { mask-image: linear-gradient(to right, transparent, #000 28px, #000 calc(100% - 28px), transparent); }
|
|
526
|
-
|
|
527
|
-
/* A failed view (PanelBoundary): an inline message in its own frame, never a blank page. */
|
|
528
|
-
.caos-panel-error { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: baseline; padding: 0.7rem 0.9rem; border: 1px solid color-mix(in oklab, var(--color-bad) 45%, transparent); border-left: 4px solid var(--color-bad); border-radius: 8px; background: var(--color-surface-2); color: var(--color-fg); font-size: 0.86rem; }
|
|
529
|
-
.caos-panel-error code { flex-basis: 100%; font-size: 0.78rem; color: var(--color-fg-subtle); }
|
|
530
|
-
|
|
531
|
-
/* Lane and provenance badges. */
|
|
532
|
-
.caos-badges { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
|
|
533
|
-
.caos-prov-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 45%, transparent); }
|
|
534
|
-
.caos-prov-synthetic { color: var(--color-magenta); border-color: color-mix(in oklab, var(--color-magenta) 45%, transparent); }
|
|
535
|
-
.caos-prov-published { color: var(--color-fg-subtle); }
|
|
578
|
+
/* A row of views side by side. Every view of the row takes an equal share, a filling card included (known shell
|
|
579
|
+
defect 23, #54: `.caos-plot.fill` outranked the row's zero basis and took the row). */
|
|
580
|
+
.caos-views-row { display: flex; gap: 0.9rem; flex: 1 1 auto; min-height: 0; min-width: 0; }
|
|
581
|
+
.caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: 1 1 0; min-width: 0; }
|
|
536
582
|
|
|
537
583
|
/* Staleness: a view showing data for an earlier selection says so. */
|
|
538
584
|
.caos-stale .caos-plot-body > :not(.caos-stale-overlay), .caos-readout.caos-stale dl { opacity: 0.45; }
|
|
539
|
-
.caos-stale-overlay { position: absolute; inset: auto 0.5rem 0.5rem auto; padding: 0.25rem 0.55rem; border-radius:
|
|
585
|
+
.caos-stale-overlay { position: absolute; inset: auto 0.5rem 0.5rem auto; padding: 0.25rem 0.55rem; border-radius: var(--radius-sm); background: var(--color-surface-2); border: 1px solid var(--color-border); font-size: 0.76rem; color: var(--color-warn); }
|
|
540
586
|
.caos-stale-note { margin: 0.2rem 0 0; font-size: 0.76rem; color: var(--color-warn); }
|
|
541
|
-
.caos-readout-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; flex-wrap: wrap; }
|
|
542
587
|
|
|
543
|
-
/*
|
|
544
|
-
.caos-
|
|
545
|
-
|
|
546
|
-
.caos-
|
|
547
|
-
.caos-
|
|
548
|
-
.caos-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
.caos-cw > .tabs > .tabpanel:not([hidden]) { display: flex; flex-direction: column; }
|
|
555
|
-
.caos-cw-panel { flex: 1 1 auto; min-height: 0; }
|
|
556
|
-
/* In the workbench the group row is a compact header of the instrument, not a page section break. */
|
|
557
|
-
.caos-cw > .tabs > .tablist { margin-bottom: 0.5rem; padding-bottom: 0.25rem; }
|
|
558
|
-
.caos-cw > .tabs > .tablist .tab { padding: 0.38rem 0.85rem; }
|
|
559
|
-
/* The rail head: the case and variant pickers; the variants wrap in the rail instead of scrolling. */
|
|
560
|
-
.caos-wb-rail-head { display: flex; flex-direction: column; gap: 0.75rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--color-border); }
|
|
561
|
-
.caos-wb-rail .caos-variant-bar { margin-bottom: 0; }
|
|
562
|
-
.caos-wb-rail .caos-chip-row { flex-wrap: wrap; overflow: visible; }
|
|
563
|
-
.caos-wb-rail .caos-variant-note { font-size: 0.8rem; }
|
|
564
|
-
.caos-cw-panel > .subtabs { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-block: 0; }
|
|
565
|
-
.caos-cw-panel > .subtabs > .subtablist { margin-bottom: 0.45rem; }
|
|
566
|
-
/* Known shell defect 16: the group row and the sub-tab row are scroll containers (overflow-x auto), so their
|
|
567
|
-
automatic minimum height is zero, and in this column flex chain they shrank with a panel taller than the
|
|
568
|
-
instrument: the rows were clipped and the panel's top covered the sub-tabs (CAOS_Contraste, 2026-10-05). A tab
|
|
569
|
-
row keeps its height; the panel below it scrolls. */
|
|
570
|
-
.caos-cw > .tabs > .tablist, .caos-cw-panel > .subtabs > .subtablist { flex: none; }
|
|
571
|
-
.page-body.wide.caos-wb { padding-inline: 1rem; }
|
|
572
|
-
.caos-cw-panel > .subtabs > .subtabpanels, .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
573
|
-
.caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { gap: 0.6rem; }
|
|
574
|
-
.caos-views-row { display: flex; gap: 0.9rem; flex: 1 1 auto; min-height: 0; min-width: 0; }
|
|
575
|
-
.caos-views-row > * { flex: 1 1 0; min-width: 0; }
|
|
576
|
-
.caos-plot.fill { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
577
|
-
.caos-plot.fill > .caos-plot-body { flex: 1 1 0; min-height: 0; overflow: hidden; }
|
|
578
|
-
@media (max-width: 900px) {
|
|
579
|
-
.caos-views-row { flex-direction: column; }
|
|
580
|
-
.caos-plot.fill > .caos-plot-body { flex: none; height: clamp(260px, 48vh, 440px); }
|
|
581
|
-
}
|
|
588
|
+
/* Stage: the drawing surface of an instrument, sized by its container. */
|
|
589
|
+
.caos-stage { position: relative; width: 100%; height: 100%; min-width: 0; min-height: 0; }
|
|
590
|
+
/* BarChart: as wide as its box; a filling chart takes the box's height and scrolls rows that do not fit. */
|
|
591
|
+
.caos-bars { position: relative; width: 100%; min-width: 0; }
|
|
592
|
+
.caos-bars.fill { height: 100%; min-height: 0; overflow-y: auto; }
|
|
593
|
+
.caos-bars > svg { display: block; }
|
|
594
|
+
/* A view whose data is not there yet says so (and declares data-state="loading" for the gate). */
|
|
595
|
+
.caos-pending { margin: auto; padding: var(--space-5); color: var(--color-fg-faint); font-size: 0.86rem; text-align: center; }
|
|
596
|
+
/* A failed view (PanelBoundary): an inline message in its own frame, never a blank page. */
|
|
597
|
+
.caos-panel-error { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: baseline; padding: 0.7rem 0.9rem; border: 1px solid color-mix(in oklab, var(--color-bad) 45%, transparent); border-left: 4px solid var(--color-bad); border-radius: var(--radius-md); background: var(--color-surface-2); color: var(--color-fg); font-size: 0.86rem; }
|
|
598
|
+
.caos-panel-error code { flex-basis: 100%; font-size: 0.78rem; color: var(--color-fg-subtle); }
|
|
582
599
|
|
|
583
600
|
/* Tables in views and documents: tabular figures, compact rows, a header that stays in view while the body scrolls.
|
|
584
|
-
|
|
585
|
-
.caos-table { width: 100%; border-collapse: collapse; font-size:
|
|
601
|
+
A column of words reads left-aligned and wraps; numbers stay right-aligned. */
|
|
602
|
+
.caos-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums; color: var(--color-fg); }
|
|
586
603
|
.caos-table th, .caos-table td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--color-border); text-align: right; white-space: nowrap; }
|
|
587
604
|
.caos-table th:first-child, .caos-table td:first-child { text-align: left; }
|
|
588
|
-
/* A column of words (a description, an expected band) reads left-aligned and wraps; numbers stay right-aligned. */
|
|
589
605
|
.caos-table th.caos-col-text, .caos-table td.caos-col-text { text-align: left; white-space: normal; min-width: 16ch; }
|
|
590
606
|
.caos-table thead th { position: sticky; top: 0; background: var(--color-surface); color: var(--color-fg-subtle); font-weight: 600; border-bottom-color: var(--color-fg-faint); }
|
|
591
607
|
.caos-table tbody tr:hover { background: var(--color-surface-2); }
|
|
592
|
-
/* A phone wraps the cells instead of pushing the table past the page (found by the gate on the template, 390 px). */
|
|
593
|
-
@media (max-width: 600px) { .caos-table th, .caos-table td { white-space: normal; padding: 0.3rem 0.4rem; } }
|
|
594
608
|
|
|
595
|
-
|
|
596
|
-
|
|
609
|
+
@media (max-width: 900px) {
|
|
610
|
+
/* The views of a row stack; a filling view gets a fixed readable height instead of the panel's. */
|
|
611
|
+
.caos-views-row { flex-direction: column; }
|
|
612
|
+
.caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: none; }
|
|
613
|
+
.caos-plot.fill > .caos-plot-body { flex: none; height: clamp(260px, 48vh, 440px); }
|
|
614
|
+
}
|
|
615
|
+
@media (max-width: 760px) {
|
|
616
|
+
/* A phone wraps the cells instead of pushing the table past the page (found by the gate on the template). */
|
|
617
|
+
.caos-table th, .caos-table td { white-space: normal; padding: 0.3rem 0.4rem; }
|
|
618
|
+
}
|
|
597
619
|
|
|
598
|
-
/*
|
|
599
|
-
|
|
620
|
+
/* == 10 frames ================================================================================================== */
|
|
621
|
+
|
|
622
|
+
/* ADR-0070: the shell-owned, full-viewport scenario focus frame. */
|
|
623
|
+
.caos-focus-shell { position: fixed; inset: 0; z-index: var(--z-focus); display: grid; grid-template-columns: minmax(0,1fr) var(--rail-w); min-width: 0; height: 100dvh; background: var(--color-bg); color: var(--color-fg); }
|
|
624
|
+
.caos-focus-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--color-bg); }
|
|
625
|
+
.caos-focus-instrument { position: absolute; inset: 0; min-width: 0; min-height: 0; }
|
|
626
|
+
.caos-focus-label, .caos-focus-hud > div { background: color-mix(in oklab,var(--color-surface) 82%,transparent); backdrop-filter: blur(6px); border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
|
|
627
|
+
.caos-focus-label { position: absolute; top: 14px; left: 14px; max-width: min(46ch,calc(100% - 230px)); display: grid; gap: 4px; padding: 10px 12px; pointer-events: none; }
|
|
628
|
+
.caos-focus-label strong { font-size: 0.96rem; line-height: 1.2; }
|
|
629
|
+
.caos-focus-label span { font-size: 0.78rem; line-height: 1.4; color: var(--color-fg-subtle); }
|
|
630
|
+
.caos-focus-hud { position: absolute; left: 14px; top: 104px; display: grid; gap: 6px; pointer-events: none; }
|
|
631
|
+
.caos-focus-hud > div { display: grid; gap: 1px; padding: 7px 10px; min-width: 120px; }
|
|
632
|
+
.caos-focus-hud strong { font: 700 1rem var(--font-mono,monospace); }
|
|
633
|
+
.caos-focus-hud span { color: var(--color-fg-subtle); font-size: 0.61rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; }
|
|
634
|
+
.caos-focus-actions { position: absolute; top: 12px; right: 12px; display: flex; gap: 6px; align-items: center; padding: 4px; border: 1px solid var(--color-border); border-radius: var(--radius-sm); background: color-mix(in oklab,var(--color-surface) 90%,transparent); backdrop-filter: blur(6px); }
|
|
635
|
+
.caos-focus-actions button { border: 0; border-radius: 4px; padding: 6px 9px; background: var(--color-surface-2); color: var(--color-fg); font-size: 0.75rem; font-weight: 700; cursor: pointer; }
|
|
636
|
+
.caos-focus-rail { min-width: 0; min-height: 0; overflow-y: auto; overscroll-behavior: contain; border-left: 1px solid var(--color-border); background: var(--color-surface); }
|
|
637
|
+
@media (max-width: 900px) {
|
|
638
|
+
.caos-focus-shell { grid-template-columns: minmax(0,1fr); grid-template-rows: minmax(0,54dvh) minmax(0,46dvh); }
|
|
639
|
+
.caos-focus-rail { border-left: 0; border-top: 1px solid var(--color-border); }
|
|
640
|
+
.caos-focus-label { max-width: calc(100% - 16px); top: 49px; left: 8px; padding: 6px 8px; }
|
|
641
|
+
.caos-focus-hud { top: auto; bottom: 8px; left: 8px; right: 8px; display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 4px; }
|
|
642
|
+
.caos-focus-hud > div { min-width: 0; padding: 5px; }
|
|
643
|
+
.caos-focus-hud strong { font-size: 0.72rem; white-space: nowrap; }
|
|
644
|
+
.caos-focus-hud span { font-size: 0.48rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
645
|
+
.caos-focus-actions { top: 7px; right: 7px; }
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/* The authenticated console frame (WorkbenchShell): a sidebar on a desktop, a bottom bar on a phone. Products supply
|
|
649
|
+
their slots; the package owns the frame, the navigation semantics and the main landmark. */
|
|
650
|
+
.caos-workbench-shell { min-height: 100vh; display: grid; grid-template-columns: 238px minmax(0, 1fr); }
|
|
651
|
+
.caos-workbench-sidebar { position: fixed; inset: 0 auto 0 0; z-index: 20; width: 238px; display: flex; flex-direction: column; padding: 1.25rem 0.875rem; border-right: 1px solid var(--color-border); background: var(--color-surface); }
|
|
652
|
+
.caos-workbench-sidebar nav { display: grid; gap: var(--space-1); }
|
|
653
|
+
.caos-workbench-sidebar nav a { display: flex; align-items: center; gap: var(--space-3); padding: 0.625rem 0.7rem; border: 1px solid transparent; border-radius: 0.7rem; color: var(--color-fg-subtle); font-size: 0.9rem; font-weight: 650; }
|
|
654
|
+
.caos-workbench-sidebar nav a:hover { color: var(--color-fg); background: var(--color-surface-2); text-decoration: none; }
|
|
655
|
+
.caos-workbench-sidebar nav a.active { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 24%, transparent); background: var(--color-accent-soft); }
|
|
656
|
+
.caos-workbench-sidebar nav a svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
|
|
657
|
+
.caos-workbench-main { grid-column: 2; min-width: 0; }
|
|
658
|
+
.caos-workbench-header { position: sticky; top: 0; z-index: 15; min-height: 64px; display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); padding: 0 2rem; border-bottom: 1px solid var(--color-border); background: color-mix(in oklab, var(--color-bg) 88%, transparent); backdrop-filter: blur(12px); }
|
|
659
|
+
.caos-workbench-content { width: min(1540px, 100%); margin: 0 auto; padding: 2.25rem 2rem 4rem; }
|
|
660
|
+
@media (max-width: 760px) {
|
|
661
|
+
.caos-workbench-shell { display: block; padding-bottom: 66px; }
|
|
662
|
+
.caos-workbench-sidebar { inset: auto 0 0; width: auto; height: 62px; display: block; border: 0; border-top: 1px solid var(--color-border); padding: 5px 8px; }
|
|
663
|
+
.caos-workbench-sidebar > :not(nav) { display: none; }
|
|
664
|
+
.caos-workbench-sidebar nav { grid-template-columns: repeat(var(--caos-workbench-route-count, 5), minmax(0, 1fr)); }
|
|
665
|
+
.caos-workbench-sidebar nav a { display: grid; justify-items: center; gap: 2px; overflow: hidden; padding: 5px; font-size: 0.7rem; text-overflow: ellipsis; white-space: nowrap; }
|
|
666
|
+
.caos-workbench-main { min-width: 0; }
|
|
667
|
+
.caos-workbench-header { min-height: 58px; padding: 0 1rem; }
|
|
668
|
+
.caos-workbench-content { padding: 1.5rem 1rem 2.5rem; }
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
/* ADR-0058: the architecture modal. A hand-authored architecture SVG carries BOTH languages in ONE file and the
|
|
672
|
+
wrapper picks one; the rules are scoped to [data-arch-lang] so the short class names cannot collide. */
|
|
673
|
+
[data-arch-lang] .l-es { display: none; }
|
|
674
|
+
[data-arch-lang="es"] .l-en { display: none; }
|
|
675
|
+
[data-arch-lang="es"] .l-es { display: inline; }
|
|
676
|
+
.caos-architecture-diagram > svg { display: block; width: 100%; height: auto; max-width: none; }
|
|
677
|
+
.caos-arch-toggle { margin: 0 0 8px; font-size: 12px; padding: 5px 10px; color: var(--color-fg); background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-sm); cursor: pointer; }
|