@qball-inc/tokens 1.0.0 → 1.1.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/README.md ADDED
@@ -0,0 +1,102 @@
1
+ <p align="center">
2
+ <a href="https://qball-inc.github.io/qball-design-system/">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/QBall-Inc/qball-design-system/main/assets/qball-logo-handoff/qball-logo-dark.gif">
5
+ <img src="https://raw.githubusercontent.com/QBall-Inc/qball-design-system/main/assets/qball-logo-handoff/qball-logo-parchment.gif" alt="QBall Design System" width="180" height="180">
6
+ </picture>
7
+ </a>
8
+ </p>
9
+
10
+ <h1 align="center">@qball-inc/tokens</h1>
11
+
12
+ <p align="center">
13
+ The locked <b>token layer</b> of the QBall Design System — drop-in CSS custom properties,<br>
14
+ component classes, and a DTCG / Style-Dictionary JSON mirror. Zero build step.<br>
15
+ Framework-agnostic. Light and dark from the same source.
16
+ </p>
17
+
18
+ <p align="center">
19
+ <a href="https://www.npmjs.com/package/@qball-inc/tokens"><img src="https://img.shields.io/npm/v/@qball-inc/tokens?color=3F6B5B&label=npm" alt="npm version"></a>
20
+ <a href="https://github.com/QBall-Inc/qball-design-system/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@qball-inc/tokens?color=3F6B5B" alt="Apache-2.0 license"></a>
21
+ <a href="https://qball-inc.github.io/qball-design-system/"><img src="https://img.shields.io/badge/gallery-live-3F6B5B" alt="component gallery"></a>
22
+ </p>
23
+
24
+ ---
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ pnpm add @qball-inc/tokens
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ The token layer is **plain CSS** plus a JSON mirror — there is no build step and no
35
+ runtime. Import the CSS in your app's style entry. **Order matters:** the component
36
+ layer reads `var(--token)` values defined by the layer above it.
37
+
38
+ ```css
39
+ /* app.css */
40
+
41
+ /* REQUIRED — every --token (colors, --data-* finance signals, --font-display,
42
+ radii, spacing) + semantic element styles + the button family (.btn). */
43
+ @import "@qball-inc/tokens/colors-and-type.css";
44
+
45
+ /* REQUIRED — the application component layer (.stat, .num, .badge, .meter,
46
+ .modal, .switch, .field, …). Must come AFTER colors-and-type.css. */
47
+ @import "@qball-inc/tokens/components.css";
48
+
49
+ /* OPTIONAL — Tailwind v4 @theme export: token-named utilities for your own
50
+ markup + the --font-display override seam. */
51
+ @import "@qball-inc/tokens/theme.css";
52
+ ```
53
+
54
+ Switch themes by setting `data-theme` on the root — light and dark are both
55
+ first-class and swap every token:
56
+
57
+ ```html
58
+ <html data-theme="dark">
59
+ <!-- … --></html>
60
+ ```
61
+
62
+ Consume the tokens as cross-platform data (DTCG / Style-Dictionary shape) from the
63
+ package root or the explicit subpath:
64
+
65
+ ```js
66
+ import tokens from "@qball-inc/tokens"; // → tokens.json
67
+ // or: import tokens from "@qball-inc/tokens/tokens.json";
68
+ ```
69
+
70
+ ## What's in the package
71
+
72
+ | Import | File | Delivers | Required? |
73
+ | --- | --- | --- | --- |
74
+ | `@qball-inc/tokens/colors-and-type.css` | `colors_and_type.css` | Every CSS custom property the components reference + semantic element styles + the `.btn` family. | **Yes** |
75
+ | `@qball-inc/tokens/components.css` | `components.css` | The full application component layer (the rest of the class inventory). | **Yes** |
76
+ | `@qball-inc/tokens/theme.css` | `theme.css` | Tailwind v4 `@theme` export (token-named utilities + the `--font-display` seam). | Optional |
77
+ | `@qball-inc/tokens` · `@qball-inc/tokens/tokens.json` | `tokens.json` | DTCG / Style-Dictionary JSON mirror (cross-platform). | Optional |
78
+
79
+ Importing **only `colors-and-type.css` then `components.css`** (in that order) paints
80
+ the entire component inventory. Omitting either leaves components unstyled — a silent
81
+ miss, not an error. Full wiring guide:
82
+ [docs/consumer-setup.md](https://github.com/QBall-Inc/qball-design-system/blob/main/docs/consumer-setup.md).
83
+
84
+ ## Display font
85
+
86
+ This package ships with **Fira Code** as the default display face. The system's
87
+ intended display face is **Berkeley Mono**, a commercial typeface that is **not**
88
+ redistributed here, so nothing licensed reaches the published package. To restore
89
+ Berkeley Mono in a private build, see the
90
+ [repository README](https://github.com/QBall-Inc/qball-design-system#display-font).
91
+
92
+ ## Part of the QBall Design System
93
+
94
+ - **Components:** [`@qball-inc/react`](https://www.npmjs.com/package/@qball-inc/react) — the token-driven React component library.
95
+ - **Gallery:** [live component contact-sheet](https://qball-inc.github.io/qball-design-system/) (light + dark).
96
+ - **Source + docs:** [QBall-Inc/qball-design-system](https://github.com/QBall-Inc/qball-design-system).
97
+
98
+ ## License
99
+
100
+ [Apache-2.0](https://github.com/QBall-Inc/qball-design-system/blob/main/LICENSE) ©
101
+ QBall Inc. (The Apache-2.0 license covers this package's code; it is distinct from the
102
+ Berkeley Mono font license, which is not granted here.)
@@ -458,3 +458,65 @@ hr, .rule {
458
458
  .num--up { color: var(--data-up); }
459
459
  .num--down { color: var(--data-down); }
460
460
  .num--flat { color: var(--data-flat); }
461
+
462
+ /* ============================================================
463
+ QuBrain graph stage + text scale (additive, 1.1.0)
464
+ Theme-INDEPENDENT constants: the graph explorer is dark-only
465
+ by ruling, so it never flips with the page theme. graph.css
466
+ maps the ordinary tokens (--bg-*, --text-*, --border-*,
467
+ --color-*, --data-*, --anno-*) onto these inside the
468
+ explorer; nothing else consumes them.
469
+ Two tiers, as approved:
470
+ · canvas — deep-ink stage + brighter labels (--stage-*)
471
+ · panel — the entity panel, filter bar and details pill
472
+ (--stage-panel-*; lighter, accessibility-tested
473
+ greys than the page dark theme)
474
+ Accents are the luminous dark-theme values, pinned so a
475
+ light page can never repaint the nodes.
476
+ ============================================================ */
477
+ :root {
478
+ /* canvas tier */
479
+ --stage-bg: #12161F; /* Deep ink */
480
+ --stage-surface: #1A1F2B;
481
+ --stage-text-primary: #EDE8E1;
482
+ --stage-text-secondary: #D6D1C8;
483
+ --stage-text-muted: #A8A29E;
484
+ --stage-border: rgba(255, 255, 255, 0.06);
485
+ --stage-border-strong: rgba(255, 255, 255, 0.25);
486
+
487
+ /* panel tier (panel, filter bar, details pill) */
488
+ --stage-panel-bg: #1E1D1B;
489
+ --stage-panel-surface: #2A2826;
490
+ --stage-panel-text-primary: #E7E0D6;
491
+ --stage-panel-text-secondary: #CDC6BB;
492
+ --stage-panel-text-muted: #8A847D;
493
+ --stage-panel-border: rgba(255, 255, 255, 0.06);
494
+ --stage-panel-border-strong: rgba(255, 255, 255, 0.14);
495
+ --stage-panel-divider: rgba(255, 255, 255, 0.07); /* glass strip hairline */
496
+ --stage-mark: #E7E2DA; /* launcher mascot ink over the stage */
497
+
498
+ /* accents (shared by both tiers) */
499
+ --stage-signal: #5B9E87;
500
+ --stage-highlight: #D97706;
501
+ --stage-signal-bg: rgba(91, 158, 135, 0.15);
502
+ --stage-highlight-bg: rgba(217, 119, 6, 0.15);
503
+ --stage-data-up: #4FB07A;
504
+ --stage-data-down: #E2705F;
505
+ --stage-data-warn: #D9B43C;
506
+ --stage-data-info: #5B9BD6;
507
+ --stage-data-flat: #A8A29E;
508
+ --stage-data-up-bg: rgba(79, 176, 122, 0.15);
509
+ --stage-data-down-bg: rgba(226, 112, 95, 0.15);
510
+ --stage-data-warn-bg: rgba(217, 180, 60, 0.16);
511
+ --stage-data-info-bg: rgba(91, 155, 214, 0.15);
512
+ --stage-anno-source: #93A7B5;
513
+ --stage-anno-source-bg: rgba(147, 167, 181, 0.16);
514
+
515
+ /* Light chat scrim — the QuBae overlay dims the page less than a modal. */
516
+ --color-scrim-light: rgba(20, 20, 20, 0.22);
517
+
518
+ /* Text scale — multiplies the QuBrain / QuBae component text sizes.
519
+ 1 = exactly as designed. A consumer that steps its type up on wide
520
+ screens sets it to match, e.g. 1.25 at min-width 1600px. */
521
+ --text-scale: 1;
522
+ }
package/components.css CHANGED
@@ -1196,3 +1196,212 @@ html[data-theme="dark"] .theme-toggle .ic-moon { display: inline; }
1196
1196
  background-clip: padding-box;
1197
1197
  }
1198
1198
  *::-webkit-scrollbar-corner { background: transparent; }
1199
+
1200
+
1201
+ /* ============================================================
1202
+ QuBrain trust components + QuBae chat surface (additive, 1.1.0)
1203
+ ClaimCard · SourceRow · ProvenanceFooter · FacetFilterBar ·
1204
+ EntityPanel · QuBae launcher, overlay, turns, verdict stamps.
1205
+ Component text sizes multiply by --text-scale (1 = as designed).
1206
+ The graph explorer frame + canvas ship separately in graph.css.
1207
+ ============================================================ */
1208
+ /* ---- ClaimCard: the single way a claim renders anywhere ---- */
1209
+ .claim{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-md);padding:12px 14px;display:flex;flex-direction:column;gap:8px}
1210
+ .claim__text{margin:0;font-family:var(--font-body);font-size:calc(13.5px * var(--text-scale, 1));line-height:1.55;color:var(--text-primary);text-wrap:pretty}
1211
+ .claim--superseded .claim__text{color:var(--text-muted);text-decoration:line-through;text-decoration-thickness:1px}
1212
+ .claim__now{margin:0;font-family:var(--font-body);font-size:calc(13px * var(--text-scale, 1));line-height:1.5;color:var(--text-primary);border-left:2px solid var(--color-signal);padding-left:10px;text-wrap:pretty}
1213
+ .claim__now b{font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:.8px;text-transform:uppercase;color:var(--color-signal);font-weight:600;margin-right:4px}
1214
+ .claim__meta{display:flex;flex-wrap:wrap;gap:5px 14px;align-items:baseline;font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));letter-spacing:.3px;color:var(--text-muted)}
1215
+ .claim__conf{font-weight:600}
1216
+ .claim__conf--high{color:var(--color-signal)}
1217
+ .claim__conf--med{color:var(--data-warn)}
1218
+ .claim__conf--low{color:var(--data-flat)}
1219
+ .claim__mark--endorsed{color:var(--color-signal);font-weight:500}
1220
+ .claim__mark--verified{color:var(--anno-source);font-weight:500}
1221
+ .claim__src{margin-left:auto;color:var(--anno-source);text-decoration:none;white-space:nowrap}
1222
+ .claim__src:hover{color:var(--color-signal)}
1223
+ /* ---- SourceRow: the reading-list unit ---- */
1224
+ .srclist{display:flex;flex-direction:column}
1225
+ .srcrow{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;gap:10px;align-items:center;padding:8px 10px;text-decoration:none}
1226
+ .srcrow+.srcrow{border-top:.5px solid var(--border-default)}
1227
+ .srcrow__mark{font-family:var(--font-ui);font-size:calc(9px * var(--text-scale, 1));letter-spacing:.5px;font-weight:600;color:var(--anno-source);background:var(--anno-source-bg);padding:2px 5px;border-radius:var(--radius-sm)}
1228
+ .srcrow__title{font-family:var(--font-body);font-size:calc(12.5px * var(--text-scale, 1));color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1229
+ .srcrow__date{font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));color:var(--text-muted);white-space:nowrap}
1230
+ .srcrow__out{color:var(--anno-source);font-size:calc(11px * var(--text-scale, 1))}
1231
+ .srcrow:hover .srcrow__title{color:var(--color-signal)}
1232
+ .srcrow:hover .srcrow__out{color:var(--color-signal)}
1233
+ /* ---- ProvenanceFooter: one line, two fixed variants, never hidden ---- */
1234
+ .provfoot{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));letter-spacing:.35px;color:var(--text-muted);padding:9px 0 0;border-top:1px solid var(--border-default)}
1235
+ .provfoot b{color:var(--text-secondary);font-weight:600}
1236
+ /* ---- FacetFilterBar: assembled from chip primitives, squared (no pills) ---- */
1237
+ .facetbar{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center;font-family:var(--font-ui)}
1238
+ .facetbar__group{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
1239
+ .facetbar__dom{font-size:calc(9.5px * var(--text-scale, 1));letter-spacing:1px;text-transform:uppercase;color:var(--text-muted);margin-right:3px}
1240
+ .fchip{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));letter-spacing:.3px;padding:3px 9px;border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:transparent;color:var(--text-secondary);cursor:pointer}
1241
+ .fchip:hover{border-color:var(--color-signal);color:var(--color-signal)}
1242
+ .fchip[aria-pressed="true"]{background:var(--signal-bg);color:var(--color-signal);border-color:var(--color-signal)}
1243
+ .facetbar__clear{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));border:0;background:none;color:var(--anno-source);cursor:pointer;padding:3px 4px}
1244
+ .facetbar__clear:hover{color:var(--color-signal)}
1245
+ .facetbar__count{font-size:calc(10px * var(--text-scale, 1));color:var(--text-muted)}
1246
+ /* ---- EntityPanel: the reading surface beside the canvas ---- */
1247
+ .epanel{display:flex;flex-direction:column;background:var(--bg-primary);min-height:0}
1248
+ .epanel__head{padding:14px 16px 12px;border-bottom:1px solid var(--border-default);display:flex;flex-direction:column;gap:6px}
1249
+ .epanel__crumbs{display:flex;flex-wrap:wrap;gap:4px;align-items:center;font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));color:var(--text-muted)}
1250
+ .epanel__crumbs button{border:0;background:none;padding:0;font:inherit;color:var(--anno-source);cursor:pointer}
1251
+ .epanel__crumbs button:hover{color:var(--color-signal)}
1252
+ .epanel__crumbs button[aria-current="true"]{color:var(--text-primary);font-weight:600;cursor:default}
1253
+ .epanel__name{margin:0;font-family:var(--font-heading);font-size:calc(16px * var(--text-scale, 1));font-weight:600;color:var(--text-primary);letter-spacing:-.2px;display:flex;gap:8px;align-items:baseline;flex-wrap:wrap}
1254
+ .epanel__cls{color:var(--color-signal);font-size:calc(10px * var(--text-scale, 1));text-transform:uppercase;letter-spacing:.8px;font-family:var(--font-ui);font-weight:600}
1255
+ .epanel__meta{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));color:var(--text-muted)}
1256
+ .epanel__tags{display:flex;flex-wrap:wrap;gap:4px}
1257
+ .epanel__scroll{flex:1;overflow-y:auto;padding:12px 16px 16px;display:flex;flex-direction:column;gap:16px;min-height:0}
1258
+ .epanel__hlabel{margin:0 0 8px;font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:1px;text-transform:uppercase;color:var(--text-muted)}
1259
+ .epanel__hop{display:flex;flex-direction:column;gap:8px}
1260
+ .epanel__comnote{font-family:var(--font-ui);font-size:calc(11.5px * var(--text-scale, 1));color:var(--text-secondary);line-height:1.6;margin:0}
1261
+ .epanel__empty{font-family:var(--font-ui);font-size:calc(11.5px * var(--text-scale, 1));color:var(--text-muted);line-height:1.7;padding:8px 0}
1262
+ .epanel__foot{padding:0 16px 12px}
1263
+ .nrow{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:baseline;padding:7px 2px;border:0;background:none;text-align:left;cursor:pointer;font-family:var(--font-ui)}
1264
+ .nrow+.nrow{border-top:.5px solid var(--border-default)}
1265
+ .nrow__name{font-size:calc(12px * var(--text-scale, 1));color:var(--text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1266
+ .nrow:hover .nrow__name{color:var(--color-signal)}
1267
+ .nrow__kind{font-size:calc(9.5px * var(--text-scale, 1));letter-spacing:.4px;white-space:nowrap}
1268
+ .nrow__kind--typed{color:var(--color-signal)}
1269
+ .nrow__kind--com{color:var(--text-muted)}
1270
+
1271
+ /* ============================================================
1272
+ QuBae — chat agent surface for a knowledge graph. Locked rulings:
1273
+ launcher = corner mark + "ask [Q]" + antenna pulse-dot (the one
1274
+ sanctioned idle motion); overlay = hairline corner panel, ~460px
1275
+ portrait, theme-responsive; answers = verdict-tinted boxes with
1276
+ right-aligned squared stamps, in-box +1/−1 feedback, shimmering
1277
+ [N sources · newest …] line. No hover tooltips
1278
+ inside the overlay: click-to-expand only (touch-safe, no
1279
+ overlay-on-overlay clipping). Behavior: @qball-inc/elements chat.
1280
+ ============================================================ */
1281
+
1282
+ /* mascot — riff on the Stocky CRT: amber eyes + antenna tips, sage scanline */
1283
+ .qbmark{display:inline-grid;place-items:center;line-height:0;color:var(--text-primary)}
1284
+ .qbmark svg{width:100%;height:100%;display:block;overflow:visible}
1285
+ .qb-screen{fill:#161410}
1286
+ .qb-scan{fill:#2E5348}
1287
+ .qb-eye{fill:#D97706}
1288
+ .qb-glint{fill:#F7F3EE}
1289
+ .qb-dot{fill:#D97706}
1290
+
1291
+ /* keycap — shared kbd chip (esc, Q) */
1292
+ .keycap{display:inline-flex;align-items:center;justify-content:center;min-width:15px;height:16px;padding:0 4px;border:1px solid var(--border-strong);border-bottom-width:2px;border-radius:3px;font-family:var(--font-ui);font-size:calc(9.5px * var(--text-scale, 1));font-weight:600;color:var(--text-secondary);background:var(--bg-primary);box-sizing:border-box}
1293
+
1294
+ /* launcher — fixed corner mark */
1295
+ .qlaunch{position:fixed;right:clamp(20px,1.6vw,44px);bottom:clamp(18px,1.5vw,40px);z-index:60;display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;background:none;border:0;padding:6px;color:var(--text-primary)}
1296
+ .qlaunch:hover{color:var(--color-signal)}
1297
+ .qlaunch .qbmark{width:clamp(40px,2.6vw,56px);height:clamp(44px,2.86vw,62px);position:relative}
1298
+ .qlaunch__dot{position:absolute;right:-2px;top:-2px;width:5px;height:5px;border-radius:50%;background:var(--color-highlight);animation:qb-pulse 2.4s var(--ease-in-out) infinite}
1299
+ .qlaunch__cap{display:flex;align-items:center;gap:5px;font-family:var(--font-ui);font-size:clamp(9.5px,.6vw,11px);letter-spacing:.6px;color:var(--text-muted)}
1300
+ @keyframes qb-pulse{0%,100%{opacity:.35;transform:scale(1)}50%{opacity:1;transform:scale(1.25)}}
1301
+ @media (prefers-reduced-motion:reduce){.qlaunch__dot{animation:none;opacity:.8}}
1302
+
1303
+ /* overlay — scrim + corner-lifted portrait panel */
1304
+ .qoverlay{position:fixed;inset:0;z-index:70;visibility:hidden}
1305
+ .qoverlay.open{visibility:visible}
1306
+ .qoverlay__scrim{position:absolute;inset:0;background:var(--color-scrim-light);opacity:0;transition:opacity var(--dur-base) var(--ease-out)}
1307
+ .qoverlay.open .qoverlay__scrim{opacity:1}
1308
+ .qpanel{position:absolute;right:18px;bottom:16px;width:min(460px,calc(100vw - 36px));height:min(600px,calc(100vh - 32px));display:flex;flex-direction:column;background:var(--bg-primary);border:1px solid var(--border-strong);border-radius:var(--radius-lg);box-shadow:0 18px 48px rgba(20,20,20,.18);opacity:0;transform:translateY(14px);transition:opacity var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out)}
1309
+ .qoverlay.open .qpanel{opacity:1;transform:none}
1310
+ @media (prefers-reduced-motion:reduce){.qpanel{transform:none}.qoverlay__scrim{transition:none}}
1311
+ @media (max-width:720px){.qpanel{left:12px;right:12px;bottom:12px;width:auto;box-sizing:border-box;height:calc(100vh - 24px);height:min(720px,calc(100dvh - 24px))}}
1312
+ .qpanel__head{display:flex;align-items:center;gap:8px;padding:10px 14px;border-bottom:.5px solid var(--border-default);font-family:var(--font-ui)}
1313
+ .qpanel__head .qbmark{width:20px;height:22px}
1314
+ .qpanel__title{font-size:calc(11.5px * var(--text-scale, 1));color:var(--text-muted);letter-spacing:.5px}
1315
+ .qpanel__esc{margin-left:auto;display:flex;align-items:center}
1316
+ .qpanel__esc .keycap{position:relative;top:-1px;cursor:pointer}
1317
+ .qpanel__body{flex:1;overflow-y:auto;padding:2px 14px;font-family:var(--font-display);font-size:calc(12.5px * var(--text-scale, 1));line-height:1.65}
1318
+ .qpanel__comp{padding:10px 14px 4px;border-top:.5px solid var(--border-default);display:grid;grid-template-columns:56px 1fr;gap:8px;align-items:start}
1319
+ .qpanel__prompt{font-family:var(--font-display);font-size:calc(12.5px * var(--text-scale, 1));color:var(--color-signal);font-weight:600;white-space:nowrap;line-height:1.65;padding-top:7px}
1320
+ .qpanel__input{font-family:var(--font-display);font-size:calc(12.5px * var(--text-scale, 1));line-height:1.65;border:0;border-bottom:1px solid var(--border-strong);padding:7px 4px;min-height:20px;background:transparent;color:var(--text-primary);outline:none;width:100%;resize:none;overflow:hidden;box-sizing:border-box}
1321
+ .qpanel__disc{padding:8px 14px 12px;font-family:var(--font-ui);font-size:calc(9.5px * var(--text-scale, 1));color:var(--text-muted);line-height:1.45}
1322
+
1323
+ /* conversation turns (terminal register) */
1324
+ .qturn{display:grid;grid-template-columns:56px minmax(0,1fr);gap:8px;align-items:start;padding:11px 0;font-family:var(--font-display);font-size:calc(12.5px * var(--text-scale, 1));line-height:1.65}
1325
+ .qturn__you{color:var(--color-signal);font-weight:600;white-space:nowrap}
1326
+ .qturn__bot{color:var(--color-highlight);font-weight:700;white-space:nowrap}
1327
+ .qturn__t-you{color:var(--text-primary)}
1328
+ .qturn__t-bot{color:var(--text-secondary)}
1329
+ .qsep{height:0;border:0;border-top:.5px solid var(--border-default);margin:0}
1330
+ .qn{color:var(--data-up);font-weight:600}
1331
+
1332
+ /* verdict stamp row — right rail.
1333
+ Click stamp toggles the trimmed explanation inline; › also closes.
1334
+ Refused is a boundary (dashed), not an error. */
1335
+ .vrow{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin-bottom:7px;min-height:22px}
1336
+ .vrow.open{justify-content:space-between;gap:10px}
1337
+ .vstamp{display:inline-flex;align-items:center;gap:6px;font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));font-weight:600;letter-spacing:1.2px;text-transform:uppercase;padding:4px 9px;border-radius:2px;cursor:pointer;flex:none;white-space:nowrap}
1338
+ .vstamp--grounded{color:var(--color-signal);background:var(--signal-bg);border:1px solid color-mix(in srgb,var(--color-signal) 30%,transparent)}
1339
+ .vstamp--refused{color:var(--text-muted);background:var(--bg-surface);border:1px dashed var(--border-strong)}
1340
+ .vstamp--withheld{color:var(--color-highlight);background:var(--highlight-bg);border:1px solid color-mix(in srgb,var(--color-highlight) 30%,transparent)}
1341
+ .vrow__exp{display:none;align-items:baseline;gap:8px;font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));color:var(--text-muted);white-space:nowrap;flex:1 1 auto;min-width:0}
1342
+ .vrow.open .vrow__exp{display:flex}
1343
+ .vrow__close{flex:none;background:none;border:0;padding:0;cursor:pointer;font-family:var(--font-display);font-size:calc(12px * var(--text-scale, 1));font-weight:700;color:var(--text-secondary)}
1344
+ .vrow__close:hover{color:var(--text-primary)}
1345
+
1346
+ /* verdict-tinted answer boxes */
1347
+ .vbox{display:block;border-radius:var(--radius-sm);padding:10px 12px;line-height:1.6}
1348
+ .vbox--grounded{background:var(--signal-bg);border:1px solid color-mix(in srgb,var(--color-signal) 30%,transparent)}
1349
+ .vbox--refused{background:var(--bg-surface);border:1px dashed var(--border-strong)}
1350
+ .vbox--withheld{background:var(--highlight-bg);border:1px solid color-mix(in srgb,var(--color-highlight) 30%,transparent)}
1351
+
1352
+ /* feedback marks — +1/−1 diff register, in-box bottom-right, wake on hover/press */
1353
+ .qfb{display:flex;justify-content:flex-end;gap:12px;margin-top:8px;font-family:var(--font-display);font-size:calc(10px * var(--text-scale, 1));font-weight:600;color:var(--text-muted);opacity:.55;transition:opacity var(--dur-fast) var(--ease-out)}
1354
+ .vbox:hover .qfb,.qfb:has([aria-pressed="true"]){opacity:1}
1355
+ .qfb button{background:none;border:0;padding:0;cursor:pointer;font:inherit;color:inherit;transition:color var(--dur-fast) var(--ease-out)}
1356
+ .qfb button:hover{color:var(--text-primary)}
1357
+ .qfb .qfb__up[aria-pressed="true"]{color:var(--color-signal)}
1358
+ .qfb .qfb__down[aria-pressed="true"]{color:var(--color-highlight)}
1359
+
1360
+ /* sources line — [N sources · newest …]: count + freshness only, titles on expand */
1361
+ .qsrcline{display:inline-flex;background-color:transparent;border:0;padding:0;cursor:pointer;font-family:var(--font-display);font-size:calc(10.5px * var(--text-scale, 1));margin-top:7px}
1362
+ .ground-wave--sources{--wave-base:var(--data-info);--wave-hi:#A7D0F0}
1363
+ .qsrclist{display:none;flex-direction:column;margin-top:2px}
1364
+ .qsrclist.open{display:flex}
1365
+
1366
+ /* traceable-claim rows inside a withheld answer */
1367
+ .qclaims{display:flex;flex-direction:column;margin-top:10px;font-family:var(--font-ui)}
1368
+ .qclaim{display:grid;grid-template-columns:16px minmax(0,1fr) auto;gap:8px;align-items:baseline;padding:7px 0;border-top:.5px solid var(--border-default);font-size:calc(11px * var(--text-scale, 1));color:var(--text-secondary)}
1369
+ .qclaim__conf{font-family:var(--font-display);font-weight:600}
1370
+ .qclaim__conf--high{color:var(--color-signal)}
1371
+ .qclaim__conf--med{color:var(--data-warn)}
1372
+ .qclaim__conf--low{color:var(--text-muted)}
1373
+ .qclaim__lvl{font-size:calc(10px * var(--text-scale, 1));color:var(--text-muted);font-family:var(--font-display)}
1374
+
1375
+ /* launcher — compact corner variant for long-form pages whose bottom chrome owns the corner */
1376
+ @media (max-width:720px){.qlaunch__cap{display:none}.qlaunch{right:16px;bottom:16px}}
1377
+ @media (max-width:720px){.qlaunch--post{left:16px;right:auto;bottom:16px}.qlaunch--post .qbmark{width:34px;height:37px}}
1378
+
1379
+ /* verdict row — provenance ticker when the explanation overflows; stamp shimmer until opened */
1380
+ .vrow__txt{flex:1;min-width:0;overflow:hidden;white-space:nowrap}.vtick{display:inline-flex}
1381
+ .vrow__txt.is-ticking{-webkit-mask-image:linear-gradient(90deg,transparent 0,#000 10px,#000 calc(100% - 18px),transparent);mask-image:linear-gradient(90deg,transparent 0,#000 10px,#000 calc(100% - 18px),transparent)}
1382
+ .vrow__txt.is-ticking .vtick{animation:vtick var(--tdur,12s) linear infinite}.vrow__txt.is-ticking .vtick>span{padding-right:40px}.vrow__txt.is-ticking:hover .vtick{animation-play-state:paused}
1383
+ @keyframes vtick{to{transform:translateX(-50%)}}
1384
+ .vstamp__wave{background-size:220% 100%;-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent;animation:vstamp-wave 2.6s linear infinite}
1385
+ .vstamp--grounded .vstamp__wave{background-image:linear-gradient(100deg,var(--color-signal) 0%,var(--color-signal) 38%,color-mix(in srgb,var(--color-signal) 35%,#fff) 50%,var(--color-signal) 62%,var(--color-signal) 100%)}
1386
+ .vstamp--withheld .vstamp__wave{background-image:linear-gradient(100deg,var(--color-highlight) 0%,var(--color-highlight) 38%,color-mix(in srgb,var(--color-highlight) 35%,#fff) 50%,var(--color-highlight) 62%,var(--color-highlight) 100%)}
1387
+ .vstamp--refused .vstamp__wave{background-image:linear-gradient(100deg,var(--text-muted) 0%,var(--text-muted) 38%,color-mix(in srgb,var(--text-muted) 35%,#fff) 50%,var(--text-muted) 62%,var(--text-muted) 100%)}
1388
+ .vstamp.is-seen .vstamp__wave{animation:none;background:none;-webkit-text-fill-color:currentColor;color:inherit}
1389
+ @keyframes vstamp-wave{from{background-position:120% 0}to{background-position:-120% 0}}
1390
+ @media (prefers-reduced-motion:reduce){.vstamp__wave{animation:none;background:none;-webkit-text-fill-color:currentColor;color:inherit}.vrow__txt{white-space:normal}.vrow__txt.is-ticking{-webkit-mask-image:none;mask-image:none}.vrow__txt.is-ticking .vtick{animation:none}.vtick>span[aria-hidden]{display:none}}
1391
+
1392
+ /* notice — designed, non-apologetic system notes inside the thread (limits, pauses) */
1393
+ .qnotice{margin:12px 0;padding:13px 15px;border:1px dashed var(--border-strong);border-radius:var(--radius-sm);background:var(--bg-surface);font-family:var(--font-ui);font-size:calc(11.5px * var(--text-scale, 1));line-height:1.7;color:var(--text-secondary);text-align:center}
1394
+ .qnotice a,.qnotice button{color:var(--color-signal);background:none;border:0;padding:0;font:inherit;cursor:pointer;font-weight:600}
1395
+ .qnotice a:hover,.qnotice button:hover{color:var(--color-highlight)}
1396
+
1397
+ /* answer link — "walk this in the graph →" */
1398
+ .qlink{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));display:inline-block;margin-top:7px}
1399
+
1400
+ /* thinking cursor — shown while an answer is pending */
1401
+ .qcursor{display:inline-block;color:var(--color-signal);animation:qc-blink 1s steps(2) infinite}
1402
+ @keyframes qc-blink{50%{opacity:0}}
1403
+ @media (prefers-reduced-motion:reduce){.qcursor{animation:none}}
1404
+
1405
+ /* shipped badges reused inside the QuBrain components (facet tags, "superseded")
1406
+ follow the same text scale as the text around them */
1407
+ .claim .badge,.epanel .badge{font-size:calc(11px * var(--text-scale, 1))}
package/graph.css ADDED
@@ -0,0 +1,103 @@
1
+ /* ============================================================
2
+ @qball-inc/tokens — graph.css (opt-in, 1.1.0)
3
+ The QuBrain graph explorer: canvas chrome, explorer frame,
4
+ glass panel/filter strip, bottom sheet, details pill.
5
+ Load order: colors-and-type.css → components.css → graph.css.
6
+ Pages without a graph never load this file.
7
+ ============================================================ */
8
+
9
+ /* ---- Dark stage (never follows the page theme) ----
10
+ Panel tier on the whole organism (panel, filter bar, pill and
11
+ everything inside them, incl. ClaimCards / SourceRows), then the
12
+ canvas tier on the canvas itself. Selectors out-rank any
13
+ [data-theme] attribute inside the explorer. */
14
+ .gx,.gx [data-theme]{
15
+ --bg-primary:var(--stage-panel-bg);--bg-surface:var(--stage-panel-surface);
16
+ --text-primary:var(--stage-panel-text-primary);--text-secondary:var(--stage-panel-text-secondary);--text-muted:var(--stage-panel-text-muted);
17
+ --border-default:var(--stage-panel-border);--border-strong:var(--stage-panel-border-strong);
18
+ --color-signal:var(--stage-signal);--color-highlight:var(--stage-highlight);--signal-bg:var(--stage-signal-bg);--highlight-bg:var(--stage-highlight-bg);
19
+ --data-up:var(--stage-data-up);--data-down:var(--stage-data-down);--data-warn:var(--stage-data-warn);--data-info:var(--stage-data-info);--data-flat:var(--stage-data-flat);
20
+ --data-up-bg:var(--stage-data-up-bg);--data-down-bg:var(--stage-data-down-bg);--data-warn-bg:var(--stage-data-warn-bg);--data-info-bg:var(--stage-data-info-bg);
21
+ --anno-source:var(--stage-anno-source);--anno-source-bg:var(--stage-anno-source-bg);
22
+ color-scheme:dark;
23
+ }
24
+ .graphcanvas,.graphcanvas[data-theme],.gx .graphcanvas,.gx .graphcanvas[data-theme]{
25
+ --bg-primary:var(--stage-bg);--bg-surface:var(--stage-surface);
26
+ --text-primary:var(--stage-text-primary);--text-secondary:var(--stage-text-secondary);--text-muted:var(--stage-text-muted);
27
+ --border-default:var(--stage-border);--border-strong:var(--stage-border-strong);
28
+ --color-signal:var(--stage-signal);--color-highlight:var(--stage-highlight);--signal-bg:var(--stage-signal-bg);--highlight-bg:var(--stage-highlight-bg);
29
+ --data-up:var(--stage-data-up);--data-down:var(--stage-data-down);--data-warn:var(--stage-data-warn);--data-info:var(--stage-data-info);--data-flat:var(--stage-data-flat);
30
+ --anno-source:var(--stage-anno-source);--anno-source-bg:var(--stage-anno-source-bg);
31
+ color-scheme:dark;
32
+ }
33
+
34
+ /* ============================================================
35
+ GraphCanvas — QuBrain 3D knowledge-graph explorer
36
+ Dark-only by ruling: the stage below pins the palette, so it
37
+ renders identically inside a light or dark page.
38
+ Behavior: @qball-inc/elements graph.
39
+ ============================================================ */
40
+ .graphcanvas{position:relative;overflow:hidden;background:var(--bg-primary);border:1px solid var(--border-strong);border-radius:var(--radius-md);font-family:var(--font-ui)}
41
+ .graphcanvas .gc-canvas{position:relative;z-index:1;display:block}
42
+ .graphcanvas .gc-labels{position:absolute;inset:0;overflow:hidden;pointer-events:none;z-index:2;font-family:var(--font-ui)}
43
+ .graphcanvas .gc-hud{position:absolute;left:0;right:0;bottom:0;z-index:3;display:flex;justify-content:space-between;align-items:flex-end;gap:16px;padding:12px 16px;pointer-events:none}
44
+ .graphcanvas .gc-status{font-size:calc(11px * var(--text-scale, 1));color:var(--text-muted);letter-spacing:.4px;max-width:45%}
45
+ .graphcanvas .gc-hint{font-size:calc(10.5px * var(--text-scale, 1));color:var(--text-muted);text-align:right;max-width:50%}
46
+ .graphcanvas .gc-chip{position:absolute;left:16px;bottom:40px;z-index:4;max-width:min(480px,80%);background:var(--bg-surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);padding:10px 12px;font-size:calc(12px * var(--text-scale, 1));color:var(--text-secondary)}
47
+ .graphcanvas .gc-chip b{color:var(--text-primary);font-weight:600}
48
+ .graphcanvas .gc-cls{color:var(--color-signal);font-size:calc(10.5px * var(--text-scale, 1));text-transform:uppercase;letter-spacing:.8px}
49
+ .graphcanvas .gc-chip button{font-family:var(--font-ui);font-size:calc(10.5px * var(--text-scale, 1));border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:transparent;color:var(--color-signal);padding:2px 8px;cursor:pointer;margin-left:6px}
50
+ .graphcanvas .gc-chip button:hover{background:var(--signal-bg)}
51
+ .graphcanvas .gc-hover{position:absolute;z-index:5;background:var(--bg-surface);border:1px solid var(--border-strong);border-radius:var(--radius-sm);padding:4px 8px;font-size:calc(11px * var(--text-scale, 1));color:var(--text-primary);pointer-events:none}
52
+ .graphcanvas .gc-lgwrap{position:absolute;right:16px;bottom:40px;z-index:3;display:flex;flex-direction:column;align-items:flex-end;gap:6px}
53
+ .graphcanvas .gc-legend{display:flex;flex-direction:column;gap:5px;background:color-mix(in srgb, var(--bg-primary) 72%, transparent);border:1px solid var(--border-strong);border-radius:var(--radius-md);padding:10px 12px}
54
+ .graphcanvas .gc-legend.is-collapsed{display:none}
55
+ .graphcanvas .gc-lgbtn{font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:.6px;text-transform:uppercase;border:1px solid var(--border-strong);border-radius:var(--radius-sm);background:color-mix(in srgb, var(--bg-primary) 72%, transparent);color:var(--text-secondary);padding:4px 8px;cursor:pointer}
56
+ .graphcanvas .gc-lgbtn:hover{color:var(--color-signal);border-color:var(--color-signal)}
57
+ @media (max-width:640px){.graphcanvas .gc-lgwrap{bottom:72px}}
58
+ .graphcanvas .gc-li{display:flex;align-items:center;gap:8px;font-size:calc(10.5px * var(--text-scale, 1));letter-spacing:.5px;color:var(--text-secondary)}
59
+ .graphcanvas .gc-sw{width:9px;height:9px;border-radius:50%}
60
+ .graphcanvas .gc-note{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:4;background:var(--bg-surface);border:1px solid var(--border-strong);border-radius:var(--radius-md);padding:12px 18px;font-size:calc(12.5px * var(--text-scale, 1));color:var(--text-secondary)}
61
+ .graphcanvas .gc-error{position:absolute;inset:0;z-index:6;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:var(--bg-primary);color:var(--text-secondary);font-size:calc(13px * var(--text-scale, 1))}
62
+
63
+
64
+ /* ---- GraphExplorer: the assembled organism (canvas full-bleed, panel as hideable overlay;
65
+ ≤900px the panel becomes a near-full bottom sheet and the pill names the entity) ---- */
66
+ .gx{position:relative;isolation:isolate;height:100%;min-height:480px;border:1px solid var(--border-strong);border-radius:var(--radius-md);overflow:hidden;background:var(--bg-primary)}
67
+ .gx__stage{position:absolute;inset:0;min-width:0}
68
+ .gx__stage .graphcanvas{position:absolute;inset:0;border:0;border-radius:0}
69
+ .gx .gc-lgwrap{right:auto;left:16px;align-items:flex-start}
70
+ .gx__panel{position:absolute;top:44px;right:12px;bottom:42px;width:400px;max-width:calc(100% - 24px);z-index:8;display:flex;background:color-mix(in srgb,var(--stage-bg) 88%,transparent);backdrop-filter:blur(8px);border:1px solid var(--stage-panel-border-strong);border-radius:var(--radius-md);overflow:hidden;transition:transform var(--dur-base) var(--ease-out),opacity var(--dur-base) var(--ease-out)}
71
+ .gx__panel .epanel{flex:1;min-width:0;background:transparent}
72
+ .gx__panel.is-hidden{transform:translateX(calc(100% + 24px));opacity:0;pointer-events:none}
73
+ .gx__pshow{position:absolute;top:44px;right:12px;z-index:8;font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:.6px;text-transform:uppercase;padding:6px 10px;border:1px solid var(--stage-panel-border-strong);border-radius:var(--radius-sm);background:color-mix(in srgb,var(--stage-bg) 88%,transparent);backdrop-filter:blur(8px);color:var(--stage-text-muted);cursor:pointer}
74
+ .gx__pshow:hover{color:var(--stage-signal);border-color:var(--stage-signal)}
75
+ .gx__pshow b{color:var(--stage-signal);font-weight:600;margin-left:6px;text-transform:none;letter-spacing:0;display:inline-block;max-width:44vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
76
+ .gx__phide{border:0;background:none;font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:.6px;text-transform:uppercase;color:var(--text-muted);cursor:pointer;padding:2px 0;align-self:flex-start;white-space:nowrap}
77
+ .gx__phide:hover{color:var(--color-signal)}
78
+ .gx__facets{position:absolute;top:0;left:0;right:0;z-index:9;padding:7px 14px;background:color-mix(in srgb,var(--stage-bg) 92%,transparent);backdrop-filter:blur(6px);border-bottom:1px solid var(--stage-panel-divider);display:flex;align-items:center;gap:10px}
79
+ .gx:has(.gx__panel:not(.is-hidden)) .gx__facets{right:424px;border-right:1px solid var(--stage-panel-divider)}
80
+ .gx .gx__facets.is-collapsed,.gx:has(.gx__panel:not(.is-hidden)) .gx__facets.is-collapsed{right:auto;width:auto;border-right:1px solid var(--stage-panel-divider);border-bottom-right-radius:var(--radius-md)}
81
+ .gx__facets .facetbar{flex:1;min-width:0;gap:4px 14px}
82
+ .gx__facets.is-collapsed .facetbar{display:none}
83
+ .gx__ftoggle{font-family:var(--font-ui);font-size:calc(10px * var(--text-scale, 1));letter-spacing:.6px;text-transform:uppercase;border:0;background:none;color:var(--text-muted);cursor:pointer;padding:3px 0;white-space:nowrap}
84
+ .gx__ftoggle:hover{color:var(--color-signal)}
85
+ .gx__ftoggle b{color:var(--color-signal);font-weight:600}
86
+ .gx__facets .fchip{font-size:calc(9.5px * var(--text-scale, 1));padding:2px 7px}
87
+ .gx__facets .facetbar__dom{font-size:calc(9px * var(--text-scale, 1))}
88
+ .gx .epanel{min-width:0}
89
+ @media (max-width:900px){
90
+ .gx__panel{left:12px;right:12px;width:auto;top:44px;bottom:12px;max-height:none}
91
+ .gx__panel.is-hidden{transform:translateY(calc(100% + 24px))}
92
+ .gx:has(.gx__panel:not(.is-hidden)) .gx__facets{right:0;border-right:0}
93
+ }
94
+
95
+
96
+ /* ---- QuBae launcher over the stage (opt-in modifier) ----
97
+ The launcher floats bare; over the dark canvas it borrows the stage ink. */
98
+ .qlaunch--on-stage{color:var(--stage-mark)}
99
+ .qlaunch--on-stage:hover{color:var(--stage-signal)}
100
+ .qlaunch--on-stage .qlaunch__cap{color:var(--stage-text-muted)}
101
+ .qlaunch--on-stage .keycap{background:var(--stage-surface);color:var(--stage-text-secondary);border-color:var(--stage-border-strong)}
102
+
103
+ @media (prefers-reduced-motion:reduce){.gx__panel{transition:none}.gx__panel.is-hidden{transform:none}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qball-inc/tokens",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "QBall Design System tokens — framework-agnostic CSS custom properties, component classes, and a DTCG/Style-Dictionary JSON mirror. Zero build step; public default display face is Fira Code (Berkeley Mono restored per README in private builds).",
5
5
  "keywords": [
6
6
  "design-tokens",
@@ -15,6 +15,14 @@
15
15
  "monospace"
16
16
  ],
17
17
  "license": "Apache-2.0",
18
+ "author": "QBall Inc",
19
+ "homepage": "https://qball-inc.github.io/qball-design-system/",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/QBall-Inc/qball-design-system.git",
23
+ "directory": "packages/tokens"
24
+ },
25
+ "bugs": "https://github.com/QBall-Inc/qball-design-system/issues",
18
26
  "private": false,
19
27
  "publishConfig": {
20
28
  "access": "public"
@@ -25,12 +33,14 @@
25
33
  "./theme.css": "./theme.css",
26
34
  "./colors-and-type.css": "./colors_and_type.css",
27
35
  "./components.css": "./components.css",
36
+ "./graph.css": "./graph.css",
28
37
  "./tokens.json": "./tokens.json"
29
38
  },
30
39
  "files": [
31
40
  "theme.css",
32
41
  "colors_and_type.css",
33
42
  "components.css",
43
+ "graph.css",
34
44
  "tokens.json"
35
45
  ]
36
46
  }
package/tokens.json CHANGED
@@ -64,6 +64,46 @@
64
64
  "source": { "$type": "color", "light": "#4E6577", "dark": "#93A7B5" },
65
65
  "source-bg": { "$type": "color", "light": "rgba(78,101,119,0.12)", "dark": "rgba(147,167,181,0.16)" }
66
66
  },
67
+ "stage": {
68
+ "$description": "QuBrain graph explorer dark stage — theme-INDEPENDENT (the explorer never follows the page theme). Consumed only by graph.css, which maps the ordinary tokens onto these inside the explorer. Two tiers: canvas (deep ink + brighter labels) and panel (entity panel, filter bar, details pill).",
69
+ "bg": { "$type": "color", "$value": "#12161F", "$description": "canvas deep-ink stage" },
70
+ "surface": { "$type": "color", "$value": "#1A1F2B" },
71
+ "text-primary": { "$type": "color", "$value": "#EDE8E1" },
72
+ "text-secondary": { "$type": "color", "$value": "#D6D1C8" },
73
+ "text-muted": { "$type": "color", "$value": "#A8A29E" },
74
+ "border": { "$type": "color", "$value": "rgba(255,255,255,0.06)" },
75
+ "border-strong": { "$type": "color", "$value": "rgba(255,255,255,0.25)" },
76
+ "panel-bg": { "$type": "color", "$value": "#1E1D1B" },
77
+ "panel-surface": { "$type": "color", "$value": "#2A2826" },
78
+ "panel-text-primary": { "$type": "color", "$value": "#E7E0D6" },
79
+ "panel-text-secondary": { "$type": "color", "$value": "#CDC6BB" },
80
+ "panel-text-muted": { "$type": "color", "$value": "#8A847D" },
81
+ "panel-border": { "$type": "color", "$value": "rgba(255,255,255,0.06)" },
82
+ "panel-border-strong": { "$type": "color", "$value": "rgba(255,255,255,0.14)" },
83
+ "panel-divider": { "$type": "color", "$value": "rgba(255,255,255,0.07)", "$description": "glass filter-strip hairline" },
84
+ "mark": { "$type": "color", "$value": "#E7E2DA", "$description": "QuBae launcher mascot ink over the stage" },
85
+ "signal": { "$type": "color", "$value": "#5B9E87" },
86
+ "highlight": { "$type": "color", "$value": "#D97706" },
87
+ "signal-bg": { "$type": "color", "$value": "rgba(91,158,135,0.15)" },
88
+ "highlight-bg": { "$type": "color", "$value": "rgba(217,119,6,0.15)" },
89
+ "data-up": { "$type": "color", "$value": "#4FB07A" },
90
+ "data-down": { "$type": "color", "$value": "#E2705F" },
91
+ "data-warn": { "$type": "color", "$value": "#D9B43C" },
92
+ "data-info": { "$type": "color", "$value": "#5B9BD6" },
93
+ "data-flat": { "$type": "color", "$value": "#A8A29E" },
94
+ "data-up-bg": { "$type": "color", "$value": "rgba(79,176,122,0.15)" },
95
+ "data-down-bg": { "$type": "color", "$value": "rgba(226,112,95,0.15)" },
96
+ "data-warn-bg": { "$type": "color", "$value": "rgba(217,180,60,0.16)" },
97
+ "data-info-bg": { "$type": "color", "$value": "rgba(91,155,214,0.15)" },
98
+ "anno-source": { "$type": "color", "$value": "#93A7B5" },
99
+ "anno-source-bg": { "$type": "color", "$value": "rgba(147,167,181,0.16)" }
100
+ },
101
+ "scrim": {
102
+ "light": { "$type": "color", "$value": "rgba(20,20,20,0.22)", "$description": "QuBae chat overlay scrim — dims the page less than a modal (--color-scrim-light)" }
103
+ },
104
+ "scale": {
105
+ "text": { "$type": "number", "$value": 1, "$description": "--text-scale: multiplies QuBrain/QuBae component text sizes; 1 = as designed. Consumers stepping type up on wide screens set it to match (e.g. 1.25 at min-width 1600px)." }
106
+ },
67
107
  "radius": {
68
108
  "sm": { "$type": "dimension", "$value": "4px" },
69
109
  "md": { "$type": "dimension", "$value": "8px" },