@prplkane/roundtable 0.0.0-stage → 0.6.3

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +513 -0
  2. package/LICENSE +21 -0
  3. package/README.md +188 -3
  4. package/SECURITY.md +299 -0
  5. package/docs/workflow.md +1325 -0
  6. package/package.json +52 -6
  7. package/scripts/agent.mjs +40 -0
  8. package/scripts/export.mjs +20 -0
  9. package/scripts/mcp.mjs +175 -0
  10. package/scripts/run-debate.mjs +70 -0
  11. package/scripts/server.mjs +28 -0
  12. package/scripts/setup.mjs +182 -0
  13. package/skills/roundtable/SKILL.md +55 -0
  14. package/src/adapters/agy.js +7 -0
  15. package/src/adapters/catalogue.js +49 -0
  16. package/src/adapters/claude.js +6 -0
  17. package/src/adapters/codex.js +6 -0
  18. package/src/adapters/common.js +304 -0
  19. package/src/adapters/config.js +432 -0
  20. package/src/adapters/endpoint.js +178 -0
  21. package/src/adapters/errors.js +69 -0
  22. package/src/adapters/index.js +11 -0
  23. package/src/adapters/models.js +106 -0
  24. package/src/adapters/quota.js +305 -0
  25. package/src/adapters/spawn.js +178 -0
  26. package/src/agent-client.js +108 -0
  27. package/src/cli.js +44 -0
  28. package/src/contract.js +256 -0
  29. package/src/diagnostics.js +133 -0
  30. package/src/doctor.js +96 -0
  31. package/src/engine.js +902 -0
  32. package/src/estimate.js +331 -0
  33. package/src/export.js +307 -0
  34. package/src/fake.js +75 -0
  35. package/src/folder-picker.js +46 -0
  36. package/src/history.js +220 -0
  37. package/src/local-http.js +39 -0
  38. package/src/local-server.js +82 -0
  39. package/src/notes.js +16 -0
  40. package/src/personas.js +49 -0
  41. package/src/preflight.js +126 -0
  42. package/src/progress.js +30 -0
  43. package/src/prompts.js +278 -0
  44. package/src/research.js +113 -0
  45. package/src/review-view.js +157 -0
  46. package/src/seats.js +272 -0
  47. package/src/server.js +913 -0
  48. package/src/settings.js +27 -0
  49. package/src/setup-toml.js +124 -0
  50. package/src/snapshot.js +93 -0
  51. package/src/store.js +303 -0
  52. package/src/terminal.js +53 -0
  53. package/src/terms.js +52 -0
  54. package/src/ui/app.js +1967 -0
  55. package/src/ui/avatars.js +132 -0
  56. package/src/ui/ceremony.js +87 -0
  57. package/src/ui/design/app.css +714 -0
  58. package/src/ui/design/preset-dusk.css +91 -0
  59. package/src/ui/design/tokens.css +129 -0
  60. package/src/ui/diagnostics.js +61 -0
  61. package/src/ui/help.js +122 -0
  62. package/src/ui/icons.js +64 -0
  63. package/src/ui/index.html +272 -0
  64. package/src/ui/loader.js +73 -0
  65. package/src/ui/logo.svg +4 -0
  66. package/src/ui/scan.js +57 -0
  67. package/src/ui/scribe.js +64 -0
  68. package/src/ui/sound.js +80 -0
  69. package/src/validate.js +112 -0
  70. package/src/version.js +5 -0
@@ -0,0 +1,714 @@
1
+ /* Roundtable app.css: per-app knobs plus page layout. Loads after tokens.css and preset-dusk.css
2
+ (the Dusk preset: Ink & paper with purple instead of blue; its accent is Roundtable's, so no
3
+ accent knob is set here). Seat colours are the family accents, checked at >= 5.3:1 on plum
4
+ paper and >= 5.4:1 on night plum; the chairman's is the chrome plum. */
5
+
6
+ :root {
7
+ --knob-density: 1;
8
+ --seat-rust: #b0412c;
9
+ --seat-olive: #4a7326;
10
+ --seat-teal: #1f6f66;
11
+ --seat-dusk: #84489a;
12
+ --seat-steel: #2f6590;
13
+ --seat-ink: #5b3478;
14
+ }
15
+ /* Plum paper, tuned for this app. The preset's cream and its near-equal surfaces read as another
16
+ product beside night plum: here paper takes night's structure, three clear tonal steps (page,
17
+ panel, raised field) on a faint plum paper, controls with a border that reads, seat hues that
18
+ match night's while keeping text contrast (each >= 4.7:1 on every surface), softer position
19
+ tints and a lighter overlay shadow. */
20
+ :root, :root[data-theme="paper"] {
21
+ --color-bg: #f3eff2;
22
+ --color-surface: #fbf9fb;
23
+ --color-surface-raised: #ffffff;
24
+ --color-border: #ded5dd;
25
+ --color-selection: #efe6f2;
26
+ --color-control: #c4b7c6;
27
+ --tint: 4%;
28
+ --shadow-overlay: 5px 5px 0 #d6cad8;
29
+ }
30
+ :root[data-theme="night"] {
31
+ --seat-rust: #df6b55;
32
+ --seat-olive: #9cbc6a;
33
+ --seat-teal: #6fb3a9;
34
+ --seat-dusk: #c79ad0;
35
+ --seat-steel: #86a9c4;
36
+ --seat-ink: #c3b3cc;
37
+ --color-control: var(--color-border);
38
+ --tint: 7%;
39
+ }
40
+
41
+ * { box-sizing: border-box; }
42
+ body { margin: 0; background: var(--color-bg); color: var(--color-text); font: var(--text-base)/var(--leading-base) var(--font-sans); }
43
+ .mono { font-family: var(--font-mono); }
44
+ .label { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); }
45
+ [hidden] { display: none !important; }
46
+
47
+ .app { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto; min-height: 100vh; }
48
+
49
+ /* Header (brand layer) */
50
+ .header { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-4); background: var(--color-chrome); color: var(--color-chrome-text); font: var(--weight-strong) var(--text-sm) var(--font-mono); letter-spacing: var(--tracking-label); box-shadow: inset 0 -3px 0 var(--color-action), inset 0 -6px 0 var(--color-chrome-accent); padding-bottom: calc(var(--space-2) + 6px); }
51
+ .logo { width: 18px; height: 18px; }
52
+ .logo .tile { fill: var(--color-chrome-accent); }
53
+ /* the one blinking element in the brand layer: a block cursor after the wordmark */
54
+ .cursor { display: inline-block; width: 7px; height: 13px; background: var(--color-chrome-accent); vertical-align: -2px; animation: blink var(--cursor-blink); }
55
+ .logo .ink { fill: var(--color-chrome); }
56
+ @keyframes blink { 50% { opacity: 0; } }
57
+ .header .meta { margin-left: auto; display: flex; gap: var(--space-3); align-items: center; font-weight: var(--weight-regular); color: var(--color-chrome-muted); font-size: var(--text-xs); }
58
+ .header .btn { background: transparent; color: var(--color-chrome-text); border-color: var(--color-chrome-muted); }
59
+ .header { flex-wrap: wrap; }
60
+ .wordmark { white-space: nowrap; }
61
+ .run-mode { border: 1px solid currentColor; padding: 1px var(--space-2); font-size: var(--text-xs); text-transform: uppercase; }
62
+ .run-mode.demo { color: var(--color-chrome-accent); }
63
+ .mode-note { margin: 0; color: var(--color-text-muted); font-size: var(--text-sm); }
64
+ .local-data { color: var(--color-text-muted); font-size: var(--text-sm); }
65
+ .local-data summary { cursor: pointer; }
66
+ .local-data code { overflow-wrap: anywhere; }
67
+
68
+ .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
69
+ .field-label { display: inline-flex; gap: 4px; align-items: center; min-height: 24px; white-space: nowrap; }
70
+ .help-label { width: fit-content; min-height: 24px; display: inline-flex; align-items: center; cursor: help; transition: color 160ms; }
71
+ .help-label:hover { color: var(--color-action); }
72
+ .help-label:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; border-radius: 2px; }
73
+ .help-popover { position: fixed; z-index: 100; width: min(320px, calc(100vw - 24px)); padding: 12px 14px; border: 1px solid var(--color-border-strong); border-radius: 6px; background: var(--color-surface-raised); color: var(--color-text); box-shadow: 0 6px 22px #24152d24; font: var(--text-sm)/1.5 var(--font-sans); opacity: 0; visibility: hidden; pointer-events: none; transform: translateY(4px); transition: opacity 180ms ease, transform 180ms ease, visibility 180ms; }
74
+ .help-popover.is-open { opacity: 1; visibility: visible; pointer-events: auto; transform: translateY(0); }
75
+ .help-popover strong { font-size: var(--text-sm); }
76
+ .help-popover p { margin: 5px 0 0; }
77
+ .text-reveal-word { animation: text-reveal 260ms ease-out both; }
78
+ @keyframes text-reveal { from { opacity: 0; text-shadow: 0 0 9px var(--color-focus); } 55% { opacity: 1; text-shadow: 0 0 5px color-mix(in srgb, var(--color-focus) 28%, transparent); } to { opacity: 1; text-shadow: none; } }
79
+ .seat-card.seat-invalid { border-color: var(--color-danger); }
80
+ .seat-card .flat[aria-invalid="true"] { border-color: var(--color-danger); border-style: solid; }
81
+ .seat-field-error { margin: 2px 0 5px; }
82
+ .reply-text { display: contents; }
83
+ /* Session cue (brand layer): a pixel gavel strikes once at open and once at the end. */
84
+ .session-ceremony { --cue: var(--color-accent); position: fixed; z-index: 90; top: 68px; left: 50%; width: min(360px, calc(100vw - 32px)); pointer-events: none; transform: translateX(-50%); }
85
+ .session-ceremony[data-phase="verdict"] { --cue: var(--color-ok); }
86
+ .session-ceremony[data-phase="ended"] { --cue: var(--color-border-strong); }
87
+ .session-ceremony[data-phase="failed"] { --cue: var(--color-danger); }
88
+ .ceremony-card { display: flex; align-items: center; gap: 14px; padding: 12px 16px; background: var(--color-surface-raised); border: 2px solid var(--color-border-strong); border-top: 4px solid var(--cue); border-radius: 2px; box-shadow: var(--shadow-overlay); }
89
+ .ceremony-art { width: 60px; height: 72.5px; flex: none; overflow: visible; }
90
+ .ceremony-block { fill: var(--color-text-muted); }
91
+ .ceremony-gavel { fill: var(--color-action); }
92
+ .session-ceremony[data-phase="failed"] .ceremony-gavel { fill: var(--color-text-muted); }
93
+ .ceremony-chip { fill: var(--cue); opacity: 0; }
94
+ .session-ceremony[data-phase="failed"] .ceremony-chip { fill: var(--color-text-muted); }
95
+ .ceremony-text strong { display: block; font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; }
96
+ .ceremony-text span { display: block; margin-top: 4px; font-size: var(--text-sm); color: var(--color-text-muted); }
97
+ /* The gavel's frames are swapped by ceremony.js; steps() keeps the rest chunky. Delays match HIT_MS. */
98
+ .session-ceremony.is-playing { animation: ceremony-notice 2000ms steps(2, jump-end) both; }
99
+ .session-ceremony.is-playing .ceremony-chip { animation: ceremony-chip 460ms 505ms steps(5, jump-end) forwards; }
100
+ .session-ceremony.is-playing:not([data-phase="open"]) .ceremony-card { animation: ceremony-shake 140ms 505ms steps(1, jump-end) forwards; }
101
+ .session-ceremony.is-playing[data-phase="failed"] .ceremony-card { animation-name: ceremony-thud; }
102
+ @keyframes ceremony-notice { 0% { opacity: 0; transform: translate(-50%, -4px); } 6%, 90% { opacity: 1; transform: translate(-50%, 0); } 100% { opacity: 0; transform: translate(-50%, -2px); } }
103
+ @keyframes ceremony-chip { 0% { opacity: 1; transform: none; } 55% { opacity: 1; transform: translate(var(--dx), var(--dy)); } 100% { opacity: 0; transform: translate(calc(var(--dx) * 1.3), calc(var(--dy) + 3px)); } }
104
+ @keyframes ceremony-shake { 0% { transform: translateX(1px); } 30% { transform: translateX(-1px); } 60% { transform: translateX(1px); } 100% { transform: none; } }
105
+ @keyframes ceremony-thud { 0% { transform: translateY(1px); } 100% { transform: none; } }
106
+ @media (prefers-reduced-motion: reduce) {
107
+ .session-ceremony.is-playing, .session-ceremony.is-playing * { animation: none !important; } /* a still card; sound follows its own toggle */
108
+ .help-popover, .help-label { transition: none; transform: none; }
109
+ .text-reveal-word { animation: none !important; opacity: 1; text-shadow: none; }
110
+ .cursor, .led-thinking { animation: none; }
111
+ .switch, .switch::after { transition: none; }
112
+ .card .reply-more { animation: none !important; } /* the tokens are 0 here as well; a card opens and folds at once */
113
+ }
114
+
115
+ html { scroll-padding-bottom: calc(var(--board-bar-height, 0px) + 52px); }
116
+ main { padding: var(--space-5); padding-bottom: max(120px, calc(var(--board-bar-height, 0px) + 52px)); display: flex; flex-direction: column; gap: var(--space-5); max-width: 1100px; width: 100%; margin: 0 auto; }
117
+ main, .humanbar { overflow-wrap: anywhere; }
118
+ .screen { display: flex; flex-direction: column; gap: var(--space-5); }
119
+ h1 { margin: 0; font-size: var(--text-xl); line-height: var(--leading-tight); }
120
+ .lede { margin: var(--space-1) 0 0; color: var(--color-text-muted); }
121
+
122
+ /* Panels */
123
+ .panel { background: var(--color-surface); border: var(--border-width) solid var(--color-border); border-radius: var(--radius); }
124
+ .panel-title { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-2) var(--space-3); font-weight: var(--weight-strong); border-bottom: var(--border-width) solid var(--color-border); }
125
+
126
+ /* Tables */
127
+ table { width: 100%; border-collapse: collapse; }
128
+ th { text-align: left; padding: var(--space-1) var(--space-3); border-bottom: var(--border-width) solid var(--color-border); }
129
+ td { padding: var(--space-2) var(--space-3); border-bottom: var(--border-width) solid var(--color-border); vertical-align: middle; }
130
+ tr:last-child td { border-bottom: 0; }
131
+ td.data, .data { font: var(--text-sm) var(--font-mono); font-variant-numeric: tabular-nums; color: var(--color-text-muted); white-space: nowrap; }
132
+ tr.total td { font-weight: var(--weight-strong); color: var(--color-text); border-top: var(--border-width) solid var(--color-border-strong); }
133
+ .status { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); display: inline-flex; align-items: center; gap: 6px; text-transform: uppercase; }
134
+ .status::before { content: ""; width: var(--led-size); height: var(--led-size); background: currentColor; }
135
+ .ok { color: var(--color-ok); } .warn { color: var(--color-warn); } .danger { color: var(--color-danger); } .info { color: var(--color-info); } .muted { color: var(--color-text-muted); }
136
+
137
+ /* Buttons and forms */
138
+ .row { display: flex; gap: var(--space-2); flex-wrap: wrap; align-items: center; justify-content: flex-end; }
139
+ .btn { font: var(--weight-strong) var(--text-sm) var(--font-sans); padding: var(--space-1) var(--space-3); min-height: 32px; border-radius: var(--radius-sm); border: var(--border-width) solid var(--color-control); background: var(--color-surface); color: var(--color-text); cursor: pointer; }
140
+ .btn-small { min-height: 24px; padding: 0 var(--space-2); font-size: var(--text-xs); }
141
+ .btn:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible, summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
142
+ .btn:active { transform: translateY(1px); box-shadow: none; }
143
+ .btn-primary { background: var(--color-action); border-color: var(--color-action); color: var(--color-on-action); box-shadow: var(--shadow-hard-action); }
144
+ .btn-danger { color: var(--color-danger); border-color: var(--color-danger); padding-left: calc(var(--space-3) + 6px); background-image: var(--pattern-hazard); background-size: 6px 100%; background-repeat: no-repeat; }
145
+ .btn[disabled] { opacity: 0.5; cursor: default; }
146
+
147
+ .fields { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); padding: var(--space-3); }
148
+ .fields-row { grid-template-columns: 2fr 1fr 1fr 1fr; }
149
+ .field { display: flex; flex-direction: column; gap: var(--space-1); }
150
+ .field.wide { grid-column: 1 / -1; }
151
+ input, textarea, select { font: var(--text-base) var(--font-sans); padding: var(--space-2); background: var(--color-surface-raised); color: var(--color-text); border: var(--border-width) solid var(--color-control); border-radius: var(--radius-sm); width: 100%; }
152
+ textarea { resize: vertical; }
153
+ input[aria-invalid="true"] { border-color: var(--color-danger); }
154
+ .hint { font-size: var(--text-sm); color: var(--color-text-muted); }
155
+ .error { font-size: var(--text-sm); color: var(--color-danger); margin-right: auto; }
156
+ #seats td input, #seats td select { padding: var(--space-1) var(--space-2); font-size: var(--text-sm); }
157
+ #seats td:first-child { width: 72px; } #seats td:first-child input { width: auto; }
158
+ /* Seat mark: a short bar in the seat colour, the same shape as a card's left edge. Squares mean state only. */
159
+ .swatch, td .seat-dot { content: ""; display: inline-block; width: 4px; height: 14px; background: var(--seat); flex: none; }
160
+ td .seat-dot { margin-right: var(--space-2); vertical-align: -2px; }
161
+
162
+ /* Empty state (brand layer) */
163
+ .empty { font: var(--text-sm)/1.7 var(--font-mono); color: var(--color-text-muted); border: var(--border-width) dashed var(--color-border); border-radius: var(--radius); padding: var(--space-3) var(--space-4); display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
164
+ .empty .prompt { color: var(--color-accent); font-weight: var(--weight-strong); }
165
+
166
+ /* Board */
167
+ .rounds { display: flex; flex-direction: column; gap: var(--space-4); }
168
+ .round { background: var(--color-surface); border: var(--border-width) solid var(--color-border); border-radius: var(--radius); }
169
+ .round[open] { box-shadow: var(--shadow-hard); }
170
+ .round summary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); cursor: pointer; font-weight: var(--weight-strong); list-style: none; }
171
+ .round summary::-webkit-details-marker { display: none; }
172
+ .round summary .tally { font-weight: var(--weight-regular); color: var(--color-text-muted); font-size: var(--text-sm); }
173
+ /* The option columns have a grid of their own: a full-width item in the same grid (the thinking
174
+ strip, a note) would keep every unused column alive, leaving a blank column beside two options. */
175
+ .groups { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); border-top: var(--border-width) solid var(--color-border); }
176
+ .columns { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--space-3); }
177
+ .group { border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius); padding: var(--space-2); display: flex; flex-direction: column; gap: var(--space-2); background: var(--color-bg); }
178
+ .group-title { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; display: flex; flex-wrap: wrap; gap: var(--space-1); justify-content: space-between; padding: 0 var(--space-1); }
179
+ .group-title .count { color: var(--color-text-muted); }
180
+ .group.span { grid-column: 1 / -1; }
181
+ .group.empty { border-style: dashed; }
182
+ .group.empty .group-title .count { font-weight: var(--weight-regular); text-transform: none; letter-spacing: 0; }
183
+ .group.thinking .cards { flex-direction: row; flex-wrap: wrap; }
184
+ .group.thinking .card { flex: 1 1 220px; }
185
+ .cards { display: flex; flex-direction: column; gap: var(--space-2); }
186
+
187
+ .card { background: var(--color-surface); border: var(--border-width) solid var(--color-border); border-left: 4px solid var(--seat); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); transition: background-color 0.5s ease; }
188
+ .card-head { display: flex; align-items: baseline; gap: var(--space-2); flex-wrap: wrap; }
189
+ .card-head .vendor { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--seat); display: inline-flex; align-items: center; gap: 6px; }
190
+ .card-head .lens { font-weight: var(--weight-strong); }
191
+ .card-head .flags { margin-left: auto; display: flex; gap: var(--space-2); }
192
+ .card dl { margin: 0; display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-3); font-size: var(--text-sm); }
193
+ .card dt { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); padding-top: 2px; }
194
+ .card dd { margin: 0; }
195
+ .card dd ul { margin: 0; padding-left: 1.1em; }
196
+ .card .question { border: var(--border-width) solid var(--color-warn); border-radius: var(--radius-sm); padding: var(--space-1) var(--space-2); font-size: var(--text-sm); }
197
+ .card .question b { color: var(--color-warn); font-family: var(--font-mono); font-size: var(--text-xs); letter-spacing: var(--tracking-label); }
198
+ .card .question summary { padding: 5px 0; font-size: var(--text-sm); color: var(--color-warn); }
199
+ .card .question p { margin: 6px 0; }
200
+ .seat-stance { display: flex; flex-direction: column; gap: 5px; padding: 10px 0 14px; border-bottom: 2px solid var(--color-border-strong); }
201
+ .seat-stance strong { font-size: var(--text-lg); line-height: 1.35; }
202
+ .argument-section { border-left: 3px solid var(--color-border); padding: 2px 0 2px 12px; margin: 5px 0; }
203
+ .argument-section h4 { margin: 0 0 7px; font: var(--weight-strong) var(--text-xs) var(--font-mono); text-transform: uppercase; letter-spacing: var(--tracking-label); color: var(--color-text-muted); }
204
+ .argument-section ul { margin: 0; padding-left: 1.1em; font-size: var(--text-base); line-height: 1.6; }
205
+ .argument-section li + li { margin-top: 8px; }
206
+ .argument-disagree { border-color: var(--color-danger); }
207
+ .argument-disagree h4, .term-disagree { color: var(--color-danger); }
208
+ .argument-agree { border-color: var(--color-ok); }
209
+ .argument-agree h4, .term-agree { color: var(--color-ok); }
210
+ .argument-new { border-color: var(--color-info); }
211
+ .argument-assumptions { border-color: var(--color-warn); }
212
+ .led-cancelled { color: var(--color-warn); opacity: 1; }
213
+ /* The board's heading: the question large, its state a small tag beside it. No box: the
214
+ conclusion panel below is the first boxed thing, so the eye goes question, then answer. */
215
+ .review-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2) var(--space-4); padding: 0 var(--space-1); }
216
+ .review-question { margin: 0; flex: 1 1 24ch; min-width: 0; font-size: calc((var(--text-lg) + var(--text-xl)) / 2); line-height: var(--leading-tight); font-weight: var(--weight-strong); text-wrap: balance; }
217
+ .review-state { flex: none; white-space: nowrap; cursor: default; }
218
+ /* Quota as one quiet line above the board: a chip per pool, the Usage details toggle at its end */
219
+ .usage-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); padding: 0 var(--space-1); font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
220
+ .usage-summary { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); }
221
+ .quota-chip { display: inline-flex; align-items: center; gap: var(--space-2); }
222
+ .quota-chip b { color: var(--color-text); letter-spacing: var(--tracking-label); text-transform: uppercase; }
223
+ .quota-chip .quota-track { display: inline-block; width: 48px; height: 4px; margin: 0; }
224
+ /* A fold toggle that is not a <details>: its glyph has a fixed width, so the label never moves */
225
+ .fold-toggle { margin-left: auto; padding: 0; border: 0; background: none; font: inherit; letter-spacing: inherit; color: var(--color-text-muted); cursor: pointer; }
226
+ .fold-toggle::before { content: "▸"; display: inline-block; width: 2ch; }
227
+ .fold-toggle[aria-expanded="true"]::before { content: "▾"; }
228
+ .fold-toggle:hover, .fold-toggle[aria-expanded="true"] { color: var(--color-text); }
229
+
230
+ /* Header icons and the status-line link */
231
+ .btn-icon { width: 28px; padding: 0; display: inline-grid; place-items: center; }
232
+ .btn-icon svg { width: 14px; height: 14px; }
233
+ .statusline-link { background: none; border: 0; padding: 0; margin: 0; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; cursor: pointer; text-decoration: underline dotted; }
234
+ .statusline-link:hover { color: var(--color-text); }
235
+
236
+ /* A panel that folds: its title is the summary, the glyph at its end says which way it goes */
237
+ details.panel > summary { list-style: none; cursor: pointer; }
238
+ details.panel > summary::-webkit-details-marker { display: none; }
239
+ .panel-title.fold::after { content: "▾"; margin-left: auto; font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
240
+ details:not([open]) > .panel-title.fold::after { content: "▸"; }
241
+ details.panel:not([open]) > .panel-title { border-bottom: 0; }
242
+ .panel-title.fold .btn { margin-left: var(--space-2); }
243
+ .quota-track { height: 5px; margin: 7px 0; border-radius: 3px; background: var(--color-border); overflow: hidden; }
244
+ .quota-track span { display: block; height: 100%; background: currentColor; }
245
+ .decision-actions > summary { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); cursor: pointer; }
246
+ .usage-details { overflow-x: auto; margin-top: calc(-1 * var(--space-3)); }
247
+ .decision-actions > p { padding: 0 var(--space-3); margin: 0 0 var(--space-2); }
248
+ .questions-panel { scroll-margin-top: 18px; border-color: var(--color-warn); }
249
+ .questions-panel > p { margin: var(--space-3); }
250
+ #question-inputs { padding: 0 var(--space-3); display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 360px), 1fr)); gap: var(--space-3); }
251
+ .question-answer { display: flex; flex-direction: column; gap: 8px; }
252
+ .question-answer label { display: flex; flex-direction: column; gap: 6px; }
253
+ .question-answer label strong { font-size: var(--text-base); line-height: 1.5; }
254
+ .question-answer textarea { font-size: var(--text-base); }
255
+ .question-sources { font: var(--text-xs) var(--font-mono); color: var(--color-warn); display: flex; flex-wrap: wrap; align-items: center; gap: 4px var(--space-2); }
256
+ .asker { display: inline-flex; align-items: center; gap: 6px; color: var(--color-text); }
257
+ .asker .seat-dot { display: inline-block; width: 4px; height: 14px; background: var(--seat); flex: none; }
258
+ .asker .card-avatar { width: 18px; height: 18px; }
259
+ .question-actions { padding: var(--space-3); justify-content: space-between; }
260
+ .card pre { margin: 0; white-space: pre-wrap; font: var(--text-sm)/1.5 var(--font-mono); color: var(--color-text-muted); max-height: 220px; overflow: auto; }
261
+ .card.pending { opacity: 0.7; }
262
+ /* Folding: every reply starts folded to its seat and stance; a click on its head opens it, and the
263
+ glyph at the head's end says which way it goes. The head is a button for the keyboard too. */
264
+ .card[data-key] :is(.card-head, .seat-stance) { cursor: pointer; }
265
+ .card[data-key] .card-head:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; border-radius: 2px; }
266
+ .card[data-key] .card-head::after { content: "▾"; margin-left: var(--space-2); font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
267
+ .card[data-key] .card-head .flags:empty { margin-left: auto; }
268
+ .card[data-key]:is(.folded, .is-folding) .card-head::after { content: "▸"; }
269
+ .card[data-key].folded .reply-more { display: none; }
270
+ /* the stance line takes its folded form at the click, so only the body below it moves */
271
+ .card[data-key]:is(.folded, .is-folding) .seat-stance { flex-direction: row; align-items: baseline; gap: var(--space-2); padding: 2px 0 0; border-bottom: 0; }
272
+ .card[data-key]:is(.folded, .is-folding) .seat-stance strong { font-size: var(--text-base); }
273
+ /* What a folded card hides, in one grid row so its height can move between 0fr and 1fr. It
274
+ unrolls over --motion-base and rolls up over --motion-fast (app.js toggleCard); the negative
275
+ margin takes the card's gap with it, so nothing jumps when the body leaves the layout. */
276
+ .reply-more { display: grid; grid-template-rows: 1fr; }
277
+ .reply-more > div { min-height: 0; display: flex; flex-direction: column; gap: var(--space-2); }
278
+ .card:is(.is-unfolding, .is-folding) .reply-more > div { overflow: hidden; }
279
+ .card.is-unfolding .reply-more { animation: card-unfold var(--motion-base) var(--ease) var(--motion-elapsed, 0ms) both; }
280
+ .card.is-folding .reply-more { animation: card-fold var(--motion-fast) var(--ease) var(--motion-elapsed, 0ms) both; }
281
+ /* both ends spelled out: an implicit end resolves to pixels, which cannot blend with 0fr */
282
+ @keyframes card-unfold { from { grid-template-rows: 0fr; margin-top: calc(var(--space-2) * -1); } to { grid-template-rows: 1fr; margin-top: 0; } }
283
+ @keyframes card-fold { from { grid-template-rows: 1fr; margin-top: 0; } to { grid-template-rows: 0fr; margin-top: calc(var(--space-2) * -1); } }
284
+ .card.pending .lens::after { content: " working"; color: var(--color-text-muted); font-weight: var(--weight-regular); }
285
+ .human-note { grid-column: 1 / -1; border: var(--border-width) dashed var(--color-border-strong); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); font-size: var(--text-sm); }
286
+ .human-note b { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-accent); margin-right: var(--space-2); }
287
+
288
+ /* Seat state: a small light in the card head and the strip row (connection), and a faint tint
289
+ behind the card or row (position in the round). The seat colour on the left edge reads first,
290
+ so the tint stays at 7% and the light is the token LED size. */
291
+ .led { display: inline-block; width: var(--led-size); height: var(--led-size); background: currentColor; color: var(--color-text-muted); opacity: 0.45; vertical-align: 0; margin-left: 2px; }
292
+ .led-thinking { color: var(--color-warn); opacity: 1; animation: blink var(--cursor-blink); }
293
+ .led-replied { color: var(--color-ok); opacity: 1; }
294
+ .led-reprompted { color: var(--color-warn); opacity: 1; }
295
+ .led-failed, .led-timed-out { color: var(--color-danger); opacity: 1; }
296
+ .card[data-position="agreed"], tr[data-position="agreed"] td { background: color-mix(in srgb, var(--color-ok) var(--tint), var(--color-surface)); }
297
+ .card[data-position="disagreed"], tr[data-position="disagreed"] td { background: color-mix(in srgb, var(--color-danger) var(--tint), var(--color-surface)); }
298
+ .card[data-position="neutral"], tr[data-position="neutral"] td { background: color-mix(in srgb, var(--color-info) var(--tint), var(--color-surface)); }
299
+ .card[data-position="passed"], tr[data-position="passed"] td { background: color-mix(in srgb, var(--color-text-muted) var(--tint), var(--color-surface)); }
300
+ .card-head .led { align-self: center; }
301
+
302
+ /* Conclusion and supporting detail */
303
+ .verdict { box-shadow: var(--shadow-overlay); border-color: var(--color-border-strong); }
304
+ .verdict-body { padding: var(--space-3); display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }
305
+ .verdict-body .section { display: flex; flex-direction: column; gap: var(--space-1); }
306
+ .verdict-body > .wide { grid-column: 1 / -1; }
307
+ .verdict-body .section { min-width: 0; }
308
+ .verdict-body h3 { margin: 0; }
309
+ .verdict-body .section p, .verdict-body .section ul { margin: 0; }
310
+ .verdict-body .section p { white-space: pre-line; }
311
+ .verdict-body .section ul { padding-left: 1.1em; }
312
+ .verdict-body pre { white-space: pre-wrap; margin: 0; font: var(--text-sm)/1.5 var(--font-mono); }
313
+ .verdict-meta { grid-column: 1 / -1; font: var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); }
314
+
315
+ .verdict-title { gap: var(--space-2); flex-wrap: wrap; }
316
+ .verdict-title .btn { margin-left: auto; }
317
+ .result-copy { padding: 0 var(--space-3); }
318
+ .result-copy:has(#copy-result-status:empty) { display: none; }
319
+ .result-copy .hint { display: block; margin-top: var(--space-2); }
320
+ #copy-result-text { display: block; width: 100%; min-height: 180px; max-height: 45vh; resize: vertical; margin: var(--space-2) 0; }
321
+ .verdict-answer > p:first-of-type { font-size: 1.1em; line-height: 1.65; max-width: 80ch; }
322
+ .verdict-pick { color: var(--color-text); overflow-wrap: anywhere; }
323
+ .verdict-pick strong { font-weight: var(--weight-strong); }
324
+ .verdict-pick { margin-top: var(--space-1) !important; }
325
+ .verdict-questions { padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-sm); }
326
+ .verdict-needed { border-left: 3px solid var(--color-warn); }
327
+ .verdict-details { min-width: 0; border-top: 1px solid var(--color-border); }
328
+ .verdict-details > summary { padding: var(--space-2) 0; cursor: pointer; font-size: var(--text-sm); }
329
+ .verdict-support { display: flex; flex-direction: column; gap: var(--space-3); padding-top: var(--space-2); }
330
+ .verdict-positions .hint { display: block; }
331
+ .verdict-meta { overflow-wrap: anywhere; }
332
+
333
+ .export-bar { display: flex; gap: var(--space-2); align-items: center; padding: var(--space-2) var(--space-3); border-top: var(--border-width) solid var(--color-border); flex-wrap: wrap; }
334
+ .export-bar input { flex: 1; min-width: 240px; padding: var(--space-1) var(--space-2); font-size: var(--text-sm); }
335
+ .export-bar .hint { font-family: var(--font-mono); font-size: var(--text-xs); }
336
+ .export-bar > * { min-width: 0; max-width: 100%; }
337
+
338
+ /* Human bar */
339
+ .humanbar { position: fixed; left: 0; right: 0; bottom: 28px; background: var(--color-surface); border-top: var(--border-width) solid var(--color-border-strong); padding: var(--space-2) var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); }
340
+ .humanbar-status { font: var(--text-sm) var(--font-sans); display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; max-height: 25vh; overflow-y: auto; }
341
+ .humanbar-form { display: flex; gap: var(--space-2); max-width: 1100px; width: 100%; margin: 0 auto; }
342
+ .humanbar-form input { flex: 1; min-width: 0; }
343
+ .answer-label-short { display: none; }
344
+ #human-error { max-height: 20vh; overflow-y: auto; }
345
+ .humanbar .countdown { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-warn); display: inline-flex; align-items: center; gap: 6px; }
346
+ .humanbar .countdown::before { content: ""; width: var(--led-size); height: var(--led-size); background: currentColor; }
347
+
348
+ /* Status line */
349
+ .statusline { position: fixed; left: 0; right: 0; bottom: 0; height: 28px; display: flex; gap: var(--space-4); align-items: center; padding: 0 var(--space-4); background: var(--color-bg); border-top: var(--border-width) solid var(--color-border); font: var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); }
350
+ .statusline .end { margin-left: auto; }
351
+
352
+ @media (max-width: 720px) {
353
+ main { padding: var(--space-4); padding-bottom: max(140px, calc(var(--board-bar-height, 0px) + 52px)); }
354
+ .fields, .fields-row, .verdict-body { grid-template-columns: 1fr; }
355
+ .columns { grid-template-columns: minmax(0, 1fr); }
356
+ #seats th:last-child, #seats td:last-child { display: none; }
357
+ .humanbar-form { flex-wrap: wrap; }
358
+ .humanbar-form input { flex-basis: 100%; }
359
+ .humanbar-status .gate-guidance, .answer-label-full { display: none; }
360
+ .answer-label-short { display: inline; }
361
+ }
362
+ @media (max-width: 420px) {
363
+ .statusline { gap: var(--space-2); }
364
+ .statusline .end { display: none; }
365
+ }
366
+
367
+ /* Seat cards: a character card per seat. The left edge is square and carries the vendor colour;
368
+ the right corners are rounded. Every value is a control that reads as text until hovered or
369
+ focused, so a seat is edited in place. */
370
+ .seats { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--space-3); padding: var(--space-3); }
371
+ .seat-card { --v: var(--seat); position: relative; display: flex; flex-direction: column; background: var(--color-surface-raised); border: var(--border-width) solid var(--color-border-strong); border-left: 4px solid var(--v); border-radius: 0 var(--radius-lg) var(--radius-lg) 0; }
372
+ .seat-hd { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); border-bottom: var(--border-width) solid var(--color-border); }
373
+ .avatar { width: 32px; height: 32px; flex: none; display: grid; place-items: center; color: var(--v); background: var(--color-bg); border: var(--border-width) solid var(--color-border-strong); }
374
+ .avatar svg { width: 24px; height: 24px; }
375
+ .avatar-lg { width: 40px; height: 40px; } .avatar-lg svg { width: 30px; height: 30px; }
376
+ .seat-id { display: flex; flex-direction: column; min-width: 0; flex: 1; }
377
+ /* the card's status lamp: round, the one exception to the square LEDs (signature-design components) */
378
+ .lamp { width: 11px; height: 11px; flex: none; border-radius: 50%; background: var(--lamp); box-shadow: 0 0 0 2px var(--color-surface-raised), 0 0 0 3px var(--color-border-strong); }
379
+ .lamp.ok { --lamp: var(--color-ok); } .lamp.warn { --lamp: var(--color-warn); } .lamp.danger { --lamp: var(--color-danger); } .lamp.idle { --lamp: var(--color-border-strong); }
380
+ .seat-card .remove { position: absolute; top: 2px; right: 2px; min-height: 18px; padding: 0 var(--space-1); border: 0; background: transparent; color: var(--color-text-muted); font-size: var(--text-sm); }
381
+ .seat-card .remove:hover { color: var(--color-danger); }
382
+ .seat-card .lamp { margin-right: var(--space-3); }
383
+ .seat-bd { display: flex; flex: 1; flex-direction: column; gap: var(--space-1); padding: var(--space-2) var(--space-3) var(--space-3); }
384
+ .f { display: grid; grid-template-columns: 76px minmax(0, 1fr); align-items: center; gap: var(--space-2); min-height: 26px; }
385
+ .seat-note { font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
386
+ .seat-note.danger { color: var(--color-danger); } .seat-note.warn { color: var(--color-warn); }
387
+ .iso-note { min-height: 0; } /* a card on Antigravity: the limitation, its explanation as the tip */
388
+ .lamp-note { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; line-height: 1.4; min-height: 2.8em; }
389
+ .lamp-note:focus { display: block; overflow: visible; }
390
+ .card-notices, .card-notices-empty { display: block; min-height: 26px; font: var(--text-xs)/1.5 var(--font-mono); }
391
+ .card-notices > summary { cursor: pointer; padding: 3px 0; }
392
+ .card-notices-body { display: grid; gap: var(--space-2); padding: var(--space-2); border-left: 2px solid currentColor; }
393
+ .seat-more { margin-top: auto; }
394
+ /* a card on a vendor with a terms notice: a note that opens the notice (#vendor-terms) */
395
+ .terms-note { display: block; padding: 0; border: 0; background: none; text-align: left; text-decoration: underline dotted; text-underline-offset: 2px; cursor: pointer; }
396
+ /* flat controls */
397
+ .seat-card .flat { width: 100%; padding: 2px var(--space-1); font-size: var(--text-sm); color: var(--color-text); background: transparent; border: var(--border-width) solid transparent; border-bottom: var(--border-width) dashed var(--color-border-strong); border-radius: var(--radius-sm); }
398
+ .seat-card .flat:hover { border-color: var(--color-border-strong); }
399
+ .seat-card .flat:focus { background: var(--color-surface); border-style: solid; border-color: var(--color-focus); outline: none; }
400
+ .seat-card .flat.vendor { font-weight: var(--weight-strong); font-size: var(--text-base); border-bottom-color: transparent; padding-left: 0; }
401
+ .seat-card .flat.model { font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); border-bottom-color: transparent; padding-left: 0; }
402
+ .seat-card .flat.model:hover, .seat-card .flat.model:focus { border-bottom-color: var(--color-border-strong); }
403
+ .seat-card .mood-text { margin-top: var(--space-1); }
404
+ /* effort as pips: one per level the CLI accepts; none filled is the CLI's default */
405
+ .pips { display: grid; gap: 0; min-width: 0; }
406
+ .pip-buttons { display: flex; min-width: 0; gap: 2px; }
407
+ .pips.locked { pointer-events: none; opacity: 0.55; }
408
+ .card-avatar { width: 22px; height: 22px; color: var(--seat); } .card-avatar svg { width: 16px; height: 16px; }
409
+ .pip { display: inline-grid; place-items: center; flex: 0 1 28px; min-width: 16px; width: 28px; height: 28px; padding: 0; border: 0; background: transparent; cursor: pointer; }
410
+ .pip::before { content: ''; width: 12px; height: 12px; border: var(--border-width) solid var(--v); }
411
+ .pip.on::before { background: var(--v); }
412
+ .pip:hover { background: var(--color-bg); }
413
+ .pip:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
414
+ .pip-label { min-height: 1.5em; font: var(--text-xs)/1.5 var(--font-mono); color: var(--color-text-muted); }
415
+ .seat-more summary { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); cursor: pointer; padding: var(--space-1) 0; }
416
+ .seat-more .flat { margin-top: var(--space-1); }
417
+ .seats-actions { padding: 0 var(--space-3) var(--space-3); display: flex; justify-content: space-between; align-items: center; }
418
+ /* the chairman: one wide card, a heavier frame in its vendor's colour, the gavel */
419
+ .chair-wrap { padding: 0 var(--space-3) var(--space-3); }
420
+ .chair-card { border-width: 2px; border-left-width: 6px; border-color: var(--v); box-shadow: var(--shadow-hard); }
421
+ .chair-card .seat-hd { background: var(--color-surface); }
422
+ .chair-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); font-weight: var(--weight-strong); }
423
+ .chair-title .flat.vendor { width: auto; }
424
+ /* Where a seat runs, on every card: "CLI · subscription" muted, "API · local" / "API · pay-per-token"
425
+ in the vendor colour, so a seat that bills per token is never mistaken for one on a plan. */
426
+ .kind-tag { font: var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); border: var(--border-width) solid transparent; border-radius: var(--radius-sm); padding: 0 var(--space-1); white-space: nowrap; line-height: 18px; }
427
+ /* the one boxed tag on a seat: a seat that bills per token */
428
+ .kind-tag.api { color: var(--v); border-color: var(--v); }
429
+ .chair-role { margin: 0 0 var(--space-1); font-size: var(--text-sm); color: var(--color-text-muted); }
430
+ /* Run settings: numbers take the width a number needs; Memory takes what is left, so the row
431
+ ends at the panel's edge instead of in a blank column. */
432
+ .rules { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3) var(--space-4); border-top: var(--border-width) solid var(--color-border); }
433
+ .rules .field { flex: 0 0 140px; }
434
+ .rules .field:has(#memory) { flex: 1 1 260px; }
435
+ .rules .field-check { flex: 0 0 auto; }
436
+ .rules .field-check .check { min-height: 36px; }
437
+ /* Unattended: an arming switch. The checkbox stays for the keyboard and screen readers; the
438
+ switch is its face. Off: a plain slide. On: danger colour and the hazard stripe, since the
439
+ table will not wait for anyone once it is armed. */
440
+ .field-check .check { display: inline-flex; align-items: center; gap: var(--space-2); min-height: 24px; position: relative; cursor: pointer; font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); }
441
+ .field-check input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; }
442
+ .switch { flex: none; width: 38px; height: 20px; border: 1px solid var(--color-border-strong); border-radius: 2px; background: var(--color-surface); box-shadow: var(--shadow-hard-action); position: relative; transition: background-color 0.15s ease, border-color 0.15s ease; }
443
+ .switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 14px; height: 14px; background: var(--color-text-muted); transition: transform 0.15s ease, background-color 0.15s ease; }
444
+ .switch-text::before { content: attr(data-off); }
445
+ .field-check input:checked + .switch { border-color: var(--color-danger); background-color: var(--color-surface-raised); background-image: var(--pattern-hazard); background-size: 6px 100%; background-repeat: no-repeat; }
446
+ .field-check input:checked + .switch::after { transform: translateX(18px); background: var(--color-danger); }
447
+ .field-check input:checked ~ .switch-text { color: var(--color-danger); }
448
+ .field-check input:checked ~ .switch-text::before { content: attr(data-on); }
449
+ .field-check input:focus-visible + .switch { outline: 2px solid var(--color-focus); outline-offset: 2px; }
450
+ .field-check .check:hover .switch { border-color: var(--color-danger); }
451
+ @media (max-width: 720px) { .rules .field { flex: 1 1 120px; } }
452
+
453
+ /* Field notes: options as chips, the rest behind "More context" */
454
+ .options { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
455
+ .opt { display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px var(--space-1) 2px var(--space-2); background: var(--color-surface-raised); border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius-sm); }
456
+ .opt b { font: var(--weight-strong) var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
457
+ .opt input { width: auto; min-width: 8ch; padding: 2px; border: 0; background: transparent; font-size: var(--text-base); }
458
+ .opt input:focus-visible { outline: none; }
459
+ .opt:focus-within { border-color: var(--color-focus); }
460
+ .opt.dup { border-color: var(--color-danger); }
461
+ .opt-x { min-height: 0; padding: 0 var(--space-1); border: 0; background: transparent; color: var(--color-text-muted); }
462
+ .opt-x:hover { color: var(--color-danger); }
463
+ .opt-add { border-style: dashed; color: var(--color-text-muted); }
464
+ .more { border-top: var(--border-width) solid var(--color-border); padding-top: var(--space-2); }
465
+ .more summary { cursor: pointer; }
466
+ .more > .fields { padding: var(--space-2) 0 0; grid-template-columns: repeat(4, minmax(0, 1fr)); }
467
+ /* Known and Assumed side by side; Reversibility, Deadline and Export to share the next row */
468
+ .more > .fields > :nth-child(-n + 2), .more > .fields > .wide { grid-column: span 2; }
469
+ .more-filled { font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
470
+ /* Anything marked wide in a field grid takes the whole row, a fold included */
471
+ .fields > .wide { grid-column: 1 / -1; }
472
+ @media (max-width: 720px) { .more > .fields > * { grid-column: 1 / -1 !important; } }
473
+
474
+
475
+ /* Window readout (signature-design components.md): one slot per fact. The figure leads, the
476
+ track shows used plus this debate's projected draw, the reset and rate sit beneath. */
477
+ .readouts { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--space-3); min-width: 0; }
478
+ .readout { --level: var(--color-text-muted); display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
479
+ .readout.lvl-warn { --level: var(--color-warn); }
480
+ .readout.lvl-danger { --level: var(--color-danger); }
481
+ .readout-fig { display: flex; align-items: baseline; gap: var(--space-2); }
482
+ .readout-fig b { font: var(--weight-strong) var(--text-md) var(--font-mono); font-variant-numeric: tabular-nums; color: var(--color-text); }
483
+ .readout.lead .readout-fig b { font-size: var(--text-lg); }
484
+ .readout.lvl-warn .readout-fig b, .readout.lvl-danger .readout-fig b { color: var(--level); }
485
+ .readout-fig span { font-size: var(--text-sm); color: var(--color-text-muted); }
486
+ .track { display: flex; height: 6px; border: var(--border-width) solid var(--color-border); background: var(--color-surface-raised); }
487
+ .track .used { background: var(--level); }
488
+ .track .adds { background: color-mix(in srgb, var(--level) 40%, transparent); }
489
+ .readout-sub { font: var(--text-xs) var(--font-mono); font-variant-numeric: tabular-nums; color: var(--color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
490
+
491
+ /* Pool identity and meta, shared by the board row and the setup card */
492
+ .pool-id { display: flex; flex-direction: column; min-width: 0; }
493
+ .pool-id b { font-weight: var(--weight-strong); }
494
+ .pool-id span { font-size: var(--text-sm); color: var(--color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
495
+ .pool-meta { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-1); font-size: var(--text-sm); color: var(--color-text-muted); white-space: nowrap; }
496
+ .pool-meta a, .pool-cap a { color: var(--color-text); text-underline-offset: 2px; font-size: var(--text-sm); }
497
+
498
+ /* Board: the usage table. Numbers right-aligned in the data face; each pool is a one-line group
499
+ heading (who, plan, live windows, usage page) over its seats; the totals close it. */
500
+ #usage th { white-space: nowrap; padding-top: var(--space-2); padding-bottom: var(--space-2); }
501
+ #usage .num { text-align: right; }
502
+ #usage td { padding-top: 6px; padding-bottom: 6px; }
503
+ #usage td.data { color: var(--color-text); }
504
+ #usage .partial { margin-left: 1px; color: var(--color-warn); cursor: help; }
505
+ tr.pool-row td { background: var(--color-bg); border-top: var(--border-width) solid var(--color-border-strong); padding: var(--space-2) var(--space-3); }
506
+ .pool-head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-4); font-size: var(--text-sm); }
507
+ .pool-name { display: inline-flex; align-items: baseline; gap: var(--space-2); min-width: 0; }
508
+ .pool-name span { color: var(--color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
509
+ .pool-figures { display: inline-flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); margin-left: auto; font: var(--text-xs) var(--font-mono); font-variant-numeric: tabular-nums; color: var(--color-text-muted); }
510
+ .pool-window { display: inline-flex; align-items: center; gap: var(--space-2); white-space: nowrap; }
511
+ .pool-window .quota-track { display: inline-block; width: 40px; height: 4px; margin: 0; color: var(--color-ok); }
512
+ .pool-window.warn .quota-track { color: var(--color-warn); } .pool-window.danger .quota-track { color: var(--color-danger); }
513
+ .pool-head > a { color: var(--color-text); text-underline-offset: 2px; white-space: nowrap; }
514
+ .seat-cell { display: flex; align-items: flex-start; gap: var(--space-2); }
515
+ .seat-cell .seat-dot { margin: 3px 0 0; }
516
+ .seat-cell > span:last-child { display: flex; flex-direction: column; min-width: 0; }
517
+ .seat-lens { display: inline-flex; align-items: center; gap: var(--space-1); }
518
+ td .seat-meta { color: var(--color-text-muted); font: var(--text-xs) var(--font-mono); }
519
+ #usage tr.subtotal td { color: var(--color-text-muted); }
520
+ #usage tr.subtotal td:first-child, #usage tr.total td:first-child { font: var(--weight-strong) var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; }
521
+
522
+ /* Setup: one card per vendor pool, a stacked bar of its seats */
523
+ .pools { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--space-3); padding: var(--space-3); }
524
+ .pool { border: var(--border-width) solid var(--color-border); border-radius: var(--radius); padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-3); background: var(--color-bg); }
525
+ .pool-top { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-3); }
526
+ .pool-total { display: flex; flex-direction: column; align-items: flex-end; white-space: nowrap; }
527
+ .pool-total b { font: var(--weight-strong) var(--text-lg) var(--font-mono); font-variant-numeric: tabular-nums; }
528
+ .pool-total span { font-size: var(--text-sm); color: var(--color-text-muted); }
529
+ /* The bar: one segment per seat, 2px apart. Seats of one vendor share a colour, so segments step
530
+ down in shade and the chairman is hatched; the legend swatch uses the same fill. */
531
+ .bar { display: flex; gap: 2px; height: 10px; overflow: hidden; }
532
+ .bar span { display: block; height: 100%; min-width: 2px; background: var(--fill); }
533
+ :is(.bar span, .pool-seats .chip) { --fill: var(--seat); }
534
+ :is(.bar span, .pool-seats .chip).shade-1 { --fill: color-mix(in srgb, var(--seat) 68%, var(--color-surface)); }
535
+ :is(.bar span, .pool-seats .chip).shade-2 { --fill: color-mix(in srgb, var(--seat) 46%, var(--color-surface)); }
536
+ :is(.bar span, .pool-seats .chip).shade-3 { --fill: color-mix(in srgb, var(--seat) 30%, var(--color-surface)); }
537
+ :is(.bar span, .pool-seats .chip).chair { --fill: repeating-linear-gradient(-45deg, var(--seat) 0 2px, color-mix(in srgb, var(--seat) 22%, var(--color-surface)) 2px 4px); }
538
+ /* The legend: swatch and lens, tokens, cost, in three aligned columns */
539
+ .pool-seats { display: grid; grid-template-columns: minmax(0, 1fr) auto 6ch; gap: var(--space-1) var(--space-3); font-size: var(--text-sm); }
540
+ .pool-seats .chip { display: contents; }
541
+ .pool-seats .chip > span:first-child { display: flex; align-items: center; gap: var(--space-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
542
+ .pool-seats .chip > span:first-child::before { content: ""; flex: none; width: 10px; height: 10px; background: var(--fill); }
543
+ .pool-seats .chip > b, .pool-seats .chip > b + span { font: var(--text-sm) var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }
544
+ .pool-seats .chip > b + span { color: var(--color-text-muted); }
545
+ .pool-note { margin: 0; font-size: var(--text-sm); color: var(--color-text-muted); }
546
+ .pool-note b { color: var(--color-text); }
547
+ /* Every card has the same three parts in the same places: the seats, the window, the cap. The
548
+ cap row sits at the card's foot, so cards in one row line up whatever is above. */
549
+ .pool-window-section { display: flex; flex-direction: column; gap: var(--space-2); padding-top: var(--space-3); border-top: var(--border-width) solid var(--color-border); }
550
+ .pool-cap { margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); padding-top: var(--space-3); border-top: var(--border-width) solid var(--color-border); font-size: var(--text-sm); }
551
+ .pool-cap label { color: var(--color-text-muted); }
552
+ .pool-cap input { width: 100px; padding: var(--space-1); font-size: var(--text-sm); }
553
+ .pool-cap a { margin-left: auto; }
554
+
555
+ /* A pool figure typed in for a vendor with no feed */
556
+ .pool-edit summary { font-size: var(--text-sm); color: var(--color-text-muted); cursor: pointer; }
557
+ .pool-entry { display: grid; grid-template-columns: 1fr 80px 1fr 1fr auto; gap: var(--space-1); align-items: center; margin-top: var(--space-1); }
558
+ .pool-entry input { padding: var(--space-1); font-size: var(--text-sm); }
559
+
560
+ @media (max-width: 720px) {
561
+ #usage th:nth-child(3), #usage td:nth-child(3), #usage th:nth-child(6), #usage td:nth-child(6), #usage th:nth-child(7), #usage td:nth-child(7) { display: none; }
562
+ #usage td.data .seat-meta { display: block; margin-left: 0; white-space: normal; }
563
+ .pool-head { grid-template-columns: minmax(0, 1fr) auto; gap: var(--space-2) var(--space-3); }
564
+ .pool-head .readouts { grid-column: 1 / -1; grid-row: 2; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
565
+ .pool-entry { grid-template-columns: 1fr 1fr; }
566
+ }
567
+
568
+ /* Links styled as buttons (the header's Debates) */
569
+ a.btn { display: inline-flex; align-items: center; text-decoration: none; }
570
+
571
+ /* The list of debates on the setup screen */
572
+ .debates { display: flex; flex-direction: column; container-type: inline-size; }
573
+ .debates .empty { margin: var(--space-3); }
574
+ .history-row { display: flex; align-items: stretch; border-top: var(--border-width) solid var(--color-border); }
575
+ .history-row:first-child { border-top: 0; }
576
+ .history-row .debate-row { flex: 1; min-width: 0; border-top: 0; }
577
+ .history-delete { align-self: center; margin: var(--space-2); }
578
+ #delete-history, #vendor-terms { width: min(480px, calc(100% - 32px)); color: var(--color-text); background: var(--color-surface); border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius); padding: var(--space-4); box-shadow: var(--shadow-overlay); }
579
+ #delete-history::backdrop, #vendor-terms::backdrop { background: rgb(0 0 0 / 45%); }
580
+ #delete-history h2, #vendor-terms h2 { margin-top: 0; }
581
+ #delete-history p, #vendor-terms p { overflow-wrap: anywhere; }
582
+ .debate-row { display: grid; grid-template-columns: 88px minmax(0, 1fr) 128px minmax(0, 160px) 184px; gap: var(--space-3); align-items: center; padding: var(--space-2) var(--space-3); border-top: var(--border-width) solid var(--color-border); color: inherit; text-decoration: none; }
583
+ .debate-row:first-child { border-top: 0; }
584
+ .debate-row:hover, .debate-row:focus-visible { background: var(--color-selection); }
585
+ .debate-row:focus-visible { outline: 2px solid var(--color-focus); outline-offset: -2px; }
586
+ .debate-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: var(--weight-strong); }
587
+ .debate-pick { font-size: var(--text-sm); color: var(--color-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
588
+ .debate-row .data:last-child { text-align: right; }
589
+ /* Every row is its own grid, so every column but the title has a fixed width: a column sized to
590
+ its own text would shift the columns before it from row to row. */
591
+ .debate-row > :nth-child(5) { white-space: normal; text-align: right; }
592
+ .debates-more { align-self: flex-start; margin: var(--space-2) var(--space-3) var(--space-3); }
593
+ @media (max-width: 720px) {
594
+ .debate-row { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "date title title" "state pick size"; row-gap: var(--space-1); }
595
+ .debate-row > :nth-child(1) { grid-area: date; } .debate-row > :nth-child(2) { grid-area: title; } .debate-row > :nth-child(3) { grid-area: state; }
596
+ .debate-row > :nth-child(4) { grid-area: pick; } .debate-row > :nth-child(5) { grid-area: size; }
597
+ }
598
+
599
+ /* "Open the table" stays in reach: a bar that sticks above the status line, with what the table
600
+ is projected to cost */
601
+ .startbar { position: sticky; bottom: 40px; z-index: 2; display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-3); background: var(--color-surface-raised); border: var(--border-width) solid var(--color-border-strong); border-radius: var(--radius); box-shadow: var(--shadow-hard); }
602
+ .startbar-summary { margin-right: auto; font: var(--text-sm) var(--font-mono); font-variant-numeric: tabular-nums; color: var(--color-text-muted); }
603
+ .startbar-summary b { color: var(--color-text); }
604
+ .startbar .error { margin-right: 0; }
605
+
606
+ /* Errors on the board: banners above it, a plain reason on a failed card, the CLI's words behind it */
607
+ .banners { display: flex; flex-direction: column; gap: var(--space-2); }
608
+ .banners:empty { display: none; }
609
+ .banner { padding: var(--space-2) var(--space-3); border: var(--border-width) solid currentColor; border-left-width: 4px; border-radius: 0 var(--radius) var(--radius) 0; background: var(--color-surface-raised); font-size: var(--text-sm); color: var(--color-text); }
610
+ .banner.danger { border-color: var(--color-danger); } .banner.warn { border-color: var(--color-warn); }
611
+ .banner .status { margin-right: var(--space-2); }
612
+ .debate-warning { grid-column: 1 / -1; white-space: normal; overflow-wrap: anywhere; color: var(--color-warn); font-size: var(--text-sm); }
613
+ .transcript-warning { overflow-wrap: anywhere; }
614
+ .fail-line { margin: 0; font-size: var(--text-sm); }
615
+ .fail-line.danger { color: var(--color-danger); }
616
+ .fail-detail summary { font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); cursor: pointer; }
617
+ .led-down { color: var(--color-danger); opacity: 1; }
618
+ .synth { display: inline-flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; max-width: 100%; }
619
+ .synth select { width: auto; max-width: 100%; min-width: 0; padding: 2px var(--space-1); font-size: var(--text-sm); }
620
+
621
+ /* the model picker reads as the model line under the vendor */
622
+ .seat-card .flat.model-pick { font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); border-bottom-color: transparent; padding-left: 0; }
623
+ .seat-card .flat.model-pick:hover, .seat-card .flat.model-pick:focus { border-bottom-color: var(--color-border-strong); color: var(--color-text); }
624
+ .pick-row { display: flex; gap: var(--space-2); align-items: center; }
625
+ .pick-row input { flex: 1; min-width: 0; }
626
+
627
+ #research-panel { overflow-wrap: anywhere; }
628
+ #research-body { padding: var(--space-3); }
629
+ #research-panel details { padding: var(--space-2) 0; border-top: var(--border-width) solid var(--color-border); }
630
+ #research-panel summary { cursor: pointer; font-weight: 600; }
631
+ #research-panel p { white-space: pre-wrap; }
632
+
633
+ /* The chairman at work: the sheet and quill scribe.js draws while the verdict call runs */
634
+ .verdict.is-writing :is(.result-copy, .decision-actions, .export-bar) { display: none; }
635
+ .scribe { grid-column: 1 / -1; display: flex; justify-content: center; padding-top: var(--space-2); }
636
+ .scribe-art { width: 108px; height: 108px; }
637
+ .scribe-shadow { fill: var(--color-border-strong); }
638
+ .scribe-page { fill: var(--color-surface-raised); }
639
+ .scribe-ink { fill: var(--color-text-muted); }
640
+ .scribe-quill { fill: var(--color-action); }
641
+ .scribe-note { grid-column: 1 / -1; margin: 0; text-align: center; padding-bottom: var(--space-2); }
642
+
643
+ /* The searcher at work: the eye reading a column of results that scan.js draws while research runs */
644
+ .scan { display: flex; justify-content: center; padding-top: var(--space-2); }
645
+ .scan-art { width: 108px; height: 108px; }
646
+ .scan-unread { fill: var(--color-border-strong); }
647
+ .scan-read { fill: var(--color-text-muted); }
648
+ .scan-kept, .scan-eye { fill: var(--color-action); }
649
+ .scan-note { margin: 0; text-align: center; padding-bottom: var(--space-2); }
650
+
651
+ /* Loading: shown only when setup takes longer than a moment (app.js, boot). A plain boot
652
+ screen: the page colour, the logo (loader.js) and one line of text, no card, tile or shadow.
653
+ The ring breathes in four slow steps (rest, out, rest, in) while a light runs round it; every
654
+ change is a whole-pixel switch (steps), so it stays pixel art. Lit means toward the text colour:
655
+ dark plum on paper, pale lilac at night. */
656
+ .boot { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; background: var(--color-bg); }
657
+ .boot-card { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); font: var(--text-sm)/1.7 var(--font-mono); color: var(--color-text-muted); }
658
+ .boot-card .prompt { color: var(--color-accent); font-weight: var(--weight-strong); }
659
+ .loader { --lap: 1600ms; --breath: 4000ms; --rest: color-mix(in srgb, var(--color-accent) 34%, var(--color-bg)); --lit: color-mix(in srgb, var(--color-accent) 45%, var(--color-text)); width: 96px; height: 96px; }
660
+ .loader-table { fill: var(--color-accent); }
661
+ .loader-seat { fill: var(--rest); animation: loader-seat var(--lap) steps(1, end) infinite; animation-delay: calc(var(--a) * var(--lap) - var(--lap)); }
662
+ @keyframes loader-seat {
663
+ 0% { fill: var(--lit); }
664
+ 6% { fill: var(--color-accent); }
665
+ 14% { fill: color-mix(in srgb, var(--color-accent) 65%, var(--color-bg)); }
666
+ 22%, 100% { fill: var(--rest); }
667
+ }
668
+ .loader-ring { animation: var(--breath) steps(1, end) infinite; }
669
+ .loader-mid { animation-name: loader-mid; }
670
+ .loader-out { animation-name: loader-out; opacity: 0; }
671
+ .loader-in { animation-name: loader-in; opacity: 0; }
672
+ @keyframes loader-mid { 0% { opacity: 1; } 25% { opacity: 0; } 50% { opacity: 1; } 75% { opacity: 0; } }
673
+ @keyframes loader-out { 0% { opacity: 0; } 25% { opacity: 1; } 50% { opacity: 0; } }
674
+ @keyframes loader-in { 0% { opacity: 0; } 75% { opacity: 1; } }
675
+ @media (prefers-reduced-motion: reduce) {
676
+ .loader-ring, .loader-seat { animation: none; }
677
+ .loader-seat { fill: var(--color-accent); }
678
+ }
679
+
680
+ /* Notes that open a panel, under its title */
681
+ .panel-note { margin: 0; padding: var(--space-2) var(--space-3) 0; }
682
+
683
+ /* The debates list stacks each row by the list's own width, so a title is never squeezed to a
684
+ letter beside the date, state, pick and size columns. */
685
+ @container (max-width: 760px) {
686
+ .debate-row { grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "date title title" "state pick size"; row-gap: var(--space-1); }
687
+ .debate-row > :nth-child(1) { grid-area: date; } .debate-row > :nth-child(2) { grid-area: title; } .debate-row > :nth-child(3) { grid-area: state; }
688
+ .debate-row > :nth-child(4) { grid-area: pick; } .debate-row > :nth-child(5) { grid-area: size; }
689
+ }
690
+
691
+ /* Quiet actions: text with a dotted underline, the status line's Save error log style. A border
692
+ is kept for the main controls; secondary and per-row actions do not box themselves. */
693
+ .text-btn { padding: 0; border: 0; background: none; font: var(--text-xs) var(--font-mono); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--color-text-muted); text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; }
694
+ .text-btn:hover:not([disabled]), .text-btn:focus-visible { color: var(--color-text); }
695
+ .text-btn[disabled] { opacity: 0.45; cursor: default; text-decoration: none; }
696
+ .debates-foot { display: flex; justify-content: space-between; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-top: var(--border-width) solid var(--color-border); }
697
+ .debates-foot #clear-history { margin-left: auto; }
698
+ /* Delete appears on the row under the pointer or keyboard focus; on touch screens it stays */
699
+ .history-delete { opacity: 0; margin: 0 var(--space-3) 0 var(--space-2); }
700
+ .history-delete:hover:not([disabled]) { color: var(--color-danger); }
701
+ .history-row:hover .history-delete, .history-row:focus-within .history-delete { opacity: 1; }
702
+ @media (hover: none) { .history-delete { opacity: 1; } }
703
+
704
+ /* The searcher: a card beside the chairman's, dashed because it is at the table without a seat
705
+ there. Its query and limits sit in the card; the evidence panel on the board carries its mark. */
706
+ .searcher-card { border-style: dashed; border-left-style: solid; }
707
+ .searcher-card .seat-hd { background: var(--color-surface); }
708
+ .f-top { align-items: start; }
709
+ .f-top .label { padding-top: 4px; }
710
+ .searcher-card textarea.flat { resize: vertical; min-height: 44px; font: var(--text-sm)/1.5 var(--font-sans); }
711
+ .searcher-limits { display: inline-flex; align-items: center; gap: var(--space-1); font: var(--text-xs) var(--font-mono); color: var(--color-text-muted); }
712
+ .searcher-limits input.flat { width: 8ch; text-align: right; }
713
+ .heading-avatar { display: inline-grid; place-items: center; width: 18px; height: 18px; margin-right: var(--space-2); vertical-align: -3px; color: var(--color-accent); }
714
+ .heading-avatar svg { width: 16px; height: 16px; }