chesspal 0.1.0 → 0.2.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.
Files changed (209) hide show
  1. package/README.md +45 -82
  2. package/dist/cli/chat-hook.js +1 -1
  3. package/dist/cli/command-line.d.ts +1 -2
  4. package/dist/cli/command-line.js +2 -3
  5. package/dist/commands/agents.d.ts +26 -0
  6. package/dist/commands/agents.js +72 -0
  7. package/dist/commands/ai-move.d.ts +5 -14
  8. package/dist/commands/ai-move.js +28 -35
  9. package/dist/commands/ai-say.d.ts +3 -1
  10. package/dist/commands/ai-say.js +24 -6
  11. package/dist/commands/analyse-game.d.ts +4 -0
  12. package/dist/commands/analyse-game.js +43 -16
  13. package/dist/commands/annotate-game.d.ts +4 -0
  14. package/dist/commands/annotate-game.js +65 -12
  15. package/dist/commands/answer-lines.d.ts +28 -0
  16. package/dist/commands/answer-lines.js +144 -0
  17. package/dist/commands/coach.d.ts +45 -0
  18. package/dist/commands/coach.js +344 -0
  19. package/dist/commands/context.d.ts +16 -5
  20. package/dist/commands/context.js +1 -0
  21. package/dist/commands/delete-game.d.ts +7 -0
  22. package/dist/commands/delete-game.js +30 -0
  23. package/dist/commands/delete-review.d.ts +8 -0
  24. package/dist/commands/delete-review.js +34 -0
  25. package/dist/commands/drawings.d.ts +0 -2
  26. package/dist/commands/drawings.js +5 -3
  27. package/dist/commands/end-game.js +5 -2
  28. package/dist/commands/export-game.d.ts +1 -1
  29. package/dist/commands/export-game.js +4 -3
  30. package/dist/commands/game-summary.d.ts +21 -38
  31. package/dist/commands/game-summary.js +30 -167
  32. package/dist/commands/index.d.ts +15 -0
  33. package/dist/commands/index.js +47 -2
  34. package/dist/commands/init.d.ts +3 -3
  35. package/dist/commands/init.js +4 -4
  36. package/dist/commands/lead-input.d.ts +8 -0
  37. package/dist/commands/lead-input.js +21 -0
  38. package/dist/commands/look.js +4 -1
  39. package/dist/commands/new-game.d.ts +2 -3
  40. package/dist/commands/new-game.js +7 -4
  41. package/dist/commands/play-move.d.ts +8 -15
  42. package/dist/commands/play-move.js +5 -13
  43. package/dist/commands/player-move.d.ts +2 -6
  44. package/dist/commands/player-move.js +13 -6
  45. package/dist/commands/player-say.d.ts +1 -1
  46. package/dist/commands/player-say.js +1 -1
  47. package/dist/commands/ponder.d.ts +10 -0
  48. package/dist/commands/ponder.js +33 -21
  49. package/dist/commands/position.d.ts +1 -1
  50. package/dist/commands/position.js +3 -1
  51. package/dist/commands/profiles.d.ts +13 -4
  52. package/dist/commands/profiles.js +49 -15
  53. package/dist/commands/registry.d.ts +8 -3
  54. package/dist/commands/registry.js +12 -11
  55. package/dist/commands/say.d.ts +1 -1
  56. package/dist/commands/say.js +16 -16
  57. package/dist/commands/speech.d.ts +8 -0
  58. package/dist/commands/speech.js +20 -0
  59. package/dist/commands/status.d.ts +9 -3
  60. package/dist/commands/status.js +40 -15
  61. package/dist/commands/study-games.js +1 -1
  62. package/dist/commands/study.js +3 -19
  63. package/dist/core/facts.js +15 -15
  64. package/dist/core/game.d.ts +3 -1
  65. package/dist/core/game.js +8 -4
  66. package/dist/core/illegal.js +1 -1
  67. package/dist/core/index.d.ts +5 -4
  68. package/dist/core/index.js +5 -4
  69. package/dist/core/lead.d.ts +15 -0
  70. package/dist/core/lead.js +40 -0
  71. package/dist/core/levels.d.ts +1 -1
  72. package/dist/core/levels.js +1 -1
  73. package/dist/core/moods.d.ts +0 -2
  74. package/dist/core/moods.js +2 -2
  75. package/dist/core/openings.d.ts +0 -2
  76. package/dist/core/openings.js +1 -1
  77. package/dist/core/profile.js +1 -1
  78. package/dist/core/record.d.ts +1 -1
  79. package/dist/core/record.js +1 -1
  80. package/dist/core/review.d.ts +9 -3
  81. package/dist/core/review.js +29 -9
  82. package/dist/games/analysis.d.ts +1 -1
  83. package/dist/games/archive.d.ts +24 -3
  84. package/dist/games/archive.js +96 -22
  85. package/dist/games/coach.d.ts +57 -0
  86. package/dist/games/coach.js +144 -0
  87. package/dist/games/current-game.d.ts +2 -0
  88. package/dist/games/current-game.js +7 -1
  89. package/dist/games/files.js +1 -0
  90. package/dist/games/index.d.ts +4 -3
  91. package/dist/games/index.js +4 -3
  92. package/dist/games/talk.d.ts +1 -5
  93. package/dist/games/talk.js +14 -14
  94. package/dist/home/open-folder.js +1 -1
  95. package/dist/host-files/{ponder-agents.d.ts → agents.d.ts} +10 -2
  96. package/dist/host-files/agents.js +53 -0
  97. package/dist/host-files/host-files.d.ts +7 -2
  98. package/dist/host-files/host-files.js +27 -12
  99. package/dist/host-files/index.d.ts +2 -2
  100. package/dist/host-files/index.js +3 -3
  101. package/dist/index.d.ts +1 -3
  102. package/dist/index.js +1 -0
  103. package/dist/page/app/anchor.js +88 -0
  104. package/dist/page/{app.js → app/app.js} +112 -230
  105. package/dist/page/app/keys.js +94 -0
  106. package/dist/page/app/phase.js +30 -0
  107. package/dist/page/app/served.js +73 -0
  108. package/dist/page/avatars/avatars.js +19 -0
  109. package/dist/page/avatars/thought.js +10 -0
  110. package/dist/page/base.css +160 -0
  111. package/dist/page/board/board.css +959 -0
  112. package/dist/page/board/board.js +125 -0
  113. package/dist/page/{explain.js → board/explain.js} +1 -1
  114. package/dist/page/board/marks.js +160 -0
  115. package/dist/page/board/motion.js +71 -0
  116. package/dist/page/board/pointer.js +239 -0
  117. package/dist/page/board/squares.js +26 -0
  118. package/dist/page/dialogs/analyses.js +195 -0
  119. package/dist/page/{dialog.js → dialogs/dialog.js} +1 -1
  120. package/dist/page/dialogs/dialogs.css +1228 -0
  121. package/dist/page/{new-game-dialog.js → dialogs/new-game.js} +3 -3
  122. package/dist/page/{profile-dialogs.js → dialogs/profiles.js} +40 -11
  123. package/dist/page/dialogs/search.js +31 -0
  124. package/dist/page/dialogs/settings.js +42 -0
  125. package/dist/page/dialogs/studied.js +39 -0
  126. package/dist/page/dialogs/study.js +51 -0
  127. package/dist/page/{badges.js → game/badges.js} +1 -1
  128. package/dist/page/{browse.js → game/browse.js} +1 -1
  129. package/dist/page/game/card-fold.js +40 -0
  130. package/dist/page/game/column.js +51 -0
  131. package/dist/page/{ending.js → game/ending.js} +2 -2
  132. package/dist/page/game/game.css +577 -0
  133. package/dist/page/{move-list.js → game/move-list.js} +10 -6
  134. package/dist/page/{plies.js → game/plies.js} +30 -10
  135. package/dist/page/game/result-tile.js +14 -0
  136. package/dist/page/helps/helps.css +689 -0
  137. package/dist/page/helps/helps.js +220 -0
  138. package/dist/page/helps/view.js +127 -0
  139. package/dist/page/layout/fold-tab.js +11 -0
  140. package/dist/page/{folds.js → layout/folds.js} +1 -1
  141. package/dist/page/{header.js → layout/header.js} +5 -4
  142. package/dist/page/layout/layout.css +834 -0
  143. package/dist/page/lead/lead.js +82 -0
  144. package/dist/page/lead/view.js +38 -0
  145. package/dist/page/main.js +2 -2
  146. package/dist/page/pieces/CREDITS.md +12 -29
  147. package/dist/page/pieces/capablanca-small.svg +20 -0
  148. package/dist/page/pieces/capablanca.svg +22 -0
  149. package/dist/page/pieces/nitida-small.svg +3 -2
  150. package/dist/page/pieces/nitida.svg +3 -2
  151. package/dist/page/{pieces.js → pieces/pieces.js} +2 -2
  152. package/dist/page/pieces/torretta-small.svg +15 -14
  153. package/dist/page/pieces/torretta.svg +17 -15
  154. package/dist/page/{player-card.js → players/card.js} +2 -6
  155. package/dist/page/{clock-time.js → players/clock-time.js} +2 -2
  156. package/dist/page/{profile.js → profile/profile.js} +9 -5
  157. package/dist/page/{settings.js → profile/settings.js} +5 -4
  158. package/dist/page/style.css +9 -4398
  159. package/dist/page/talk/talk.css +958 -0
  160. package/dist/page/{talk.js → talk/talk.js} +39 -46
  161. package/dist/page/text.js +137 -19
  162. package/dist/page/theme.css +292 -0
  163. package/dist/profiles/index.d.ts +1 -1
  164. package/dist/profiles/profiles.d.ts +15 -4
  165. package/dist/profiles/profiles.js +24 -7
  166. package/dist/server/bell.d.ts +10 -2
  167. package/dist/server/bell.js +28 -12
  168. package/dist/server/caller.d.ts +14 -3
  169. package/dist/server/caller.js +44 -11
  170. package/dist/server/mcp.d.ts +1 -2
  171. package/dist/server/mcp.js +42 -14
  172. package/dist/server/page/analyses.d.ts +23 -0
  173. package/dist/server/page/analyses.js +65 -0
  174. package/dist/server/page/files.d.ts +5 -0
  175. package/dist/server/page/files.js +92 -0
  176. package/dist/server/page/game.d.ts +6 -0
  177. package/dist/server/page/game.js +381 -0
  178. package/dist/server/{http.d.ts → page/http.d.ts} +13 -0
  179. package/dist/server/{http.js → page/http.js} +11 -0
  180. package/dist/server/{page.d.ts → page/page.d.ts} +8 -13
  181. package/dist/server/page/page.js +229 -0
  182. package/dist/server/{profile-routes.d.ts → page/profiles.d.ts} +2 -2
  183. package/dist/server/{profile-routes.js → page/profiles.js} +47 -18
  184. package/instructions/analysis.md +4 -0
  185. package/instructions/analyst-agent.md +8 -0
  186. package/instructions/analyst.md +3 -7
  187. package/instructions/coach.md +11 -0
  188. package/instructions/opponent.md +4 -4
  189. package/package.json +1 -1
  190. package/dist/host-files/ponder-agents.js +0 -40
  191. package/dist/page/avatars.js +0 -16
  192. package/dist/page/board.js +0 -566
  193. package/dist/page/fold-tab.js +0 -9
  194. package/dist/page/game-column.js +0 -44
  195. package/dist/page/helps-view.js +0 -51
  196. package/dist/page/helps.js +0 -90
  197. package/dist/page/pieces/cburnett-small.svg +0 -20
  198. package/dist/page/pieces/cburnett.svg +0 -20
  199. package/dist/page/settings-panel.js +0 -32
  200. package/dist/page/studied.js +0 -14
  201. package/dist/page/study-dialog.js +0 -58
  202. package/dist/server/analyses.d.ts +0 -17
  203. package/dist/server/analyses.js +0 -46
  204. package/dist/server/page.js +0 -657
  205. /package/dist/page/{torretta.js → avatars/torretta.js} +0 -0
  206. /package/dist/page/{opening-book.js → game/opening-book.js} +0 -0
  207. /package/dist/page/{model-name.js → players/model-name.js} +0 -0
  208. /package/dist/page/{sounds.js → sounds/sounds.js} +0 -0
  209. /package/dist/page/{voice.js → talk/voice.js} +0 -0
@@ -0,0 +1,958 @@
1
+ /* The talk's column: the players' cards with their pictures and names, the faces, the words said and the box to write in, the card of a page offline,
2
+ and the notes laid over the board between games */
3
+
4
+ /* The picture stays at the card's top left, however many lines the card has; the clock in the middle */
5
+ .player-line {
6
+ display: flex;
7
+ align-items: flex-start;
8
+ gap: 12px;
9
+ }
10
+
11
+ .player-line > .clock {
12
+ align-self: center;
13
+ }
14
+
15
+ .player-line > svg {
16
+ flex: none;
17
+ }
18
+
19
+ .who {
20
+ flex: 1;
21
+ min-width: 0;
22
+ line-height: 1.25;
23
+ }
24
+
25
+ .name {
26
+ font-weight: 600;
27
+ }
28
+
29
+ /* The AI's name, which the player may choose long, stays on one line: whole in its tooltip */
30
+ .player.ai .name {
31
+ overflow: hidden;
32
+ white-space: nowrap;
33
+ text-overflow: ellipsis;
34
+ }
35
+
36
+ /* Under the AI's name, the model it plays with (D-82): one line, whole in its tooltip */
37
+ .player .signed {
38
+ color: var(--soft);
39
+ font-size: 12px;
40
+ overflow: hidden;
41
+ white-space: nowrap;
42
+ text-overflow: ellipsis;
43
+ }
44
+
45
+ .turn {
46
+ color: var(--accent);
47
+ font-weight: 600;
48
+ white-space: nowrap;
49
+ }
50
+
51
+ /* A player's clock, in Zoe's pill: the running one in the accent colour, red in the last seconds */
52
+ .player .clock {
53
+ flex: none;
54
+ padding: 4px 10px;
55
+ border-radius: 7px;
56
+ background: var(--page);
57
+ font-size: 20px;
58
+ font-weight: 600;
59
+ font-variant-numeric: lining-nums tabular-nums;
60
+ letter-spacing: 0.01em;
61
+ }
62
+
63
+ .player .clock.running {
64
+ background: var(--accent);
65
+ color: var(--on-accent);
66
+ }
67
+
68
+ .player .clock.low {
69
+ color: var(--low-time);
70
+ }
71
+
72
+ .player .clock.running.low {
73
+ background: var(--low-time);
74
+ color: #fff;
75
+ }
76
+
77
+ /* The clocks wait for the player (Zoe): the button that starts them takes a line of the player's card, under the clock it starts, off the board's squares;
78
+ between games the new game takes the same line, in the clock's place (D-77) */
79
+ .player-line:has(> .start-clocks, > .next-game) {
80
+ flex-wrap: wrap;
81
+ row-gap: 10px;
82
+ }
83
+
84
+ .start-clocks,
85
+ .next-game {
86
+ flex: 1 0 100%;
87
+ justify-content: center;
88
+ padding: 8px 14px;
89
+ font-size: 15px;
90
+ font-weight: 600;
91
+ }
92
+
93
+ .start-clocks .icon {
94
+ width: 14px;
95
+ height: 14px;
96
+ fill: currentColor;
97
+ }
98
+
99
+ .next-game .icon {
100
+ width: 16px;
101
+ height: 16px;
102
+ stroke-width: 2.2;
103
+ }
104
+
105
+ /* Between games a card has no side under the name (D-77): the name alone, in the middle of the picture */
106
+ .player-line > .who:not(:has(.note)) {
107
+ align-self: center;
108
+ }
109
+
110
+ .player-line > .who:not(:has(.note)) .taken:empty {
111
+ display: none;
112
+ }
113
+
114
+ /* The pieces taken overlap within a kind, close enough that all fifteen and the score stay on one line */
115
+ .taken {
116
+ display: flex;
117
+ flex-wrap: nowrap;
118
+ align-items: center;
119
+ gap: 0;
120
+ white-space: nowrap;
121
+ min-height: 20px;
122
+ margin-top: 3px;
123
+ }
124
+
125
+ .taken .group {
126
+ display: inline-flex;
127
+ }
128
+
129
+ /* A kind starts close to the one before: the piece's own margin is the gap */
130
+ .taken .group + .group {
131
+ margin-left: -3px;
132
+ }
133
+
134
+ /* The pieces taken are the set's small ones, whose colours and edges are their own */
135
+ .taken .piece {
136
+ width: 20px;
137
+ height: 20px;
138
+ }
139
+
140
+ /* Pawns comb tight; the other pieces show more of themselves, a pair of rooks or bishops two pieces still (Zoe) */
141
+ .taken .piece + .piece {
142
+ margin-left: -11px;
143
+ }
144
+
145
+ .taken .pawns .piece + .piece {
146
+ margin-left: -15px;
147
+ }
148
+
149
+ .balance {
150
+ flex: none;
151
+ margin-left: 2px;
152
+ color: var(--soft);
153
+ font-size: 13px;
154
+ font-weight: 600;
155
+ }
156
+
157
+ /* The badges of a side's moves, in its card under the pieces taken */
158
+ .badge-counts {
159
+ display: flex;
160
+ flex-wrap: wrap;
161
+ gap: 4px 10px;
162
+ list-style: none;
163
+ margin: 6px 0 0;
164
+ padding: 0;
165
+ font-size: 13px;
166
+ }
167
+
168
+ .badge-counts li {
169
+ display: inline-flex;
170
+ align-items: center;
171
+ gap: 4px;
172
+ }
173
+
174
+ /* The player's face, masked by a circle */
175
+ .avatar {
176
+ clip-path: circle(50%);
177
+ }
178
+
179
+ .avatar .back {
180
+ fill: var(--say);
181
+ }
182
+
183
+ .avatar .shirt {
184
+ fill: var(--accent);
185
+ }
186
+
187
+ .avatar .skin {
188
+ fill: #f1c6a0;
189
+ }
190
+
191
+ .avatar .hair {
192
+ fill: #4a3426;
193
+ }
194
+
195
+ .avatar .eye {
196
+ fill: #2b2420;
197
+ }
198
+
199
+ .avatar .smile {
200
+ fill: none;
201
+ stroke: #2b2420;
202
+ stroke-width: 1.6;
203
+ stroke-linecap: round;
204
+ }
205
+
206
+ /* The dialogs (D-23, D-45, D-48): the player's picture, which a click changes, their name, which opens the profiles, the wizard, the profiles, the new game and the analyses */
207
+ .avatar.photo {
208
+ clip-path: none;
209
+ border-radius: 50%;
210
+ object-fit: cover;
211
+ box-shadow: 0 0 0 1px var(--line);
212
+ }
213
+
214
+ /* A drawn avatar, its colour in the picture: the page's colour while it loads */
215
+ .avatar.drawn {
216
+ background: var(--say);
217
+ }
218
+
219
+ .me {
220
+ position: relative;
221
+ flex: none;
222
+ padding: 0;
223
+ border: 0;
224
+ border-radius: 50%;
225
+ background: none;
226
+ line-height: 0;
227
+ cursor: pointer;
228
+ }
229
+
230
+ .me-cover {
231
+ position: absolute;
232
+ inset: 0;
233
+ display: grid;
234
+ place-items: center;
235
+ border-radius: 50%;
236
+ background: rgba(0, 0, 0, 0.45);
237
+ color: #fff;
238
+ opacity: 0;
239
+ transition: opacity 0.12s;
240
+ }
241
+
242
+ .me-cover .icon {
243
+ width: 45%;
244
+ height: 45%;
245
+ }
246
+
247
+ .me:hover .me-cover,
248
+ .me:focus-visible .me-cover {
249
+ opacity: 1;
250
+ }
251
+
252
+ /* Where nothing hovers, a camera in the corner says the picture changes */
253
+ .me-badge {
254
+ position: absolute;
255
+ right: -2px;
256
+ bottom: -2px;
257
+ display: none;
258
+ place-items: center;
259
+ width: 18px;
260
+ height: 18px;
261
+ border-radius: 50%;
262
+ background: var(--accent);
263
+ color: var(--on-accent);
264
+ box-shadow: 0 0 0 2px var(--card);
265
+ }
266
+
267
+ .me-badge .icon {
268
+ width: 12px;
269
+ height: 12px;
270
+ }
271
+
272
+ @media (hover: none) {
273
+ .me-badge {
274
+ display: grid;
275
+ }
276
+ }
277
+
278
+ .profile-name {
279
+ display: inline-flex;
280
+ align-items: center;
281
+ gap: 2px;
282
+ min-width: 0;
283
+ max-width: 100%;
284
+ padding: 0;
285
+ border: 0;
286
+ background: none;
287
+ color: inherit;
288
+ font: inherit;
289
+ text-align: left;
290
+ cursor: pointer;
291
+ }
292
+
293
+ .profile-name span {
294
+ overflow: hidden;
295
+ white-space: nowrap;
296
+ text-overflow: ellipsis;
297
+ }
298
+
299
+ .profile-name .icon {
300
+ flex: none;
301
+ width: 15px;
302
+ height: 15px;
303
+ color: var(--soft);
304
+ }
305
+
306
+ .profile-name:hover,
307
+ .profile-name:hover .icon {
308
+ color: var(--accent);
309
+ }
310
+
311
+ /* The Torretta, whose eyes blink now and then, and its moods (D-70): a new face that pops in, never fading out, a red light when worried, out when sad, a light that breathes when
312
+ thoughtful */
313
+ .torretta .antenna {
314
+ fill: none;
315
+ stroke: var(--torretta-shade);
316
+ stroke-width: 4;
317
+ stroke-linecap: round;
318
+ }
319
+
320
+ .torretta .light {
321
+ fill: var(--torretta-light);
322
+ transition: fill 0.2s;
323
+ }
324
+
325
+ .torretta.mood-worried .light {
326
+ fill: var(--torretta-alarm);
327
+ }
328
+
329
+ .torretta.mood-thoughtful .light {
330
+ animation: ponder 2.4s ease-in-out infinite;
331
+ }
332
+
333
+ .torretta.mood-sad .light {
334
+ fill: var(--torretta-shade);
335
+ }
336
+
337
+ @keyframes ponder {
338
+ 50% {
339
+ fill: var(--torretta-ponder);
340
+ }
341
+ }
342
+
343
+ .torretta .expression.changed {
344
+ transform-box: fill-box;
345
+ transform-origin: center;
346
+ animation: face-in 0.16s ease-out;
347
+ }
348
+
349
+ @keyframes face-in {
350
+ from {
351
+ transform: scale(0.8);
352
+ }
353
+ }
354
+
355
+ .torretta .shade {
356
+ fill: var(--torretta-shade);
357
+ }
358
+
359
+ .torretta .body {
360
+ fill: var(--torretta-body);
361
+ }
362
+
363
+ .torretta .screen {
364
+ fill: var(--torretta-screen);
365
+ }
366
+
367
+ .torretta .eyes,
368
+ .torretta .mouth {
369
+ fill: var(--torretta-face);
370
+ }
371
+
372
+ .torretta .expression .line,
373
+ .torretta .brows {
374
+ fill: none;
375
+ stroke: var(--torretta-face);
376
+ stroke-width: 3.4;
377
+ stroke-linecap: round;
378
+ stroke-linejoin: round;
379
+ }
380
+
381
+ .torretta .eyes {
382
+ transform-box: fill-box;
383
+ transform-origin: center;
384
+ animation: blink 6s infinite;
385
+ }
386
+
387
+ @keyframes blink {
388
+ 0%,
389
+ 95%,
390
+ 100% {
391
+ transform: scaleY(1);
392
+ }
393
+
394
+ 97% {
395
+ transform: scaleY(0.1);
396
+ }
397
+ }
398
+
399
+ @media (prefers-reduced-motion: reduce) {
400
+ .torretta .eyes,
401
+ .torretta .expression.changed,
402
+ .torretta.mood-thoughtful .light {
403
+ animation: none;
404
+ }
405
+
406
+ .torretta .light {
407
+ transition: none;
408
+ }
409
+ }
410
+
411
+ /* The bubbles: the AI's under its card, the tail under the Torretta's centre (14 px of padding, 48 px picture), and the player's above their box */
412
+ .says,
413
+ .sent {
414
+ list-style: none;
415
+ margin: 0;
416
+ padding: 0;
417
+ display: flex;
418
+ flex-direction: column;
419
+ gap: 6px;
420
+ }
421
+
422
+ /* The bubbles never scroll: those that do not fit whole are hidden, and on the side away from the card they overflow toward */
423
+ .says {
424
+ overflow: hidden;
425
+ min-height: 0;
426
+ padding-top: 12px;
427
+ }
428
+
429
+ .says:empty {
430
+ display: none;
431
+ }
432
+
433
+ .say {
434
+ position: relative;
435
+ background: var(--say);
436
+ color: var(--say-ink);
437
+ border-radius: var(--bubble);
438
+ padding: 10px 13px;
439
+ font-size: 14.5px;
440
+ line-height: 1.45;
441
+ text-wrap: pretty;
442
+ overflow-wrap: anywhere;
443
+ }
444
+
445
+ .say:first-child::before {
446
+ content: "";
447
+ position: absolute;
448
+ left: 29px;
449
+ top: -10px;
450
+ border: 10px solid transparent;
451
+ border-top: 0;
452
+ border-bottom-color: var(--say);
453
+ }
454
+
455
+ .sent {
456
+ align-items: flex-end;
457
+ justify-content: flex-end;
458
+ margin-bottom: 8px;
459
+ overflow: hidden;
460
+ min-height: 0;
461
+ }
462
+
463
+ .sent li {
464
+ display: flex;
465
+ flex-direction: column;
466
+ align-items: flex-end;
467
+ max-width: 88%;
468
+ }
469
+
470
+ .said {
471
+ margin: 0;
472
+ background: var(--accent);
473
+ color: var(--on-accent);
474
+ border-radius: var(--bubble) var(--bubble) 4px var(--bubble);
475
+ padding: 8px 12px;
476
+ font-size: 14.5px;
477
+ line-height: 1.4;
478
+ text-wrap: pretty;
479
+ overflow-wrap: anywhere;
480
+ }
481
+
482
+ .status {
483
+ display: inline-flex;
484
+ align-items: center;
485
+ gap: 3px;
486
+ margin-top: 3px;
487
+ font-size: 12px;
488
+ color: var(--soft);
489
+ }
490
+
491
+ .status .icon {
492
+ width: 15px;
493
+ height: 15px;
494
+ stroke-width: 2;
495
+ }
496
+
497
+ .status.read {
498
+ color: var(--accent);
499
+ font-weight: 600;
500
+ }
501
+
502
+ /* The box the player writes in: a bubble whose tail points at their picture */
503
+ .compose {
504
+ position: relative;
505
+ background: var(--card);
506
+ border: 1px solid var(--line);
507
+ border-radius: var(--bubble);
508
+ padding: 8px 8px 8px 12px;
509
+ margin: 0 0 12px;
510
+ box-shadow: var(--shadow);
511
+ }
512
+
513
+ .compose::after {
514
+ content: "";
515
+ position: absolute;
516
+ left: 31px;
517
+ bottom: -8px;
518
+ width: 14px;
519
+ height: 14px;
520
+ background: var(--card);
521
+ border-right: 1px solid var(--line);
522
+ border-bottom: 1px solid var(--line);
523
+ transform: rotate(45deg);
524
+ border-bottom-right-radius: 3px;
525
+ }
526
+
527
+ .compose:focus-within,
528
+ .compose:focus-within::after {
529
+ border-color: var(--accent);
530
+ }
531
+
532
+ .compose textarea {
533
+ display: block;
534
+ width: 100%;
535
+ resize: none;
536
+ border: 0;
537
+ background: none;
538
+ padding: 2px 0;
539
+ font-size: 14.5px;
540
+ line-height: 1.45;
541
+ min-height: 44px;
542
+ max-height: 96px;
543
+ field-sizing: content;
544
+ outline: none;
545
+ }
546
+
547
+ .compose textarea::placeholder {
548
+ color: var(--soft);
549
+ }
550
+
551
+ .foot {
552
+ display: flex;
553
+ align-items: center;
554
+ justify-content: space-between;
555
+ gap: 8px;
556
+ margin-top: 4px;
557
+ }
558
+
559
+ .foot .hint,
560
+ .foot .count {
561
+ font-size: 12px;
562
+ color: var(--soft);
563
+ }
564
+
565
+ .foot .count {
566
+ font-variant-numeric: tabular-nums;
567
+ }
568
+
569
+ .send {
570
+ display: inline-flex;
571
+ align-items: center;
572
+ gap: 5px;
573
+ border: 0;
574
+ border-radius: 8px;
575
+ padding: 6px 10px 6px 12px;
576
+ background: var(--accent);
577
+ color: var(--on-accent);
578
+ font-size: 13.5px;
579
+ font-weight: 600;
580
+ }
581
+
582
+ .send .icon {
583
+ width: 15px;
584
+ height: 15px;
585
+ stroke-width: 2;
586
+ }
587
+
588
+ .send:disabled {
589
+ background: var(--quote);
590
+ color: var(--soft);
591
+ cursor: default;
592
+ }
593
+
594
+ .limit {
595
+ margin: 0 4px 6px 0;
596
+ padding: 7px 10px;
597
+ border-radius: 8px;
598
+ background: var(--warn-back);
599
+ color: var(--ink);
600
+ font-size: 13px;
601
+ line-height: 1.4;
602
+ }
603
+
604
+ .limit:empty {
605
+ display: none;
606
+ }
607
+
608
+ /* Turned round: the player on top, the AI below; the tails turn with them */
609
+ .flipped .talk,
610
+ .flipped .ai-block,
611
+ .flipped .you-block {
612
+ flex-direction: column-reverse;
613
+ }
614
+
615
+ .flipped .says {
616
+ justify-content: flex-end;
617
+ padding: 0 0 12px;
618
+ }
619
+
620
+ .flipped .say:first-child::before {
621
+ content: none;
622
+ }
623
+
624
+ .flipped .say:last-child::after {
625
+ content: "";
626
+ position: absolute;
627
+ left: 29px;
628
+ bottom: -10px;
629
+ border: 10px solid transparent;
630
+ border-bottom: 0;
631
+ border-top-color: var(--say);
632
+ }
633
+
634
+ .flipped .compose {
635
+ margin: 12px 0 0;
636
+ }
637
+
638
+ .flipped .compose::after {
639
+ bottom: auto;
640
+ top: -8px;
641
+ transform: rotate(225deg);
642
+ }
643
+
644
+ .flipped .sent {
645
+ justify-content: flex-start;
646
+ margin: 8px 0 0;
647
+ }
648
+
649
+ /* In analysis nothing in the talk gives way: on a short screen the talk scrolls whole */
650
+ .talk.studied {
651
+ overflow-y: auto;
652
+ }
653
+
654
+ .talk.studied > section,
655
+ .talk.studied > section > * {
656
+ flex: none;
657
+ }
658
+
659
+ .ai-note {
660
+ display: grid;
661
+ gap: 6px;
662
+ margin-top: 12px;
663
+ }
664
+
665
+ .ai-note .who {
666
+ display: flex;
667
+ align-items: center;
668
+ gap: 8px;
669
+ color: var(--soft);
670
+ font-size: 13px;
671
+ }
672
+
673
+ /* Who made the analysis, signed under the Torretta's name in the Torretta's height (D-81, Zoe's sketch A) */
674
+ .ai-note .signed {
675
+ display: flex;
676
+ flex-direction: column;
677
+ min-width: 0;
678
+ line-height: 1.25;
679
+ }
680
+
681
+ .ai-note .signed small {
682
+ font-size: 12px;
683
+ overflow-wrap: anywhere;
684
+ }
685
+
686
+ /* Only the note's last bubble has a tail, pointing down at the Torretta beside the AI's name, the board turned round or not */
687
+ .ai-note > .say::before,
688
+ .ai-note > .say::after {
689
+ content: none;
690
+ }
691
+
692
+ .ai-note > .say:has(+ .who)::after {
693
+ content: "";
694
+ position: absolute;
695
+ left: 8px;
696
+ bottom: -9px;
697
+ border: 10px solid transparent;
698
+ border-bottom: 0;
699
+ border-top-color: var(--say);
700
+ }
701
+
702
+ .ai-note > .say + .who {
703
+ margin-top: 4px;
704
+ }
705
+
706
+ /* In analysis the board turned round changes which side's card is on top, never the order of the talk */
707
+ .flipped .talk.studied,
708
+ .flipped .talk.studied > section {
709
+ flex-direction: column;
710
+ }
711
+
712
+ .move-note .head {
713
+ display: flex;
714
+ align-items: center;
715
+ gap: 6px;
716
+ }
717
+
718
+ /* The AI's judgment of the player's last move, with the helps on (D-78): a line that opens on its note */
719
+ .move-note.judged summary {
720
+ cursor: pointer;
721
+ list-style: none;
722
+ }
723
+
724
+ .move-note.judged summary::-webkit-details-marker {
725
+ display: none;
726
+ }
727
+
728
+ /* The note is the bubble's content: in the bubble's own ink, not the soft one of a side note (Zoe) */
729
+ .move-note .note {
730
+ display: block;
731
+ margin-top: 4px;
732
+ color: var(--say-ink);
733
+ font-size: 14.5px;
734
+ }
735
+
736
+ /* The words the AI put in bold, in the titles' colour; the squares and moves in its words in the accent too, to find on the board */
737
+ .say b {
738
+ color: var(--ink);
739
+ font-weight: 700;
740
+ }
741
+
742
+ .say .on-board {
743
+ color: var(--accent);
744
+ }
745
+
746
+ /* What the colours drawn with the note or the coach's hint mean, the ones it uses */
747
+ .legend {
748
+ display: flex;
749
+ flex-wrap: wrap;
750
+ gap: 2px 12px;
751
+ margin-top: 6px;
752
+ color: var(--soft);
753
+ font-size: 12px;
754
+ }
755
+
756
+ .legend > span {
757
+ display: inline-flex;
758
+ align-items: center;
759
+ gap: 5px;
760
+ }
761
+
762
+ .legend i {
763
+ width: 14px;
764
+ height: 3px;
765
+ border-radius: 2px;
766
+ background: var(--ring);
767
+ }
768
+
769
+ .legend .green {
770
+ --ring: var(--drawn-green);
771
+ }
772
+
773
+ .legend .red {
774
+ --ring: var(--drawn-red);
775
+ }
776
+
777
+ .legend .yellow {
778
+ --ring: var(--drawn-yellow);
779
+ }
780
+
781
+ .legend .blue {
782
+ --ring: var(--drawn-blue);
783
+ }
784
+
785
+ /* The move's number, which the list far below gives on a phone */
786
+ .move-note .move-number {
787
+ display: none;
788
+ margin-right: 2px;
789
+ color: var(--soft);
790
+ font-size: 12px;
791
+ font-weight: 400;
792
+ }
793
+
794
+ /* The page without its server, after /clear in Claude's app (Zoe): a card in the middle of the window, over the page that waits under it, dimmed and still;
795
+ its light breathes while the page tries again */
796
+ .offline {
797
+ position: fixed;
798
+ top: 50%;
799
+ left: 50%;
800
+ z-index: 20;
801
+ width: min(400px, calc(100vw - 32px));
802
+ margin: 0;
803
+ padding: 20px 24px;
804
+ transform: translate(-50%, -50%);
805
+ border: 1px solid color-mix(in oklab, var(--accent) 40%, var(--line));
806
+ border-radius: var(--radius);
807
+ background: var(--card);
808
+ color: var(--ink);
809
+ /* The dialogs' backdrop, over the whole window */
810
+ box-shadow: 0 0 0 100vmax rgba(16, 22, 29, 0.5), 0 16px 40px rgb(0 0 0 / 22%);
811
+ font-size: 15px;
812
+ line-height: 1.5;
813
+ text-align: center;
814
+ text-wrap: pretty;
815
+ }
816
+
817
+ .offline::before {
818
+ content: "";
819
+ display: block;
820
+ width: 10px;
821
+ height: 10px;
822
+ margin: 0 auto 12px;
823
+ border-radius: 50%;
824
+ background: var(--accent);
825
+ animation: reconnecting 1.6s ease-in-out infinite;
826
+ }
827
+
828
+ @keyframes reconnecting {
829
+ 50% {
830
+ opacity: 0.25;
831
+ }
832
+ }
833
+
834
+ /* Grey, darker and a little blurred, so it reads as stopped even when the board's theme is already grey */
835
+ .offline + .app {
836
+ filter: grayscale(1) brightness(0.85) blur(2px);
837
+ }
838
+
839
+ /* No chat hears the player (Zoe): a note under the AI's card, by its stopped clock, on a page still in use. The AI's words below it lose their tail */
840
+ .asleep {
841
+ flex: none;
842
+ margin: var(--between) 0 0;
843
+ padding: 10px 12px;
844
+ border: 1px solid color-mix(in oklab, var(--hover-edge) 55%, var(--line));
845
+ border-radius: var(--radius);
846
+ background: var(--warn-back);
847
+ color: var(--ink);
848
+ font-size: 13.5px;
849
+ line-height: 1.45;
850
+ text-wrap: pretty;
851
+ }
852
+
853
+ .flipped .asleep {
854
+ margin: 0 0 var(--between);
855
+ }
856
+
857
+ .ai-block:has(> .asleep) .say::before,
858
+ .ai-block:has(> .asleep) .say::after {
859
+ content: none;
860
+ }
861
+
862
+ /* With the talk folded, the same note and the button that starts the clocks over the board's edge on the AI's side, away from the squares of the player's
863
+ first move (Stefano); clicks go through the note to the squares, and both step aside for a lifted piece, a promotion and a refused move */
864
+ .over-board {
865
+ position: absolute;
866
+ top: 12px;
867
+ left: 50%;
868
+ z-index: 2;
869
+ display: flex;
870
+ flex-direction: column;
871
+ align-items: center;
872
+ gap: 8px;
873
+ width: min(460px, calc(100% - 24px));
874
+ transform: translateX(-50%);
875
+ pointer-events: none;
876
+ animation: appear 200ms;
877
+ }
878
+
879
+ .flipped .over-board {
880
+ top: auto;
881
+ bottom: 12px;
882
+ flex-direction: column-reverse;
883
+ }
884
+
885
+ .over-board > .asleep {
886
+ margin: 0;
887
+ box-shadow: 0 2px 6px rgb(0 0 0 / 14%), 0 10px 28px rgb(0 0 0 / 20%);
888
+ }
889
+
890
+ .over-board > .start-clocks {
891
+ flex: none;
892
+ padding: 9px 22px;
893
+ box-shadow: 0 2px 6px rgb(0 0 0 / 14%), 0 8px 20px rgb(0 0 0 / 22%);
894
+ pointer-events: auto;
895
+ }
896
+
897
+ :root.dragging .over-board,
898
+ .board-wrap:has(.promotion, .notice) > .over-board {
899
+ visibility: hidden;
900
+ }
901
+
902
+ /* A phone shows the talk whatever its fold: the note and the button stay in the cards */
903
+ @media (max-width: 840px) {
904
+ .over-board {
905
+ display: none;
906
+ }
907
+ }
908
+
909
+ @media (prefers-reduced-motion: reduce) {
910
+ .offline::before,
911
+ .over-board {
912
+ animation: none;
913
+ }
914
+ }
915
+
916
+ /* The AI's level on its card: a button that shows what it sees, under it where the browser anchors popovers, else in the middle */
917
+ .level-name {
918
+ margin: -4px -2px;
919
+ padding: 4px 2px;
920
+ border: 0;
921
+ border-radius: 4px;
922
+ background: none;
923
+ color: inherit;
924
+ font: inherit;
925
+ cursor: help;
926
+ text-decoration: underline dotted;
927
+ text-underline-offset: 3px;
928
+ anchor-name: --ai-level;
929
+ }
930
+
931
+ .level-tip {
932
+ max-width: min(280px, calc(100vw - 32px));
933
+ padding: 8px 10px;
934
+ border: 1px solid var(--line);
935
+ border-radius: 8px;
936
+ background: var(--card);
937
+ color: var(--ink);
938
+ font-size: 13px;
939
+ line-height: 1.35;
940
+ box-shadow: var(--shadow);
941
+ }
942
+
943
+ @supports (position-area: bottom) {
944
+ .level-tip {
945
+ position-anchor: --ai-level;
946
+ position-area: bottom span-right;
947
+ position-try-fallbacks: flip-block, flip-inline;
948
+ inset: auto;
949
+ margin: 6px 16px 6px 0;
950
+ }
951
+ }
952
+
953
+ /* On a phone, or in a narrow window, the number of the judged move shows in its note */
954
+ @media (max-width: 840px) {
955
+ .move-note .move-number {
956
+ display: inline;
957
+ }
958
+ }