@fasl-work/caos-app-shell 0.13.0 → 0.14.0

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/styles.css CHANGED
@@ -1,769 +1,829 @@
1
- @import "katex/dist/katex.min.css";
2
-
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 =================================================================================================== */
24
-
25
- :root,
26
- [data-theme="dark"] {
27
- --color-bg: #0d1117;
28
- --color-surface: #161b22;
29
- --color-surface-2: #1c2230;
30
- --color-border: #30363d;
31
- --color-fg: #c9d1d9;
32
- --color-fg-subtle: #9aa6b2;
33
- --color-fg-faint: #828b97;
34
- --color-accent: #58a6ff;
35
- --color-accent-fg: #0d1117;
36
- --color-accent-soft: #132036;
37
- --color-accent-2: #3fb1c8;
38
- --color-magenta: #f778ba;
39
- --color-good: #3fb950;
40
- --color-warn: #d29922;
41
- --color-bad: #f85149;
42
- --color-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 16px rgba(0, 0, 0, 0.45);
43
- color-scheme: dark;
44
- }
45
-
46
- [data-theme="light"] {
47
- color-scheme: light;
48
- --color-bg: #f6f8fa;
49
- --color-surface: #ffffff;
50
- --color-surface-2: #f0f3f6;
51
- --color-border: #d0d7de;
52
- --color-fg: #1f2328;
53
- --color-fg-subtle: #57606a;
54
- --color-fg-faint: #656d77;
55
- --color-accent: #0969da;
56
- --color-accent-fg: #ffffff;
57
- --color-accent-soft: #ddf4ff;
58
- --color-accent-2: #0a7886;
59
- --color-magenta: #b93785;
60
- --color-good: #197c36;
61
- --color-warn: #946300;
62
- --color-bad: #cf222e;
63
- --color-shadow: 0 1px 2px rgba(31, 35, 40, 0.06), 0 4px 10px rgba(31, 35, 40, 0.04);
64
- }
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) */
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
-
110
- * { box-sizing: border-box; }
111
- /* Known shell defect 1 (fixed 0.7.0): `height: 100%` with `overflow-x: hidden` made html and body scroll containers
112
- pinned to the viewport, so a tall page could not scroll by script or anchor. Content-height documents. */
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; }
121
- /* Known shell defect 2 (fixed 0.7.0): any author `display` un-hid a `[hidden]` panel. */
122
- [hidden] { display: none !important; }
123
- body {
124
- margin: 0;
125
- font-family: var(--font-sans);
126
- background-color: var(--color-bg);
127
- color: var(--color-fg);
128
- -webkit-font-smoothing: antialiased;
129
- -moz-osx-font-smoothing: grayscale;
130
- line-height: 1.55;
131
- }
132
- a { color: var(--color-accent); text-decoration: none; }
133
- a:hover { text-decoration: underline; }
134
- button { font: inherit; cursor: pointer; color: inherit; }
135
- h1, h2, h3, h4 { line-height: 1.2; font-weight: 650; letter-spacing: -0.01em; }
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; } }
139
-
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; }
141
- .muted { color: var(--color-fg-subtle); }
142
- .faint { color: var(--color-fg-faint); }
143
- .mono { font-family: var(--font-mono); font-size: 0.9em; }
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; }
148
- .badge.live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
149
- .badge.precomputed, .badge.accent { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
150
- .badge.warn { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
151
-
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; }
169
- .brand:hover { text-decoration: none; }
170
- .brand .brand-mark { color: var(--color-accent); display: inline-flex; flex: none; }
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; }
173
- .icon-btn:hover { opacity: 1; color: var(--color-fg); text-decoration: none; }
174
- .icon-btn svg { display: block; flex: none; }
175
- .lang-code { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
176
- .header-sep { width: 1px; height: 20px; margin-inline: 0.4rem; background: var(--color-border); }
177
-
178
- /* Footer: ADR-0016 s2, one compact line of provenance and honesty. */
179
- .site-footer { border-top: 1px solid var(--color-border); margin-top: 3rem; background: var(--color-surface); }
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); }
181
- .footer-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
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; }
183
-
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
- }
208
- @media (max-width: 760px) {
209
- /* ADR-0071: the route row shares the header row and owns the horizontal scroll; no second row above the
210
- instrument. */
211
- .header-inner { height: 52px; min-height: 0; flex-wrap: nowrap; gap: 0.3rem; padding-inline: 0.55rem; }
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); }
215
- .header-sep { margin-inline: 0.15rem; }
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; }
221
- }
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. */
225
- .brand span:last-child { display: none; }
226
- .header-sep, .lang-code { display: none; }
227
- .header-actions .icon-btn { padding: 0.2rem; }
228
- }
229
-
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
- /* A document fills the width of its column (shell 0.11.0, CAOS_APP_SHELL#96): text blocks, grids, figure rows and
335
- tables all take it. A page that reads as one prose column keeps its own max width and is centred (ADR-0017 s1);
336
- only the captions keep a measure, centred under their figure. */
337
- .prose { font-size: var(--text-base); }
338
- .prose section { margin-block: 1.75rem; }
339
- .prose h2 { font-size: var(--text-xl); margin-block: 1.4rem 0.6rem; }
340
- .prose h3 { font-size: 1.06rem; margin-block: 1.1rem 0.4rem; }
341
- .prose p { margin-block: 0.6rem; }
342
- .prose ul, .prose ol { margin-block: 0.5rem; padding-left: 1.3rem; }
343
- .prose li { margin-block: 0.35rem; }
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
- /* the lede of a page takes the full width of the document column (Felipe, 2026-10-13); only captions keep a measure */
349
- .lede { color: var(--color-fg-subtle); font-size: var(--text-lg); margin: 0; max-width: none; }
350
- .caos-doc-section { margin-block: 1.75rem; }
351
- /* The references of a page or open tab: one block at its end (ADR-0017 s4). */
352
- .caos-doc-references { margin-top: 2rem; padding-top: 0.4rem; border-top: 1px solid var(--color-border); }
353
- .caos-doc-reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
354
- .caos-doc-reference-list li { margin-block: 0.5rem; }
355
- /* Wide content in a document scrolls inside its own box; the contained page never cuts it (G5). */
356
- .prose table { display: block; max-width: 100%; overflow-x: auto; }
357
- .prose pre { max-width: 100%; overflow-x: auto; }
358
- .prose img, .prose svg, .prose video { max-width: 100%; height: auto; }
359
-
360
- .fig-row { display: grid; grid-template-columns: 1.1fr 1fr; gap: 1.5rem; align-items: center; margin-block: 1.5rem; }
361
- .fig-row.rev { grid-template-columns: 1fr 1.1fr; }
362
- .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-block: 1.5rem; }
363
- .def-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin-block: 1.25rem; }
364
- .def { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.9rem 1.1rem; }
365
- .def h4 { margin: 0 0 0.3rem; color: var(--color-accent); font-size: 0.95rem; }
366
- .def p { margin: 0; font-size: 0.9rem; color: var(--color-fg-subtle); }
367
- .assume { margin-block: 1rem; padding: 0.85rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
368
- .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); }
369
- .assume ul { margin: 0; padding-left: 1.2rem; color: var(--color-fg-subtle); }
370
- .assume li { margin-block: 0.3rem; font-size: 0.92rem; }
371
- .tick-list, .cross-list { list-style: none; padding-left: 0; margin: 0.4rem 0 0; }
372
- .tick-list li, .cross-list li { position: relative; padding-left: 1.5rem; margin-block: 0.5rem; }
373
- .tick-list li::before { content: "✓"; position: absolute; left: 0; color: var(--color-good); font-weight: 700; }
374
- .cross-list li::before { content: "✕"; position: absolute; left: 0; color: var(--color-fg-faint); font-weight: 700; }
375
- @media (max-width: 900px) { .fig-row, .fig-row.rev { grid-template-columns: 1fr; } }
376
- @media (max-width: 760px) { .two-col { grid-template-columns: 1fr; } }
377
-
378
- /* Callouts. */
379
- .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; }
380
- .callout-honest { border-left-color: var(--color-warn); }
381
- .callout-strong { border-left-color: var(--color-accent); background: var(--color-accent-soft); }
382
- .callout-note { border-left-color: var(--color-fg-faint); }
383
- .callout-title { display: flex; align-items: center; gap: 0.4rem; font-weight: 650; margin: 0 0 0.4rem; color: var(--color-fg); }
384
- .callout-body { color: var(--color-fg-subtle); }
385
- .callout-body p:first-child { margin-top: 0; }
386
- .callout-body p:last-child { margin-bottom: 0; }
387
- .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); }
388
- .banner.warn { border-left-color: var(--color-warn); color: var(--color-warn); }
389
- .banner.error { border-left-color: var(--color-bad); color: var(--color-bad); }
390
- .hint { font-size: 0.8rem; color: var(--color-fg-faint); margin: 0; }
391
-
392
- /* Equations and figures. */
393
- .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; }
394
- .equation-caption { margin-top: 0.5rem; font-size: 0.82rem; color: var(--color-fg-faint); text-align: center; }
395
- .caos-glossary { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 0.4rem 1.25rem; margin: 0.75rem 0; }
396
- .caos-glossary-item { display: flex; gap: 0.5rem; align-items: baseline; }
397
- .caos-glossary dt { flex: none; min-width: 3rem; font-weight: 600; }
398
- .caos-glossary dd { margin: 0; color: var(--color-fg); }
399
- .caos-stat-value { font-variant-numeric: tabular-nums; }
400
- .caos-stat-source { color: var(--color-fg-faint); font-size: var(--text-sm); }
401
- .caos-qa { margin: 0.9rem 0; }
402
- .caos-qa-question { font-weight: 600; margin-bottom: 0.25rem; }
403
- .caos-qa-answer > :first-child { margin-top: 0; }
404
- .katex { color: var(--color-fg); }
405
- .figure { margin: 1.5rem 0; }
406
- .figure-caption, .fig-cap { text-align: center; font-size: var(--text-sm); color: var(--color-fg-faint); margin-top: 0.6rem; font-style: italic; }
407
-
408
- /* References: at the end of each section (ADR-0017 s4). */
409
- .references { margin-top: 2.5rem; border-top: 1px solid var(--color-border); padding-top: 1rem; }
410
- .reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
411
- .reference-list li { margin-block: 0.5rem; }
412
- .cite-inline { font-style: normal; font-size: 0.92em; color: var(--color-fg-subtle); }
413
- .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); }
414
- .th-refs-label { font-weight: 650; color: var(--color-fg-faint); }
415
-
416
- /* Theme-aware inline SVG diagrams (teaching figures). An <img> of an SVG cannot read these tokens. */
417
- .fig-svg { width: 100%; max-width: 560px; height: auto; display: block; margin-inline: auto; }
418
- .fig-svg.wide { max-width: 760px; }
419
- .dg-axis { stroke: var(--color-fg-faint); stroke-width: 1.3; }
420
- .dg-axis-label { fill: var(--color-fg-subtle); font: 12px var(--font-sans); }
421
- .dg-tick { fill: var(--color-fg-subtle); font: 11px var(--font-mono); }
422
- .dg-grid { stroke: var(--color-border); stroke-width: 0.5; opacity: 0.6; }
423
- .dg-curve { fill: none; stroke: var(--color-accent); stroke-width: 2.2; stroke-linejoin: round; }
424
- .dg-curve-2 { fill: none; stroke: var(--color-magenta); stroke-width: 2; }
425
- .dg-curve-faint { fill: none; stroke: var(--color-fg-faint); stroke-width: 1.4; stroke-dasharray: 4 3; }
426
- .dg-asymptote { stroke: var(--color-bad); stroke-width: 1.4; stroke-dasharray: 4 4; }
427
- .dg-marker { stroke: var(--color-warn); stroke-width: 1.2; stroke-dasharray: 3 3; }
428
- .dg-marker-label { fill: var(--color-warn); font: 600 11px var(--font-mono); }
429
- .dg-note { fill: var(--color-fg-subtle); font: italic 11px var(--font-sans); }
430
- .dg-fill-accent { fill: color-mix(in oklab, var(--color-accent) 16%, transparent); stroke: var(--color-accent); stroke-width: 1; }
431
- .dg-fill-warn { fill: color-mix(in oklab, var(--color-warn) 16%, transparent); stroke: var(--color-warn); stroke-width: 1; }
432
- .dg-box { fill: var(--color-surface); stroke: var(--color-border); stroke-width: 1.3; }
433
- .dg-box.accent { stroke: var(--color-accent); fill: var(--color-accent-soft); }
434
- .dg-box.good { stroke: var(--color-good); }
435
- .dg-box-title { fill: var(--color-fg); font: 650 12px var(--font-sans); }
436
- .dg-box-title.accent { fill: var(--color-accent); }
437
- .dg-box-sub { fill: var(--color-fg-subtle); font: 10.5px var(--font-mono); }
438
- .dg-node { fill: var(--color-surface); stroke: var(--color-accent); stroke-width: 1.4; }
439
- .dg-node-label { fill: var(--color-fg); font: 600 12px var(--font-mono); }
440
- .dg-edge { stroke: var(--color-fg-faint); stroke-width: 1.4; fill: none; }
441
- .dg-edge-label { fill: var(--color-fg-subtle); font: 11px var(--font-mono); }
442
- .dg-arrowhead { fill: var(--color-fg-faint); }
443
- .dg-bar { fill: var(--color-accent); }
444
- .dg-bar-2 { fill: var(--color-magenta); }
445
- .dg-bar-label { fill: var(--color-fg-subtle); font: 11px var(--font-sans); }
446
-
447
- /* == 7 controls ================================================================================================= */
448
-
449
- .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; }
450
- .btn:hover { border-color: var(--color-fg-faint); }
451
- .btn.primary { background: var(--color-accent); color: var(--color-accent-fg); border-color: var(--color-accent); }
452
- .btn:disabled { opacity: 0.5; cursor: default; }
453
- .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; }
454
- .range { width: 100%; accent-color: var(--color-accent); }
455
- /* Native controls follow the theme (S2; known shell defect 13). */
456
- .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); }
457
- .app-shell button { color: inherit; }
458
-
459
- /* Chips: a one-of-N choice rendered as pills; `.on` is the selected state. */
460
- .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; }
461
- .chip:hover:not(:disabled) { color: var(--color-fg); border-color: var(--color-fg-faint); }
462
- .chip.on { background: var(--color-accent); color: var(--color-accent-fg); border-color: transparent; font-weight: 600; }
463
- /* the active chip keeps its colours under the pointer: the hover rule above outranks `.chip.on` and, until 0.9.4, wrote
464
- the text colour on the accent (3.04:1 in light, 1.64:1 in dark; known shell defect 33) */
465
- .chip.on:hover:not(:disabled) { color: var(--color-accent-fg); border-color: transparent; }
466
- .chip:disabled { opacity: 0.45; cursor: default; }
467
-
468
- /* Registered controls (Knob, ChipGroup). */
469
- .caos-knob { display: flex; flex-direction: column; gap: var(--space-1); }
470
- /* Chromium keeps a 2 px user-agent side margin on a range input: at width 100% it reached 2 px past a clipping card
471
- (a PlotCard body) and the gate's G5 failed at phone widths (CAOS_APP_SHELL#91). */
472
- .caos-knob input[type='range'] { margin-inline: 0; }
473
- .caos-knob-head { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 0.8rem; color: var(--color-fg-subtle); }
474
- .caos-knob-value { font-family: var(--font-mono); color: var(--color-fg); font-weight: 600; white-space: nowrap; }
475
- .caos-chipgroup { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
476
- .caos-chipgroup-label { font-size: 0.8rem; color: var(--color-fg-subtle); }
477
- .caos-field { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
478
-
479
- /* Icons: lucide renders `svg.lucide`; its size follows the place it is in, so products pass no size and every app
480
- draws the same icon at the same size. An icon beside text takes the text's size. */
481
- svg.lucide { flex: none; }
482
- .icon-btn svg.lucide, .brand-mark svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
483
- :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; }
484
-
485
- /* == 8 case selector ============================================================================================ */
486
-
487
- .cs { display: flex; flex-direction: column; gap: 0.7rem; }
488
- .cs-source { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
489
- .cs-source-label { font-size: 0.78rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
490
- .cs-source-tabs { display: inline-flex; gap: 0.35rem; flex-wrap: wrap; }
491
- .cs-locked { margin: 0; border-left-color: var(--color-accent); }
492
- .cs-group { display: flex; flex-direction: column; gap: 0.35rem; }
493
- .cs-group-label { font-size: 0.76rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
494
- .cs-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
495
- .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; }
496
- .cs-chip:hover:not(:disabled) { color: var(--color-fg); background: var(--color-surface-2); }
497
- .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; }
498
- /* as for `.chip`: the chosen case's chip keeps its accent under the pointer (known shell defect 33) */
499
- .cs-chip.on:hover:not(:disabled) { color: var(--color-accent); background: var(--color-accent-soft); }
500
- .cs-chip:disabled { opacity: 0.45; cursor: default; }
501
- .cs-chip-id { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.76rem; font-weight: 600; opacity: 0.85; }
502
- .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; }
503
- .cs-kind-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 40%, transparent); }
504
- .cs-kind-uploaded { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 40%, transparent); }
505
- .cs-modified { display: flex; align-items: center; gap: 0.35rem 0.5rem; flex-wrap: wrap; min-width: 0; }
506
- .cs-modified .badge { white-space: normal; max-width: 100%; }
507
- .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; }
508
- /* The compact one-of-N case picker (ADR-0071 rule 7): ten cases in four categories cost a 308px chip block, 21% of a
509
- 2560x1440 viewport, and one row as a dropdown. */
510
- .cs-select { width: 100%; max-width: 460px; }
511
-
512
- /* == 9 workbench ================================================================================================ */
513
-
514
- /* The rail: sized, never scrolled when sections are used (ADR-0071 rule 6). */
515
- .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; }
516
- .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); }
517
- .caos-wb-rail-panel { display: flex; flex-direction: column; gap: 0.8rem; min-height: 0; }
518
- /* A labelled control in the rail stacks its text above it; a knob's head keeps its own row, the value at the right
519
- (until 0.9.3 this rule outranked `.caos-knob-head` and stacked every knob, a line per knob; CAOS_APP_SHELL#77). */
520
- .caos-wb-rail label:not(.caos-knob-head) { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
521
- .caos-wb-rail .select, .caos-wb-rail .range { width: 100%; }
522
- /* The variants wrap in the rail instead of scrolling. */
523
- .caos-wb-rail .caos-variant-bar { margin-bottom: 0; }
524
- .caos-wb-rail .caos-chip-row { flex-wrap: wrap; overflow: visible; }
525
- .caos-wb-rail .caos-variant-note { font-size: 0.8rem; }
526
- .caos-wb-main { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
527
-
528
- /* CaseWorkbench: ONE row of at most six question groups; the open panel takes the height the row leaves and owns its
529
- scroll (failure class 4: drawings at zero or at a guessed size). */
530
- .caos-cw { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1 1 auto; }
531
- .caos-cw > .tabs { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
532
- .caos-cw > .tabs > .tablist { margin-bottom: 0.5rem; padding-bottom: var(--space-1); }
533
- .caos-cw > .tabs > .tablist .tab { padding: 0.38rem 0.85rem; }
534
- .caos-cw > .tabs > .tabpanel:not([hidden]) { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
535
- .caos-cw-panel { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; flex: 1 1 auto; min-height: 0; }
536
- .caos-cw-panel-head { display: flex; justify-content: flex-end; }
537
- .caos-cw-panel > .subtabs { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-block: 0; }
538
- .caos-cw-panel > .subtabs > .subtablist { margin-bottom: 0.45rem; }
539
- .caos-cw-panel > .subtabs > .subtabpanels, .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
540
- .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { gap: 0.6rem; }
541
- .caos-cw-context { max-width: 92ch; }
542
-
543
- /* VariantBar. */
544
- .caos-variant-bar { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.7rem; min-width: 0; }
545
- .caos-variant-head { display: flex; align-items: center; gap: 0.4rem 0.6rem; flex-wrap: wrap; }
546
- .caos-variant-title { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 600; }
547
- .caos-variant-note { margin: 0; font-size: 0.88rem; color: var(--color-fg-subtle); font-style: italic; }
548
-
549
- /* LaneBadge and provenance badges: which lane produced the values on screen, and on what data. */
550
- .caos-badges { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
551
- .caos-lane-live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
552
- .caos-lane-replay { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
553
- .caos-lane-offline { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
554
- .caos-prov-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 45%, transparent); }
555
- .caos-prov-synthetic { color: var(--color-magenta); border-color: color-mix(in oklab, var(--color-magenta) 45%, transparent); }
556
- .caos-prov-published { color: var(--color-fg-subtle); }
557
-
558
- /* Tones shared by readouts, gauges and verdicts. */
559
- .tone-good { --tone: var(--color-good); }
560
- .tone-warn { --tone: var(--color-warn); }
561
- .tone-bad { --tone: var(--color-bad); }
562
- .tone-accent { --tone: var(--color-accent); }
563
- .tone-neutral { --tone: var(--color-fg-faint); }
564
-
565
- /* Readout: labelled live values with units. */
566
- .caos-readout { display: flex; flex-direction: column; gap: 0.35rem; }
567
- .caos-readout-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
568
- .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; }
569
- .caos-readout dl { margin: 0; display: grid; gap: var(--space-1); }
570
- .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); }
571
- .caos-readout-row dt { color: var(--color-fg-subtle); }
572
- .caos-readout-row dd { margin: 0; text-align: right; }
573
- .caos-readout-value { font-family: var(--font-mono); font-weight: 650; color: var(--color-fg); }
574
- .caos-readout-unit { color: var(--color-fg-faint); font-size: 0.78rem; }
575
-
576
- /* Gauge: a value against labelled zones. */
577
- .caos-gauge-track { position: relative; height: 14px; border-radius: 7px; background: var(--color-surface-2); overflow: hidden; margin-top: 0.35rem; }
578
- .caos-gauge-zone { position: absolute; top: 0; height: 100%; background: var(--tone); opacity: 0.45; }
579
- .caos-gauge-needle { position: absolute; top: 0; width: 3px; height: 100%; background: var(--color-fg); transform: translateX(-1px); }
580
- .caos-gauge-scale { display: flex; justify-content: space-between; font-size: 0.72rem; color: var(--color-fg-faint); margin-top: 0.2rem; }
581
- .caos-gauge-value { color: var(--color-fg); font-weight: 700; font-family: var(--font-mono); }
582
- .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); }
583
- .caos-gauge-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: var(--space-1); background: var(--tone); }
584
-
585
- /* Verdict: the current diagnosis, coloured by its tone. */
586
- .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); }
587
- .caos-verdict-text { margin: 0.2rem 0 0; font-weight: 650; color: var(--color-fg); }
588
- .caos-verdict.compact { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.15rem 0.6rem; padding: 0.4rem 0.7rem; }
589
- .caos-verdict.compact .caos-verdict-text { margin: 0; }
590
-
591
- /* PlotCard: the frame every chart or table sits in. */
592
- .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; }
593
- .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; }
594
- .caos-plot-head .badge { font-size: 0.68rem; padding: 0.05rem 0.45rem; }
595
- .caos-plot-title { font-size: var(--text-sm); color: var(--color-fg-subtle); font-weight: 600; }
596
- .caos-plot-actions { display: inline-flex; gap: 0.3rem; }
597
- .caos-plot-body { position: relative; min-width: 0; overflow-x: auto; }
598
- .caos-plot-note { margin: 0.4rem 0 0; font-size: 0.78rem; color: var(--color-fg-faint); }
599
- .caos-plot.fill { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
600
- .caos-plot.fill > .caos-plot-body { flex: 1 1 0; min-height: 0; overflow: hidden; }
601
- /* The note of a filling card keeps at most 35% of the card and scrolls beyond it, so the drawing keeps a floor
602
- (CAOS_APP_SHELL#95: a long note left plots of 10 to 90 px at 1280 x 800). */
603
- .caos-plot.fill > .caos-plot-note { flex: 0 1 auto; max-height: 35%; overflow-y: auto; }
604
-
605
- /* The stage floor of a filling card (shell 0.11.2; the gate's G6 floor, `--stage-floor` 140 px). At 1280 px and wider the
606
- body of a filling card, the box the gate measures, keeps at least the floor itself, so the card grows when its header
607
- or its note wraps (a narrow column, the Spanish title, two badges, the wide font) and the containing panel scrolls
608
- when the cards do not fit (ADR-0071; the rail never does). 0.11.1 derived a card height from a fixed chrome instead,
609
- and a header that wrapped to a third line left the stage under the floor (CAOS_Contraste 0.07.000: 138 px; a
610
- 400 px column with a note: 106 px). Below 1280 px the document scrolls and nothing changes. */
611
- @media (min-width: 1280px) {
612
- .caos-plot.fill > .caos-plot-body { min-height: var(--caos-stage-floor, 140px); }
613
- }
614
-
615
- /* A row of views side by side. Every view of the row takes an equal share, a filling card included (known shell
616
- defect 23, #54: `.caos-plot.fill` outranked the row's zero basis and took the row). */
617
- .caos-views-row { display: flex; gap: 0.9rem; flex: 1 1 auto; min-height: 0; min-width: 0; }
618
- .caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: 1 1 0; min-width: 0; }
619
- /* ViewsRow's column: a view inside it keeps its height chain (a filling card fills the column); its share of the row
620
- is its flex-grow. */
621
- .caos-views-col { display: flex; flex-direction: column; min-width: 0; min-height: 0; gap: 0.6rem; }
622
-
623
- /* Staleness: a view showing data for an earlier selection says so. */
624
- .caos-stale .caos-plot-body > :not(.caos-stale-overlay), .caos-readout.caos-stale dl { opacity: 0.45; }
625
- .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); }
626
- .caos-stale-note { margin: 0.2rem 0 0; font-size: 0.76rem; color: var(--color-warn); }
627
-
628
- /* Stage: the drawing surface of an instrument, sized by its container. */
629
- .caos-stage { position: relative; width: 100%; height: 100%; min-width: 0; min-height: 0; }
630
- /* BarChart: as wide as its box; a filling chart takes the box's height and scrolls rows that do not fit. */
631
- .caos-bars { position: relative; width: 100%; min-width: 0; }
632
- .caos-bars.fill { height: 100%; min-height: 0; overflow-y: auto; }
633
- .caos-bars > svg { display: block; }
634
- /* A view whose data is not there yet says so (and declares data-state="loading" for the gate). */
635
- .caos-pending { margin: auto; padding: var(--space-5); color: var(--color-fg-faint); font-size: 0.86rem; text-align: center; }
636
- /* A failed view (PanelBoundary): an inline message in its own frame, never a blank page. */
637
- .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; }
638
- .caos-panel-error code { flex-basis: 100%; font-size: 0.78rem; color: var(--color-fg-subtle); }
639
-
640
- /* Tables in views and documents: tabular figures, compact rows, a header that stays in view while the body scrolls.
641
- A column of words reads left-aligned and wraps; numbers stay right-aligned. */
642
- .caos-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums; color: var(--color-fg); }
643
- .caos-table th, .caos-table td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--color-border); text-align: right; white-space: nowrap; }
644
- .caos-table th:first-child, .caos-table td:first-child { text-align: left; }
645
- .caos-table th.caos-col-text, .caos-table td.caos-col-text { text-align: left; white-space: normal; min-width: 16ch; }
646
- .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); }
647
- .caos-table tbody tr:hover { background: var(--color-surface-2); }
648
-
649
- @media (max-width: 900px) {
650
- /* The views of a row stack; a filling view gets a fixed readable height instead of the panel's. */
651
- .caos-views-row { flex-direction: column; }
652
- .caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: none; }
653
- .caos-plot.fill > .caos-plot-body { flex: none; height: clamp(260px, 48vh, 440px); }
654
- .caos-plot.fill > .caos-plot-note { max-height: none; overflow-y: visible; }
655
- }
656
- @media (max-width: 760px) {
657
- /* A phone wraps the cells instead of pushing the table past the page (found by the gate on the template). */
658
- .caos-table th, .caos-table td { white-space: normal; padding: 0.3rem 0.4rem; }
659
- }
660
-
661
- /* == 10 frames ================================================================================================== */
662
-
663
- /* ADR-0070: the shell-owned, full-viewport scenario focus frame. */
664
- .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); }
665
- .caos-focus-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--color-bg); }
666
- .caos-focus-instrument { position: absolute; inset: 0; min-width: 0; min-height: 0; }
667
- .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); }
668
- .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; }
669
- .caos-focus-label strong { font-size: 0.96rem; line-height: 1.2; }
670
- .caos-focus-label span { font-size: 0.78rem; line-height: 1.4; color: var(--color-fg-subtle); }
671
- .caos-focus-hud { position: absolute; left: 14px; top: 104px; display: grid; gap: 6px; pointer-events: none; }
672
- .caos-focus-hud > div { display: grid; gap: 1px; padding: 7px 10px; min-width: 120px; }
673
- .caos-focus-hud strong { font: 700 1rem var(--font-mono,monospace); }
674
- .caos-focus-hud span { color: var(--color-fg-subtle); font-size: 0.61rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; }
675
- .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); }
676
- .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; }
677
- .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); }
678
- @media (max-width: 900px) {
679
- .caos-focus-shell { grid-template-columns: minmax(0,1fr); grid-template-rows: minmax(0,54dvh) minmax(0,46dvh); }
680
- .caos-focus-rail { border-left: 0; border-top: 1px solid var(--color-border); }
681
- .caos-focus-label { max-width: calc(100% - 16px); top: 49px; left: 8px; padding: 6px 8px; }
682
- .caos-focus-hud { top: auto; bottom: 8px; left: 8px; right: 8px; display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 4px; }
683
- .caos-focus-hud > div { min-width: 0; padding: 5px; }
684
- .caos-focus-hud strong { font-size: 0.72rem; white-space: nowrap; }
685
- .caos-focus-hud span { font-size: 0.48rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
686
- .caos-focus-actions { top: 7px; right: 7px; }
687
- }
688
-
689
- /* The authenticated console frame (WorkbenchShell): a sidebar on a desktop, a bottom bar on a phone. Products supply
690
- their slots; the package owns the frame, the navigation semantics and the main landmark. */
691
- .caos-workbench-shell { min-height: 100vh; display: grid; grid-template-columns: 238px minmax(0, 1fr); }
692
- .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); }
693
- .caos-workbench-sidebar nav { display: grid; gap: var(--space-1); }
694
- .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; }
695
- .caos-workbench-sidebar nav a:hover { color: var(--color-fg); background: var(--color-surface-2); text-decoration: none; }
696
- .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); }
697
- .caos-workbench-sidebar nav a svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
698
- .caos-workbench-main { grid-column: 2; min-width: 0; }
699
- .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); }
700
- .caos-workbench-content { width: min(1540px, 100%); margin: 0 auto; padding: 2.25rem 2rem 4rem; }
701
- @media (max-width: 760px) {
702
- .caos-workbench-shell { display: block; padding-bottom: 66px; }
703
- .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; }
704
- .caos-workbench-sidebar > :not(nav) { display: none; }
705
- .caos-workbench-sidebar nav { grid-template-columns: repeat(var(--caos-workbench-route-count, 5), minmax(0, 1fr)); }
706
- .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; }
707
- .caos-workbench-main { min-width: 0; }
708
- .caos-workbench-header { min-height: 58px; padding: 0 1rem; }
709
- .caos-workbench-content { padding: 1.5rem 1rem 2.5rem; }
710
- }
711
-
712
- /* ADR-0058: the architecture modal. A hand-authored architecture SVG carries BOTH languages in ONE file and the
713
- wrapper picks one; the rules are scoped to [data-arch-lang] so the short class names cannot collide. */
714
- [data-arch-lang] .l-es { display: none; }
715
- [data-arch-lang="es"] .l-en { display: none; }
716
- [data-arch-lang="es"] .l-es { display: inline; }
717
- .caos-architecture-diagram > svg { display: block; width: 100%; height: auto; max-width: none; }
718
- .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; }
719
-
720
- /* The executive view (shell 0.12.0, conventions/problem-context-first.md): four sections in order, three inline illustrations,
721
- numbered source notes. The product fills content/executive.json; it never styles this view. Illustrations are inline SVG
722
- coloured with the theme tokens; a drawing carrying both languages shows the labels of the displayed one. */
723
- .caos-exec { display: flex; flex-direction: column; gap: 1.5rem; min-width: 0; }
724
- /* the landing block above the sub-tabs: the title, the key statement, the headline figures */
725
- .caos-exec-landing { min-width: 0; }
726
- .caos-exec-title { margin: 0 0 0.35rem; font-size: var(--text-xl); }
727
- .caos-exec-statement { margin: 0 0 1rem; font-size: var(--text-lg); line-height: 1.45; }
728
- .caos-exec-headline, .caos-exec-figures { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0.75rem; }
729
- .caos-exec-figures { margin-block: 1rem; }
730
- .caos-exec-figure { min-width: 0; padding: 0.7rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow-wrap: anywhere; }
731
- .caos-exec-label { display: inline-block; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 650; }
732
- .caos-exec-figure > .caos-exec-label { display: block; margin-bottom: 0.1rem; }
733
- .caos-exec-value { font-size: var(--text-xl); font-variant-numeric: tabular-nums; color: var(--color-accent); }
734
- .caos-exec-sep { color: var(--color-fg-faint); }
735
- .caos-exec-cite { margin-left: 0.15rem; font-size: var(--text-xs); }
736
- /* a sub-tab: the key message line first, then the supporting content, all at the full width of the column */
737
- .caos-exec-tabs { min-width: 0; }
738
- .caos-exec-section { min-width: 0; }
739
- .caos-exec-key { margin: 0 0 1rem; font-size: var(--text-lg); line-height: 1.45; font-weight: 600; }
740
- .caos-exec-paragraph { margin: 0 0 0.75rem; }
741
- .caos-exec-sub { margin: 1.25rem 0 0.5rem; font-size: var(--text-md); }
742
- .caos-exec-setting, .caos-exec-interaction, .caos-exec-status, .caos-exec-handoff { margin: 0.75rem 0; overflow-wrap: anywhere; }
743
- .caos-exec-cards, .caos-exec-cs, .caos-exec-actions, .caos-exec-causes, .caos-exec-evidence, .caos-exec-list { list-style: none; margin: 0; padding: 0; }
744
- .caos-exec-cards, .caos-exec-cs { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.9rem; }
745
- .caos-exec-actions, .caos-exec-causes { display: flex; flex-direction: column; gap: 0.7rem; }
746
- .caos-exec-card { min-width: 0; padding: 0.8rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); display: flex; flex-direction: column; gap: 0.5rem; overflow-wrap: anywhere; }
747
- .caos-exec-list li, .caos-exec-evidence li { margin-block: 0.35rem; overflow-wrap: anywhere; }
748
- .caos-exec-list, .caos-exec-evidence { list-style: disc; padding-left: 1.3rem; }
749
- .caos-exec-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
750
- .caos-exec-badge { align-self: flex-start; padding: 0.1rem 0.5rem; font-size: var(--text-xs); border: 1px solid var(--color-border); border-radius: 999px; color: var(--color-fg-subtle); }
751
- .caos-exec-cause { min-width: 0; overflow-wrap: anywhere; }
752
- .caos-exec-cause-head { display: flex; justify-content: space-between; gap: 1rem; }
753
- .caos-exec-bar { height: 0.45rem; margin-top: 0.3rem; background: var(--color-surface-2); border-radius: 999px; overflow: hidden; }
754
- .caos-exec-bar > span { display: block; height: 100%; background: var(--color-accent); }
755
- .caos-exec-cdef { font-size: var(--text-xs); line-height: 1.4; color: var(--color-fg-faint); }
756
- .caos-exec-fig { margin: 1.25rem 0; }
757
- .caos-exec-art { width: 100%; max-width: 640px; margin-inline: auto; }
758
- .caos-exec-art > svg { display: block; width: 100%; height: auto; }
759
- .caos-exec-art-wait { aspect-ratio: 8 / 5; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
760
- .caos-exec-fig svg text { font-family: var(--font-sans); }
761
- .caos-exec-fig[data-lang="en"] [data-lang="es"], .caos-exec-fig[data-lang="es"] [data-lang="en"] { display: none; }
762
- .caos-exec-fig-error { margin: 0 auto; max-width: 640px; padding: 1rem; border: 1px solid var(--color-bad); border-radius: var(--radius-md); color: var(--color-fg); overflow-wrap: anywhere; }
763
- /* below the sub-tabs: the numbered linked sources, then the onward links */
764
- .caos-exec-notes-wrap { border-top: 1px solid var(--color-border); padding-top: 0.75rem; }
765
- .caos-exec-notes-title { margin: 0 0 0.35rem; font-size: var(--text-sm); color: var(--color-fg-faint); }
766
- .caos-exec-notes { margin: 0; padding-left: 1.4rem; font-size: var(--text-sm); color: var(--color-fg-subtle); overflow-wrap: anywhere; }
767
- .caos-exec-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; padding-top: 0.25rem; }
768
- .caos-exec-link { font-weight: 600; }
769
- .caos-exec-error { padding: 1rem 1.25rem; border: 1px solid var(--color-bad); border-radius: var(--radius-md); }
1
+ @import "katex/dist/katex.min.css";
2
+
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 =================================================================================================== */
24
+
25
+ :root,
26
+ [data-theme="dark"] {
27
+ --color-bg: #0d1117;
28
+ --color-surface: #161b22;
29
+ --color-surface-2: #1c2230;
30
+ --color-border: #30363d;
31
+ --color-fg: #c9d1d9;
32
+ --color-fg-subtle: #9aa6b2;
33
+ --color-fg-faint: #828b97;
34
+ --color-accent: #58a6ff;
35
+ --color-accent-fg: #0d1117;
36
+ --color-accent-soft: #132036;
37
+ --color-accent-2: #3fb1c8;
38
+ --color-magenta: #f778ba;
39
+ --color-good: #3fb950;
40
+ --color-warn: #d29922;
41
+ --color-bad: #f85149;
42
+ --color-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 6px 16px rgba(0, 0, 0, 0.45);
43
+ color-scheme: dark;
44
+ }
45
+
46
+ [data-theme="light"] {
47
+ color-scheme: light;
48
+ --color-bg: #f6f8fa;
49
+ --color-surface: #ffffff;
50
+ --color-surface-2: #f0f3f6;
51
+ --color-border: #d0d7de;
52
+ --color-fg: #1f2328;
53
+ --color-fg-subtle: #57606a;
54
+ --color-fg-faint: #656d77;
55
+ --color-accent: #0969da;
56
+ --color-accent-fg: #ffffff;
57
+ --color-accent-soft: #ddf4ff;
58
+ --color-accent-2: #0a7886;
59
+ --color-magenta: #b93785;
60
+ --color-good: #197c36;
61
+ --color-warn: #946300;
62
+ --color-bad: #cf222e;
63
+ --color-shadow: 0 1px 2px rgba(31, 35, 40, 0.06), 0 4px 10px rgba(31, 35, 40, 0.04);
64
+ }
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) */
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
+
110
+ * { box-sizing: border-box; }
111
+ /* Known shell defect 1 (fixed 0.7.0): `height: 100%` with `overflow-x: hidden` made html and body scroll containers
112
+ pinned to the viewport, so a tall page could not scroll by script or anchor. Content-height documents. */
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; }
121
+ /* Known shell defect 2 (fixed 0.7.0): any author `display` un-hid a `[hidden]` panel. */
122
+ [hidden] { display: none !important; }
123
+ body {
124
+ margin: 0;
125
+ font-family: var(--font-sans);
126
+ background-color: var(--color-bg);
127
+ color: var(--color-fg);
128
+ -webkit-font-smoothing: antialiased;
129
+ -moz-osx-font-smoothing: grayscale;
130
+ line-height: 1.55;
131
+ }
132
+ a { color: var(--color-accent); text-decoration: none; }
133
+ a:hover { text-decoration: underline; }
134
+ button { font: inherit; cursor: pointer; color: inherit; }
135
+ h1, h2, h3, h4 { line-height: 1.2; font-weight: 650; letter-spacing: -0.01em; }
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; } }
139
+
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; }
141
+ .muted { color: var(--color-fg-subtle); }
142
+ .faint { color: var(--color-fg-faint); }
143
+ .mono { font-family: var(--font-mono); font-size: 0.9em; }
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; }
148
+ .badge.live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
149
+ .badge.precomputed, .badge.accent { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
150
+ .badge.warn { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
151
+
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; }
169
+ .brand:hover { text-decoration: none; }
170
+ .brand .brand-mark { color: var(--color-accent); display: inline-flex; flex: none; }
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; }
173
+ .icon-btn:hover { opacity: 1; color: var(--color-fg); text-decoration: none; }
174
+ .icon-btn svg { display: block; flex: none; }
175
+ .lang-code { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600; }
176
+ .header-sep { width: 1px; height: 20px; margin-inline: 0.4rem; background: var(--color-border); }
177
+
178
+ /* Footer: ADR-0016 s2, one compact line of provenance and honesty. */
179
+ .site-footer { border-top: 1px solid var(--color-border); margin-top: 3rem; background: var(--color-surface); }
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); }
181
+ .footer-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.75rem; }
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; }
183
+
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
+ }
208
+ @media (max-width: 760px) {
209
+ /* ADR-0071: the route row shares the header row and owns the horizontal scroll; no second row above the
210
+ instrument. */
211
+ .header-inner { height: 52px; min-height: 0; flex-wrap: nowrap; gap: 0.3rem; padding-inline: 0.55rem; }
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); }
215
+ .header-sep { margin-inline: 0.15rem; }
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; }
221
+ }
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. */
225
+ .brand span:last-child { display: none; }
226
+ .header-sep, .lang-code { display: none; }
227
+ .header-actions .icon-btn { padding: 0.2rem; }
228
+ }
229
+
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
+ /* A document fills the width of its column (shell 0.11.0, CAOS_APP_SHELL#96): text blocks, grids, figure rows and
335
+ tables all take it. A page that reads as one prose column keeps its own max width and is centred (ADR-0017 s1);
336
+ only the captions keep a measure, centred under their figure. */
337
+ .prose { font-size: var(--text-base); }
338
+ .prose section { margin-block: 1.75rem; }
339
+ .prose h2 { font-size: var(--text-xl); margin-block: 1.4rem 0.6rem; }
340
+ .prose h3 { font-size: 1.06rem; margin-block: 1.1rem 0.4rem; }
341
+ .prose p { margin-block: 0.6rem; }
342
+ .prose ul, .prose ol { margin-block: 0.5rem; padding-left: 1.3rem; }
343
+ .prose li { margin-block: 0.35rem; }
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
+ /* the lede of a page takes the full width of the document column (Felipe, 2026-10-13); only captions keep a measure */
349
+ .lede { color: var(--color-fg-subtle); font-size: var(--text-lg); margin: 0; max-width: none; }
350
+ .caos-doc-section { margin-block: 1.75rem; }
351
+ /* The references of a page or open tab: one block at its end (ADR-0017 s4). */
352
+ .caos-doc-references { margin-top: 2rem; padding-top: 0.4rem; border-top: 1px solid var(--color-border); }
353
+ .caos-doc-reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
354
+ .caos-doc-reference-list li { margin-block: 0.5rem; }
355
+ /* Wide content in a document scrolls inside its own box; the contained page never cuts it (G5). */
356
+ .prose table { display: block; max-width: 100%; overflow-x: auto; }
357
+ .prose pre { max-width: 100%; overflow-x: auto; }
358
+ .prose img, .prose svg, .prose video { max-width: 100%; height: auto; }
359
+
360
+ .fig-row { display: grid; grid-template-columns: 1.1fr 1fr; gap: 1.5rem; align-items: center; margin-block: 1.5rem; }
361
+ .fig-row.rev { grid-template-columns: 1fr 1.1fr; }
362
+ .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 1.25rem; margin-block: 1.5rem; }
363
+ .def-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 1rem; margin-block: 1.25rem; }
364
+ .def { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 0.9rem 1.1rem; }
365
+ .def h4 { margin: 0 0 0.3rem; color: var(--color-accent); font-size: 0.95rem; }
366
+ .def p { margin: 0; font-size: 0.9rem; color: var(--color-fg-subtle); }
367
+ .assume { margin-block: 1rem; padding: 0.85rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
368
+ .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); }
369
+ .assume ul { margin: 0; padding-left: 1.2rem; color: var(--color-fg-subtle); }
370
+ .assume li { margin-block: 0.3rem; font-size: 0.92rem; }
371
+ .tick-list, .cross-list { list-style: none; padding-left: 0; margin: 0.4rem 0 0; }
372
+ .tick-list li, .cross-list li { position: relative; padding-left: 1.5rem; margin-block: 0.5rem; }
373
+ .tick-list li::before { content: "✓"; position: absolute; left: 0; color: var(--color-good); font-weight: 700; }
374
+ .cross-list li::before { content: "✕"; position: absolute; left: 0; color: var(--color-fg-faint); font-weight: 700; }
375
+ @media (max-width: 900px) { .fig-row, .fig-row.rev { grid-template-columns: 1fr; } }
376
+ @media (max-width: 760px) { .two-col { grid-template-columns: 1fr; } }
377
+
378
+ /* Callouts. */
379
+ .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; }
380
+ .callout-honest { border-left-color: var(--color-warn); }
381
+ .callout-strong { border-left-color: var(--color-accent); background: var(--color-accent-soft); }
382
+ .callout-note { border-left-color: var(--color-fg-faint); }
383
+ .callout-title { display: flex; align-items: center; gap: 0.4rem; font-weight: 650; margin: 0 0 0.4rem; color: var(--color-fg); }
384
+ .callout-body { color: var(--color-fg-subtle); }
385
+ .callout-body p:first-child { margin-top: 0; }
386
+ .callout-body p:last-child { margin-bottom: 0; }
387
+ .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); }
388
+ .banner.warn { border-left-color: var(--color-warn); color: var(--color-warn); }
389
+ .banner.error { border-left-color: var(--color-bad); color: var(--color-bad); }
390
+ .hint { font-size: 0.8rem; color: var(--color-fg-faint); margin: 0; }
391
+
392
+ /* Equations and figures. */
393
+ .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; }
394
+ .equation-caption { margin-top: 0.5rem; font-size: 0.82rem; color: var(--color-fg-faint); text-align: center; }
395
+ .caos-glossary { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: 0.4rem 1.25rem; margin: 0.75rem 0; }
396
+ .caos-glossary-item { display: flex; gap: 0.5rem; align-items: baseline; }
397
+ .caos-glossary dt { flex: none; min-width: 3rem; font-weight: 600; }
398
+ .caos-glossary dd { margin: 0; color: var(--color-fg); }
399
+ .caos-stat-value { font-variant-numeric: tabular-nums; }
400
+ .caos-stat-source { color: var(--color-fg-faint); font-size: var(--text-sm); }
401
+ .caos-qa { margin: 0.9rem 0; }
402
+ .caos-qa-question { font-weight: 600; margin-bottom: 0.25rem; }
403
+ .caos-qa-answer > :first-child { margin-top: 0; }
404
+ .katex { color: var(--color-fg); }
405
+ .figure { margin: 1.5rem 0; }
406
+ .figure-caption, .fig-cap { text-align: center; font-size: var(--text-sm); color: var(--color-fg-faint); margin-top: 0.6rem; font-style: italic; }
407
+
408
+ /* References: at the end of each section (ADR-0017 s4). */
409
+ .references { margin-top: 2.5rem; border-top: 1px solid var(--color-border); padding-top: 1rem; }
410
+ .reference-list { font-size: 0.85rem; color: var(--color-fg-subtle); line-height: 1.5; padding-left: 1.4rem; }
411
+ .reference-list li { margin-block: 0.5rem; }
412
+ .cite-inline { font-style: normal; font-size: 0.92em; color: var(--color-fg-subtle); }
413
+ .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); }
414
+ .th-refs-label { font-weight: 650; color: var(--color-fg-faint); }
415
+
416
+ /* Theme-aware inline SVG diagrams (teaching figures). An <img> of an SVG cannot read these tokens. */
417
+ .fig-svg { width: 100%; max-width: 560px; height: auto; display: block; margin-inline: auto; }
418
+ .fig-svg.wide { max-width: 760px; }
419
+ .dg-axis { stroke: var(--color-fg-faint); stroke-width: 1.3; }
420
+ .dg-axis-label { fill: var(--color-fg-subtle); font: 12px var(--font-sans); }
421
+ .dg-tick { fill: var(--color-fg-subtle); font: 11px var(--font-mono); }
422
+ .dg-grid { stroke: var(--color-border); stroke-width: 0.5; opacity: 0.6; }
423
+ .dg-curve { fill: none; stroke: var(--color-accent); stroke-width: 2.2; stroke-linejoin: round; }
424
+ .dg-curve-2 { fill: none; stroke: var(--color-magenta); stroke-width: 2; }
425
+ .dg-curve-faint { fill: none; stroke: var(--color-fg-faint); stroke-width: 1.4; stroke-dasharray: 4 3; }
426
+ .dg-asymptote { stroke: var(--color-bad); stroke-width: 1.4; stroke-dasharray: 4 4; }
427
+ .dg-marker { stroke: var(--color-warn); stroke-width: 1.2; stroke-dasharray: 3 3; }
428
+ .dg-marker-label { fill: var(--color-warn); font: 600 11px var(--font-mono); }
429
+ .dg-note { fill: var(--color-fg-subtle); font: italic 11px var(--font-sans); }
430
+ .dg-fill-accent { fill: color-mix(in oklab, var(--color-accent) 16%, transparent); stroke: var(--color-accent); stroke-width: 1; }
431
+ .dg-fill-warn { fill: color-mix(in oklab, var(--color-warn) 16%, transparent); stroke: var(--color-warn); stroke-width: 1; }
432
+ .dg-box { fill: var(--color-surface); stroke: var(--color-border); stroke-width: 1.3; }
433
+ .dg-box.accent { stroke: var(--color-accent); fill: var(--color-accent-soft); }
434
+ .dg-box.good { stroke: var(--color-good); }
435
+ .dg-box-title { fill: var(--color-fg); font: 650 12px var(--font-sans); }
436
+ .dg-box-title.accent { fill: var(--color-accent); }
437
+ .dg-box-sub { fill: var(--color-fg-subtle); font: 10.5px var(--font-mono); }
438
+ .dg-node { fill: var(--color-surface); stroke: var(--color-accent); stroke-width: 1.4; }
439
+ .dg-node-label { fill: var(--color-fg); font: 600 12px var(--font-mono); }
440
+ .dg-edge { stroke: var(--color-fg-faint); stroke-width: 1.4; fill: none; }
441
+ .dg-edge-label { fill: var(--color-fg-subtle); font: 11px var(--font-mono); }
442
+ .dg-arrowhead { fill: var(--color-fg-faint); }
443
+ .dg-bar { fill: var(--color-accent); }
444
+ .dg-bar-2 { fill: var(--color-magenta); }
445
+ .dg-bar-label { fill: var(--color-fg-subtle); font: 11px var(--font-sans); }
446
+
447
+ /* == 7 controls ================================================================================================= */
448
+
449
+ .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; }
450
+ .btn:hover { border-color: var(--color-fg-faint); }
451
+ .btn.primary { background: var(--color-accent); color: var(--color-accent-fg); border-color: var(--color-accent); }
452
+ .btn:disabled { opacity: 0.5; cursor: default; }
453
+ .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; }
454
+ .range { width: 100%; accent-color: var(--color-accent); }
455
+ /* Native controls follow the theme (S2; known shell defect 13). */
456
+ .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); }
457
+ .app-shell button { color: inherit; }
458
+
459
+ /* Chips: a one-of-N choice rendered as pills; `.on` is the selected state. */
460
+ .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; }
461
+ .chip:hover:not(:disabled) { color: var(--color-fg); border-color: var(--color-fg-faint); }
462
+ .chip.on { background: var(--color-accent); color: var(--color-accent-fg); border-color: transparent; font-weight: 600; }
463
+ /* the active chip keeps its colours under the pointer: the hover rule above outranks `.chip.on` and, until 0.9.4, wrote
464
+ the text colour on the accent (3.04:1 in light, 1.64:1 in dark; known shell defect 33) */
465
+ .chip.on:hover:not(:disabled) { color: var(--color-accent-fg); border-color: transparent; }
466
+ .chip:disabled { opacity: 0.45; cursor: default; }
467
+
468
+ /* Registered controls (Knob, ChipGroup). */
469
+ .caos-knob { display: flex; flex-direction: column; gap: var(--space-1); }
470
+ /* Chromium keeps a 2 px user-agent side margin on a range input: at width 100% it reached 2 px past a clipping card
471
+ (a PlotCard body) and the gate's G5 failed at phone widths (CAOS_APP_SHELL#91). */
472
+ .caos-knob input[type='range'] { margin-inline: 0; }
473
+ .caos-knob-head { display: flex; justify-content: space-between; gap: var(--space-2); font-size: 0.8rem; color: var(--color-fg-subtle); }
474
+ .caos-knob-value { font-family: var(--font-mono); color: var(--color-fg); font-weight: 600; white-space: nowrap; }
475
+ .caos-chipgroup { display: flex; flex-direction: column; gap: 0.3rem; min-width: 0; }
476
+ .caos-chipgroup-label { font-size: 0.8rem; color: var(--color-fg-subtle); }
477
+ .caos-field { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
478
+
479
+ /* Icons: lucide renders `svg.lucide`; its size follows the place it is in, so products pass no size and every app
480
+ draws the same icon at the same size. An icon beside text takes the text's size. */
481
+ svg.lucide { flex: none; }
482
+ .icon-btn svg.lucide, .brand-mark svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
483
+ :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; }
484
+
485
+ /* == 8 case selector ============================================================================================ */
486
+
487
+ .cs { display: flex; flex-direction: column; gap: 0.7rem; }
488
+ .cs-source { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
489
+ .cs-source-label { font-size: 0.78rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
490
+ .cs-source-tabs { display: inline-flex; gap: 0.35rem; flex-wrap: wrap; }
491
+ .cs-locked { margin: 0; border-left-color: var(--color-accent); }
492
+ .cs-group { display: flex; flex-direction: column; gap: 0.35rem; }
493
+ .cs-group-label { font-size: 0.76rem; font-weight: 600; color: var(--color-fg-subtle); text-transform: uppercase; letter-spacing: 0.03em; }
494
+ .cs-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; }
495
+ .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; }
496
+ .cs-chip:hover:not(:disabled) { color: var(--color-fg); background: var(--color-surface-2); }
497
+ .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; }
498
+ /* as for `.chip`: the chosen case's chip keeps its accent under the pointer (known shell defect 33) */
499
+ .cs-chip.on:hover:not(:disabled) { color: var(--color-accent); background: var(--color-accent-soft); }
500
+ .cs-chip:disabled { opacity: 0.45; cursor: default; }
501
+ .cs-chip-id { font-family: var(--font-mono, ui-monospace, monospace); font-size: 0.76rem; font-weight: 600; opacity: 0.85; }
502
+ .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; }
503
+ .cs-kind-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 40%, transparent); }
504
+ .cs-kind-uploaded { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 40%, transparent); }
505
+ .cs-modified { display: flex; align-items: center; gap: 0.35rem 0.5rem; flex-wrap: wrap; min-width: 0; }
506
+ .cs-modified .badge { white-space: normal; max-width: 100%; }
507
+ .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; }
508
+ /* The compact one-of-N case picker (ADR-0071 rule 7): ten cases in four categories cost a 308px chip block, 21% of a
509
+ 2560x1440 viewport, and one row as a dropdown. */
510
+ .cs-select { width: 100%; max-width: 460px; }
511
+
512
+ /* == 9 workbench ================================================================================================ */
513
+
514
+ /* The rail: sized, never scrolled when sections are used (ADR-0071 rule 6). */
515
+ .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; }
516
+ .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); }
517
+ .caos-wb-rail-panel { display: flex; flex-direction: column; gap: 0.8rem; min-height: 0; }
518
+ /* A labelled control in the rail stacks its text above it; a knob's head keeps its own row, the value at the right
519
+ (until 0.9.3 this rule outranked `.caos-knob-head` and stacked every knob, a line per knob; CAOS_APP_SHELL#77). */
520
+ .caos-wb-rail label:not(.caos-knob-head), .caos-focus-rail label:not(.caos-knob-head) { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.8rem; color: var(--color-fg-subtle); }
521
+ .caos-wb-rail .select, .caos-wb-rail .range, .caos-focus-rail .select, .caos-focus-rail .range { width: 100%; }
522
+ /* The variants wrap in the rail instead of scrolling. */
523
+ .caos-wb-rail .caos-variant-bar, .caos-focus-rail .caos-variant-bar { margin-bottom: 0; }
524
+ .caos-wb-rail .caos-chip-row, .caos-focus-rail .caos-chip-row { flex-wrap: wrap; overflow: visible; }
525
+ .caos-wb-rail .caos-variant-note, .caos-focus-rail .caos-variant-note { font-size: 0.8rem; }
526
+ .caos-wb-main { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
527
+
528
+ /* CaseWorkbench: ONE row of at most six question groups; the open panel takes the height the row leaves and owns its
529
+ scroll (failure class 4: drawings at zero or at a guessed size). */
530
+ .caos-cw { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1 1 auto; }
531
+ .caos-cw > .tabs { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
532
+ .caos-cw > .tabs > .tablist { margin-bottom: 0.5rem; padding-bottom: var(--space-1); }
533
+ .caos-cw > .tabs > .tablist .tab { padding: 0.38rem 0.85rem; }
534
+ .caos-cw > .tabs > .tabpanel:not([hidden]) { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }
535
+ .caos-cw-panel { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; flex: 1 1 auto; min-height: 0; }
536
+ .caos-cw-panel-head { display: flex; justify-content: flex-end; }
537
+ .caos-cw-panel > .subtabs { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin-block: 0; }
538
+ .caos-cw-panel > .subtabs > .subtablist { margin-bottom: 0.45rem; }
539
+ .caos-cw-panel > .subtabs > .subtabpanels, .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
540
+ .caos-cw-panel > .subtabs > .subtabpanels > .subtabpanel { gap: 0.6rem; }
541
+ .caos-cw-context { max-width: 92ch; }
542
+
543
+ /* VariantBar. */
544
+ .caos-variant-bar { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.7rem; min-width: 0; }
545
+ .caos-variant-head { display: flex; align-items: center; gap: 0.4rem 0.6rem; flex-wrap: wrap; }
546
+ .caos-variant-title { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 600; }
547
+ .caos-variant-note { margin: 0; font-size: 0.88rem; color: var(--color-fg-subtle); font-style: italic; }
548
+
549
+ /* LaneBadge and provenance badges: which lane produced the values on screen, and on what data. */
550
+ .caos-badges { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
551
+ .caos-lane-live { color: var(--color-good); border-color: color-mix(in oklab, var(--color-good) 45%, transparent); }
552
+ .caos-lane-replay { color: var(--color-accent); border-color: color-mix(in oklab, var(--color-accent) 45%, transparent); }
553
+ .caos-lane-offline { color: var(--color-warn); border-color: color-mix(in oklab, var(--color-warn) 45%, transparent); }
554
+ .caos-prov-real { color: var(--color-accent-2); border-color: color-mix(in oklab, var(--color-accent-2) 45%, transparent); }
555
+ .caos-prov-synthetic { color: var(--color-magenta); border-color: color-mix(in oklab, var(--color-magenta) 45%, transparent); }
556
+ .caos-prov-published { color: var(--color-fg-subtle); }
557
+
558
+ /* Tones shared by readouts, gauges and verdicts. */
559
+ .tone-good { --tone: var(--color-good); }
560
+ .tone-warn { --tone: var(--color-warn); }
561
+ .tone-bad { --tone: var(--color-bad); }
562
+ .tone-accent { --tone: var(--color-accent); }
563
+ .tone-neutral { --tone: var(--color-fg-faint); }
564
+
565
+ /* Readout: labelled live values with units. */
566
+ .caos-readout { display: flex; flex-direction: column; gap: 0.35rem; }
567
+ .caos-readout-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
568
+ .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; }
569
+ .caos-readout dl { margin: 0; display: grid; gap: var(--space-1); }
570
+ .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); }
571
+ .caos-readout-row dt { color: var(--color-fg-subtle); }
572
+ .caos-readout-row dd { margin: 0; text-align: right; }
573
+ .caos-readout-value { font-family: var(--font-mono); font-weight: 650; color: var(--color-fg); }
574
+ .caos-readout-unit { color: var(--color-fg-faint); font-size: 0.78rem; }
575
+
576
+ /* Gauge: a value against labelled zones. */
577
+ .caos-gauge-track { position: relative; height: 14px; border-radius: 7px; background: var(--color-surface-2); overflow: hidden; margin-top: 0.35rem; }
578
+ .caos-gauge-zone { position: absolute; top: 0; height: 100%; background: var(--tone); opacity: 0.45; }
579
+ .caos-gauge-needle { position: absolute; top: 0; width: 3px; height: 100%; background: var(--color-fg); transform: translateX(-1px); }
580
+ .caos-gauge-scale { display: flex; justify-content: space-between; font-size: 0.72rem; color: var(--color-fg-faint); margin-top: 0.2rem; }
581
+ .caos-gauge-value { color: var(--color-fg); font-weight: 700; font-family: var(--font-mono); }
582
+ .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); }
583
+ .caos-gauge-dot { display: inline-block; width: 8px; height: 8px; border-radius: 2px; margin-right: var(--space-1); background: var(--tone); }
584
+
585
+ /* Verdict: the current diagnosis, coloured by its tone. */
586
+ .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); }
587
+ .caos-verdict-text { margin: 0.2rem 0 0; font-weight: 650; color: var(--color-fg); }
588
+ .caos-verdict.compact { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.15rem 0.6rem; padding: 0.4rem 0.7rem; }
589
+ .caos-verdict.compact .caos-verdict-text { margin: 0; }
590
+
591
+ /* PlotCard: the frame every chart or table sits in. */
592
+ .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; }
593
+ .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; }
594
+ .caos-plot-head .badge { font-size: 0.68rem; padding: 0.05rem 0.45rem; }
595
+ .caos-plot-title { font-size: var(--text-sm); color: var(--color-fg-subtle); font-weight: 600; }
596
+ .caos-plot-actions { display: inline-flex; gap: 0.3rem; }
597
+ .caos-plot-body { position: relative; min-width: 0; overflow-x: auto; }
598
+ .caos-plot-note { margin: 0.4rem 0 0; font-size: 0.78rem; color: var(--color-fg-faint); }
599
+ .caos-plot.fill { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
600
+ .caos-plot.fill > .caos-plot-body { flex: 1 1 0; min-height: 0; overflow: hidden; }
601
+ /* The note of a filling card keeps at most 35% of the card and scrolls beyond it, so the drawing keeps a floor
602
+ (CAOS_APP_SHELL#95: a long note left plots of 10 to 90 px at 1280 x 800). */
603
+ .caos-plot.fill > .caos-plot-note { flex: 0 1 auto; max-height: 35%; overflow-y: auto; }
604
+
605
+ /* The stage floor of a filling card (shell 0.11.2; the gate's G6 floor, `--stage-floor` 140 px). At 1280 px and wider the
606
+ body of a filling card, the box the gate measures, keeps at least the floor itself, so the card grows when its header
607
+ or its note wraps (a narrow column, the Spanish title, two badges, the wide font) and the containing panel scrolls
608
+ when the cards do not fit (ADR-0071; the rail never does). 0.11.1 derived a card height from a fixed chrome instead,
609
+ and a header that wrapped to a third line left the stage under the floor (CAOS_Contraste 0.07.000: 138 px; a
610
+ 400 px column with a note: 106 px). Below 1280 px the document scrolls and nothing changes. */
611
+ @media (min-width: 1280px) {
612
+ .caos-plot.fill > .caos-plot-body { min-height: var(--caos-stage-floor, 140px); }
613
+ }
614
+
615
+ /* A row of views side by side. Every view of the row takes an equal share, a filling card included (known shell
616
+ defect 23, #54: `.caos-plot.fill` outranked the row's zero basis and took the row). */
617
+ .caos-views-row { display: flex; gap: 0.9rem; flex: 1 1 auto; min-height: 0; min-width: 0; }
618
+ .caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: 1 1 0; min-width: 0; }
619
+ /* ViewsRow's column: a view inside it keeps its height chain (a filling card fills the column); its share of the row
620
+ is its flex-grow. */
621
+ .caos-views-col { display: flex; flex-direction: column; min-width: 0; min-height: 0; gap: 0.6rem; }
622
+
623
+ /* Staleness: a view showing data for an earlier selection says so. */
624
+ .caos-stale .caos-plot-body > :not(.caos-stale-overlay), .caos-readout.caos-stale dl { opacity: 0.45; }
625
+ .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); }
626
+ .caos-stale-note { margin: 0.2rem 0 0; font-size: 0.76rem; color: var(--color-warn); }
627
+
628
+ /* Stage: the drawing surface of an instrument, sized by its container. */
629
+ .caos-stage { position: relative; width: 100%; height: 100%; min-width: 0; min-height: 0; }
630
+ /* BarChart: as wide as its box; a filling chart takes the box's height and scrolls rows that do not fit. */
631
+ .caos-bars { position: relative; width: 100%; min-width: 0; }
632
+ .caos-bars.fill { height: 100%; min-height: 0; overflow-y: auto; }
633
+ .caos-bars > svg { display: block; }
634
+ /* A view whose data is not there yet says so (and declares data-state="loading" for the gate). */
635
+ .caos-pending { margin: auto; padding: var(--space-5); color: var(--color-fg-faint); font-size: 0.86rem; text-align: center; }
636
+ /* A failed view (PanelBoundary): an inline message in its own frame, never a blank page. */
637
+ .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; }
638
+ .caos-panel-error code { flex-basis: 100%; font-size: 0.78rem; color: var(--color-fg-subtle); }
639
+
640
+ /* Tables in views and documents: tabular figures, compact rows, a header that stays in view while the body scrolls.
641
+ A column of words reads left-aligned and wraps; numbers stay right-aligned. */
642
+ .caos-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums; color: var(--color-fg); }
643
+ .caos-table th, .caos-table td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--color-border); text-align: right; white-space: nowrap; }
644
+ .caos-table th:first-child, .caos-table td:first-child { text-align: left; }
645
+ .caos-table th.caos-col-text, .caos-table td.caos-col-text { text-align: left; white-space: normal; min-width: 16ch; }
646
+ .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); }
647
+ .caos-table tbody tr:hover { background: var(--color-surface-2); }
648
+
649
+ @media (max-width: 900px) {
650
+ /* The views of a row stack; a filling view gets a fixed readable height instead of the panel's. */
651
+ .caos-views-row { flex-direction: column; }
652
+ .caos-views-row > *, .caos-views-row > .caos-plot.fill { flex: none; }
653
+ .caos-plot.fill > .caos-plot-body { flex: none; height: clamp(260px, 48vh, 440px); }
654
+ .caos-plot.fill > .caos-plot-note { max-height: none; overflow-y: visible; }
655
+ }
656
+ @media (max-width: 760px) {
657
+ /* A phone wraps the cells instead of pushing the table past the page (found by the gate on the template). */
658
+ .caos-table th, .caos-table td { white-space: normal; padding: 0.3rem 0.4rem; }
659
+ }
660
+
661
+ /* == 10 frames ================================================================================================== */
662
+
663
+ /* ADR-0070: the shell-owned, full-viewport scenario focus frame. */
664
+ .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); }
665
+ .caos-focus-stage { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--color-bg); }
666
+ .caos-focus-instrument { position: absolute; inset: 0; min-width: 0; min-height: 0; }
667
+ .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); }
668
+ .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; }
669
+ .caos-focus-label strong { font-size: 0.96rem; line-height: 1.2; }
670
+ .caos-focus-label span { font-size: 0.78rem; line-height: 1.4; color: var(--color-fg-subtle); }
671
+ .caos-focus-hud { position: absolute; left: 14px; top: 104px; display: grid; gap: 6px; pointer-events: none; }
672
+ .caos-focus-hud > div { display: grid; gap: 1px; padding: 7px 10px; min-width: 120px; }
673
+ .caos-focus-hud strong { font: 700 1rem var(--font-mono,monospace); }
674
+ .caos-focus-hud span { color: var(--color-fg-subtle); font-size: 0.61rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; }
675
+ .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); }
676
+ .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; }
677
+ .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); }
678
+ @media (max-width: 900px) {
679
+ .caos-focus-shell { grid-template-columns: minmax(0,1fr); grid-template-rows: minmax(0,54dvh) minmax(0,46dvh); }
680
+ .caos-focus-rail { border-left: 0; border-top: 1px solid var(--color-border); }
681
+ .caos-focus-label { max-width: calc(100% - 16px); top: 49px; left: 8px; padding: 6px 8px; }
682
+ .caos-focus-hud { top: auto; bottom: 8px; left: 8px; right: 8px; display: grid; grid-template-columns: repeat(4,minmax(0,1fr)); gap: 4px; }
683
+ .caos-focus-hud > div { min-width: 0; padding: 5px; }
684
+ .caos-focus-hud strong { font-size: 0.72rem; white-space: nowrap; }
685
+ .caos-focus-hud span { font-size: 0.48rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
686
+ .caos-focus-actions { top: 7px; right: 7px; }
687
+ }
688
+
689
+ /* The authenticated console frame (WorkbenchShell): a sidebar on a desktop, a bottom bar on a phone. Products supply
690
+ their slots; the package owns the frame, the navigation semantics and the main landmark. */
691
+ .caos-workbench-shell { min-height: 100vh; display: grid; grid-template-columns: 238px minmax(0, 1fr); }
692
+ .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); }
693
+ .caos-workbench-sidebar nav { display: grid; gap: var(--space-1); }
694
+ .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; }
695
+ .caos-workbench-sidebar nav a:hover { color: var(--color-fg); background: var(--color-surface-2); text-decoration: none; }
696
+ .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); }
697
+ .caos-workbench-sidebar nav a svg.lucide { width: var(--icon-lg); height: var(--icon-lg); }
698
+ .caos-workbench-main { grid-column: 2; min-width: 0; }
699
+ .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); }
700
+ .caos-workbench-content { width: min(1540px, 100%); margin: 0 auto; padding: 2.25rem 2rem 4rem; }
701
+ @media (max-width: 760px) {
702
+ .caos-workbench-shell { display: block; padding-bottom: 66px; }
703
+ .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; }
704
+ .caos-workbench-sidebar > :not(nav) { display: none; }
705
+ .caos-workbench-sidebar nav { grid-template-columns: repeat(var(--caos-workbench-route-count, 5), minmax(0, 1fr)); }
706
+ .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; }
707
+ .caos-workbench-main { min-width: 0; }
708
+ .caos-workbench-header { min-height: 58px; padding: 0 1rem; }
709
+ .caos-workbench-content { padding: 1.5rem 1rem 2.5rem; }
710
+ }
711
+
712
+ /* ADR-0058: the architecture modal. A hand-authored architecture SVG carries BOTH languages in ONE file and the
713
+ wrapper picks one; the rules are scoped to [data-arch-lang] so the short class names cannot collide. */
714
+ [data-arch-lang] .l-es { display: none; }
715
+ [data-arch-lang="es"] .l-en { display: none; }
716
+ [data-arch-lang="es"] .l-es { display: inline; }
717
+ .caos-architecture-diagram > svg { display: block; width: 100%; height: auto; max-width: none; }
718
+ .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; }
719
+
720
+ /* The executive view (shell 0.12.0, conventions/problem-context-first.md): four sections in order, three inline illustrations,
721
+ numbered source notes. The product fills content/executive.json; it never styles this view. Illustrations are inline SVG
722
+ coloured with the theme tokens; a drawing carrying both languages shows the labels of the displayed one. */
723
+ .caos-exec { display: flex; flex-direction: column; gap: 1.5rem; min-width: 0; }
724
+ /* the landing block above the sub-tabs: the title, the key statement, the headline figures */
725
+ .caos-exec-landing { min-width: 0; }
726
+ .caos-exec-title { margin: 0 0 0.35rem; font-size: var(--text-xl); }
727
+ .caos-exec-statement { margin: 0 0 1rem; font-size: var(--text-lg); line-height: 1.45; }
728
+ .caos-exec-headline, .caos-exec-figures { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0.75rem; }
729
+ .caos-exec-figures { margin-block: 1rem; }
730
+ .caos-exec-figure { min-width: 0; padding: 0.7rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow-wrap: anywhere; }
731
+ .caos-exec-label { display: inline-block; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-fg-faint); font-weight: 650; }
732
+ .caos-exec-figure > .caos-exec-label { display: block; margin-bottom: 0.1rem; }
733
+ .caos-exec-value { font-size: var(--text-xl); font-variant-numeric: tabular-nums; color: var(--color-accent); }
734
+ .caos-exec-sep { color: var(--color-fg-faint); }
735
+ .caos-exec-cite { margin-left: 0.15rem; font-size: var(--text-xs); }
736
+ /* a sub-tab: the key message line first, then the supporting content, all at the full width of the column */
737
+ .caos-exec-tabs { min-width: 0; }
738
+ .caos-exec-section { min-width: 0; }
739
+ .caos-exec-key { margin: 0 0 1rem; font-size: var(--text-lg); line-height: 1.45; font-weight: 600; }
740
+ .caos-exec-paragraph { margin: 0 0 0.75rem; }
741
+ .caos-exec-sub { margin: 1.25rem 0 0.5rem; font-size: var(--text-md); }
742
+ .caos-exec-setting, .caos-exec-interaction, .caos-exec-status, .caos-exec-handoff { margin: 0.75rem 0; overflow-wrap: anywhere; }
743
+ .caos-exec-cards, .caos-exec-cs, .caos-exec-actions, .caos-exec-causes, .caos-exec-evidence, .caos-exec-list { list-style: none; margin: 0; padding: 0; }
744
+ .caos-exec-cards, .caos-exec-cs { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.9rem; }
745
+ .caos-exec-actions, .caos-exec-causes { display: flex; flex-direction: column; gap: 0.7rem; }
746
+ .caos-exec-card { min-width: 0; padding: 0.8rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); display: flex; flex-direction: column; gap: 0.5rem; overflow-wrap: anywhere; }
747
+ .caos-exec-list li, .caos-exec-evidence li { margin-block: 0.35rem; overflow-wrap: anywhere; }
748
+ .caos-exec-list, .caos-exec-evidence { list-style: disc; padding-left: 1.3rem; }
749
+ .caos-exec-badges { display: flex; flex-wrap: wrap; gap: 0.35rem; }
750
+ .caos-exec-badge { align-self: flex-start; padding: 0.1rem 0.5rem; font-size: var(--text-xs); border: 1px solid var(--color-border); border-radius: 999px; color: var(--color-fg-subtle); }
751
+ .caos-exec-cause { min-width: 0; overflow-wrap: anywhere; }
752
+ .caos-exec-cause-head { display: flex; justify-content: space-between; gap: 1rem; }
753
+ .caos-exec-bar { height: 0.45rem; margin-top: 0.3rem; background: var(--color-surface-2); border-radius: 999px; overflow: hidden; }
754
+ .caos-exec-bar > span { display: block; height: 100%; background: var(--color-accent); }
755
+ .caos-exec-cdef { font-size: var(--text-xs); line-height: 1.4; color: var(--color-fg-faint); }
756
+ .caos-exec-fig { margin: 1.25rem 0; }
757
+ .caos-exec-art { width: 100%; max-width: 640px; margin-inline: auto; }
758
+ .caos-exec-art > svg { display: block; width: 100%; height: auto; }
759
+ .caos-exec-art-wait { aspect-ratio: 8 / 5; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
760
+ .caos-exec-fig svg text { font-family: var(--font-sans); }
761
+ .caos-exec-fig[data-lang="en"] [data-lang="es"], .caos-exec-fig[data-lang="es"] [data-lang="en"] { display: none; }
762
+ .caos-exec-fig-error { margin: 0 auto; max-width: 640px; padding: 1rem; border: 1px solid var(--color-bad); border-radius: var(--radius-md); color: var(--color-fg); overflow-wrap: anywhere; }
763
+ /* below the sub-tabs: the numbered linked sources, then the onward links */
764
+ .caos-exec-notes-wrap { border-top: 1px solid var(--color-border); padding-top: 0.75rem; }
765
+ .caos-exec-notes-title { margin: 0 0 0.35rem; font-size: var(--text-sm); color: var(--color-fg-faint); }
766
+ .caos-exec-notes { margin: 0; padding-left: 1.4rem; font-size: var(--text-sm); color: var(--color-fg-subtle); overflow-wrap: anywhere; }
767
+ .caos-exec-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; padding-top: 0.25rem; }
768
+ .caos-exec-link { font-weight: 600; }
769
+ .caos-exec-error { padding: 1rem 1.25rem; border: 1px solid var(--color-bad); border-radius: var(--radius-md); }
770
+
771
+ /* == flip cards and the card deck (shell 0.14.0) ================================================================== */
772
+
773
+ /* A flip card: two faces stacked in one cell (the card is as tall as its back, so a row of cards keeps one height), the
774
+ inner box turns on the Y axis. The hidden face leaves the accessibility tree and the tab order through `visibility`
775
+ (switched after the turn on the way out, at once on the way in) and `aria-hidden`; its content stays in the markup.
776
+ Theme tokens only. Under reduced motion the faces swap without the turn. */
777
+ .caos-flip { position: relative; display: flex; min-width: 0; width: 100%; perspective: 1100px; }
778
+ .caos-flip-inner { display: grid; flex: 1 1 auto; min-width: 0; transform-style: preserve-3d; transition: transform 0.45s ease; }
779
+ .caos-flip[data-flip-open="true"] > .caos-flip-inner { transform: rotateY(180deg); }
780
+ .caos-flip-face { grid-area: 1 / 1; min-width: 0; display: flex; flex-direction: column; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow-wrap: anywhere; backface-visibility: hidden; -webkit-backface-visibility: hidden; transition: visibility 0s linear 0s; }
781
+ .caos-flip-back { transform: rotateY(180deg); visibility: hidden; padding: 0.8rem 1rem; gap: 0.5rem; transition: visibility 0s linear 0.45s; }
782
+ .caos-flip[data-flip-open="true"] > .caos-flip-inner > .caos-flip-front { visibility: hidden; transition-delay: 0.45s; }
783
+ .caos-flip[data-flip-open="true"] > .caos-flip-inner > .caos-flip-back { visibility: visible; transition-delay: 0s; }
784
+ .caos-flip-toggle { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; width: 100%; padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
785
+ .caos-flip-front > .caos-flip-toggle { flex: 1 1 auto; padding: 0.8rem 1rem; font-weight: 650; border-radius: var(--radius-md); }
786
+ .caos-flip-front:hover { border-color: var(--color-accent); }
787
+ .caos-flip-title { min-width: 0; }
788
+ .caos-flip-icon { flex: none; color: var(--color-fg-faint); }
789
+ .caos-flip-return { flex: none; font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.04em; font-weight: 650; color: var(--color-fg-faint); }
790
+ .caos-flip-return-title { min-width: 0; }
791
+ .caos-flip-content { display: flex; flex-direction: column; gap: 0.5rem; min-width: 0; }
792
+ @media (prefers-reduced-motion: reduce) {
793
+ .caos-flip-inner { transform: none !important; transition: none !important; }
794
+ .caos-flip-back { transform: none !important; }
795
+ .caos-flip-face { transition: none !important; }
796
+ }
797
+
798
+ /* The card deck: a row of cards, or a carousel that pages through them (one window of as many cards as fit, at least
799
+ one; the page and the panel never scroll sideways). Entering cards slide in; reduced motion removes it. */
800
+ .caos-deck { display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; }
801
+ .caos-deck-track { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.9rem; min-width: 0; touch-action: pan-y; }
802
+ .caos-deck[data-deck-mode="carousel"] > .caos-deck-track { grid-template-columns: repeat(var(--deck-per, 1), minmax(0, 1fr)); }
803
+ .caos-deck-card { min-width: 0; display: flex; }
804
+ .caos-deck-card[hidden] { display: none; }
805
+ .caos-card { flex: 1 1 auto; min-width: 0; padding: 0.8rem 1rem; background: var(--color-surface-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); display: flex; flex-direction: column; gap: 0.5rem; overflow-wrap: anywhere; }
806
+ .caos-deck-bar { display: flex; align-items: center; justify-content: center; gap: 0.75rem; }
807
+ .caos-deck-btn { display: inline-flex; align-items: center; justify-content: center; width: 2.25rem; height: 2.25rem; padding: 0; border: 1px solid var(--color-border); border-radius: 999px; background: var(--color-surface); color: var(--color-fg); cursor: pointer; }
808
+ .caos-deck-btn:hover { border-color: var(--color-accent); color: var(--color-accent); }
809
+ .caos-deck-btn[aria-disabled="true"] { opacity: 0.4; cursor: default; }
810
+ .caos-deck-btn[aria-disabled="true"]:hover { border-color: var(--color-border); color: var(--color-fg); }
811
+ .caos-deck-position { min-width: 6.5rem; text-align: center; font-size: var(--text-sm); color: var(--color-fg-subtle); font-variant-numeric: tabular-nums; }
812
+ @keyframes caos-deck-in { from { opacity: 0; transform: translateX(0.75rem); } to { opacity: 1; transform: none; } }
813
+ .caos-deck[data-deck-moved] .caos-deck-card { animation: caos-deck-in 0.28s ease-out; }
814
+ @media (prefers-reduced-motion: reduce) { .caos-deck-card { animation: none !important; } }
815
+
816
+ /* Flip cards inside the executive view keep the width of the plain cards they replace. */
817
+ .caos-exec .caos-exec-cs.caos-deck-track { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
818
+ .caos-exec .caos-deck[data-deck-mode="carousel"] > .caos-exec-cs.caos-deck-track { grid-template-columns: repeat(var(--deck-per, 1), minmax(0, 1fr)); }
819
+
820
+ /* == Focus mode for the App (shell 0.14.0, ADR-0070) ================================================================== */
821
+
822
+ /* The stage is the open group; the label overlay (heading and line) sits above it, so the group starts below the label. */
823
+ .caos-focus-instrument > .caos-cw-focus { position: absolute; inset: 0; padding: 4.6rem 0.9rem 0.9rem; }
824
+ .caos-focus-instrument > .caos-cw-focus > .tabs { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto; }
825
+ .caos-focus-rail-body { display: flex; flex-direction: column; gap: var(--space-3); padding: 0.85rem; min-width: 0; }
826
+ .caos-focus-enter { align-self: flex-start; }
827
+ @media (max-width: 900px) {
828
+ .caos-focus-instrument > .caos-cw-focus { padding: 6.6rem 0.5rem 0.5rem; }
829
+ }