chesspal 0.0.1 → 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 (273) hide show
  1. package/README.md +99 -2
  2. package/dist/cli/chat-hook.d.ts +2 -0
  3. package/dist/cli/chat-hook.js +33 -0
  4. package/dist/cli/cli.d.ts +2 -0
  5. package/dist/cli/cli.js +28 -0
  6. package/dist/cli/command-line.d.ts +7 -0
  7. package/dist/cli/command-line.js +177 -0
  8. package/dist/commands/agents.d.ts +26 -0
  9. package/dist/commands/agents.js +72 -0
  10. package/dist/commands/ai-move.d.ts +28 -0
  11. package/dist/commands/ai-move.js +85 -0
  12. package/dist/commands/ai-say.d.ts +22 -0
  13. package/dist/commands/ai-say.js +58 -0
  14. package/dist/commands/analyse-game.d.ts +65 -0
  15. package/dist/commands/analyse-game.js +265 -0
  16. package/dist/commands/annotate-game.d.ts +39 -0
  17. package/dist/commands/annotate-game.js +131 -0
  18. package/dist/commands/answer-lines.d.ts +28 -0
  19. package/dist/commands/answer-lines.js +144 -0
  20. package/dist/commands/clock.d.ts +15 -0
  21. package/dist/commands/clock.js +45 -0
  22. package/dist/commands/coach.d.ts +45 -0
  23. package/dist/commands/coach.js +344 -0
  24. package/dist/commands/context.d.ts +67 -0
  25. package/dist/commands/context.js +37 -0
  26. package/dist/commands/delete-game.d.ts +7 -0
  27. package/dist/commands/delete-game.js +30 -0
  28. package/dist/commands/delete-review.d.ts +8 -0
  29. package/dist/commands/delete-review.js +34 -0
  30. package/dist/commands/draw-offer.d.ts +10 -0
  31. package/dist/commands/draw-offer.js +43 -0
  32. package/dist/commands/drawings.d.ts +13 -0
  33. package/dist/commands/drawings.js +25 -0
  34. package/dist/commands/end-game.d.ts +23 -0
  35. package/dist/commands/end-game.js +67 -0
  36. package/dist/commands/export-game.d.ts +14 -0
  37. package/dist/commands/export-game.js +27 -0
  38. package/dist/commands/game-summary.d.ts +78 -0
  39. package/dist/commands/game-summary.js +102 -0
  40. package/dist/commands/index.d.ts +18 -0
  41. package/dist/commands/index.js +64 -0
  42. package/dist/commands/init.d.ts +15 -0
  43. package/dist/commands/init.js +73 -0
  44. package/dist/commands/lead-input.d.ts +8 -0
  45. package/dist/commands/lead-input.js +21 -0
  46. package/dist/commands/levels.d.ts +9 -0
  47. package/dist/commands/levels.js +25 -0
  48. package/dist/commands/look.d.ts +31 -0
  49. package/dist/commands/look.js +64 -0
  50. package/dist/commands/new-game.d.ts +68 -0
  51. package/dist/commands/new-game.js +218 -0
  52. package/dist/commands/opening-book.d.ts +13 -0
  53. package/dist/commands/opening-book.js +84 -0
  54. package/dist/commands/page-link.d.ts +11 -0
  55. package/dist/commands/page-link.js +28 -0
  56. package/dist/commands/past-games.d.ts +11 -0
  57. package/dist/commands/past-games.js +47 -0
  58. package/dist/commands/play-move.d.ts +37 -0
  59. package/dist/commands/play-move.js +94 -0
  60. package/dist/commands/player-move.d.ts +13 -0
  61. package/dist/commands/player-move.js +51 -0
  62. package/dist/commands/player-say.d.ts +5 -0
  63. package/dist/commands/player-say.js +16 -0
  64. package/dist/commands/ponder.d.ts +52 -0
  65. package/dist/commands/ponder.js +179 -0
  66. package/dist/commands/position.d.ts +14 -0
  67. package/dist/commands/position.js +130 -0
  68. package/dist/commands/profiles.d.ts +69 -0
  69. package/dist/commands/profiles.js +163 -0
  70. package/dist/commands/registry.d.ts +59 -0
  71. package/dist/commands/registry.js +62 -0
  72. package/dist/commands/say.d.ts +16 -0
  73. package/dist/commands/say.js +84 -0
  74. package/dist/commands/speech.d.ts +8 -0
  75. package/dist/commands/speech.js +20 -0
  76. package/dist/commands/status.d.ts +35 -0
  77. package/dist/commands/status.js +128 -0
  78. package/dist/commands/study-games.d.ts +5 -0
  79. package/dist/commands/study-games.js +40 -0
  80. package/dist/commands/study.d.ts +38 -0
  81. package/dist/commands/study.js +106 -0
  82. package/dist/commands/view.d.ts +14 -0
  83. package/dist/commands/view.js +125 -0
  84. package/dist/core/board-text.d.ts +7 -0
  85. package/dist/core/board-text.js +18 -0
  86. package/dist/core/book.json +1 -0
  87. package/dist/core/clock.d.ts +45 -0
  88. package/dist/core/clock.js +109 -0
  89. package/dist/core/facts.d.ts +55 -0
  90. package/dist/core/facts.js +175 -0
  91. package/dist/core/game.d.ts +95 -0
  92. package/dist/core/game.js +352 -0
  93. package/dist/core/illegal.d.ts +19 -0
  94. package/dist/core/illegal.js +141 -0
  95. package/dist/core/index.d.ts +20 -0
  96. package/dist/core/index.js +12 -0
  97. package/dist/core/lead.d.ts +15 -0
  98. package/dist/core/lead.js +40 -0
  99. package/dist/core/levels.d.ts +20 -0
  100. package/dist/core/levels.js +33 -0
  101. package/dist/core/material.d.ts +9 -0
  102. package/dist/core/material.js +12 -0
  103. package/dist/core/moods.d.ts +21 -0
  104. package/dist/core/moods.js +45 -0
  105. package/dist/core/openings.d.ts +35 -0
  106. package/dist/core/openings.js +98 -0
  107. package/dist/core/openings.json +1 -0
  108. package/dist/core/pgn.d.ts +10 -0
  109. package/dist/core/pgn.js +213 -0
  110. package/dist/core/profile.d.ts +117 -0
  111. package/dist/core/profile.js +232 -0
  112. package/dist/core/record.d.ts +21 -0
  113. package/dist/core/record.js +25 -0
  114. package/dist/core/review.d.ts +80 -0
  115. package/dist/core/review.js +146 -0
  116. package/dist/games/ai-model.d.ts +5 -0
  117. package/dist/games/ai-model.js +15 -0
  118. package/dist/games/analysis.d.ts +12 -0
  119. package/dist/games/analysis.js +26 -0
  120. package/dist/games/archive.d.ts +63 -0
  121. package/dist/games/archive.js +242 -0
  122. package/dist/games/chat-start.d.ts +16 -0
  123. package/dist/games/chat-start.js +26 -0
  124. package/dist/games/coach.d.ts +57 -0
  125. package/dist/games/coach.js +144 -0
  126. package/dist/games/current-game.d.ts +56 -0
  127. package/dist/games/current-game.js +134 -0
  128. package/dist/games/files.d.ts +9 -0
  129. package/dist/games/files.js +53 -0
  130. package/dist/games/index.d.ts +11 -0
  131. package/dist/games/index.js +12 -0
  132. package/dist/games/plans.d.ts +9 -0
  133. package/dist/games/plans.js +23 -0
  134. package/dist/games/table-talk.d.ts +12 -0
  135. package/dist/games/table-talk.js +25 -0
  136. package/dist/games/talk.d.ts +36 -0
  137. package/dist/games/talk.js +131 -0
  138. package/dist/games/thoughts.d.ts +15 -0
  139. package/dist/games/thoughts.js +60 -0
  140. package/dist/home/data-folder.d.ts +12 -0
  141. package/dist/home/data-folder.js +55 -0
  142. package/dist/home/index.d.ts +2 -0
  143. package/dist/home/index.js +3 -0
  144. package/dist/home/open-folder.d.ts +2 -0
  145. package/dist/home/open-folder.js +14 -0
  146. package/dist/host-files/agents.d.ts +20 -0
  147. package/dist/host-files/agents.js +53 -0
  148. package/dist/host-files/host-files.d.ts +15 -0
  149. package/dist/host-files/host-files.js +182 -0
  150. package/dist/host-files/index.d.ts +2 -0
  151. package/dist/host-files/index.js +3 -0
  152. package/dist/index.d.ts +2 -0
  153. package/dist/index.js +3 -0
  154. package/dist/page/app/anchor.js +88 -0
  155. package/dist/page/app/app.js +458 -0
  156. package/dist/page/app/keys.js +94 -0
  157. package/dist/page/app/phase.js +30 -0
  158. package/dist/page/app/served.js +73 -0
  159. package/dist/page/avatars/avatars.js +19 -0
  160. package/dist/page/avatars/beanie.webp +0 -0
  161. package/dist/page/avatars/beard.webp +0 -0
  162. package/dist/page/avatars/bun.webp +0 -0
  163. package/dist/page/avatars/cat.webp +0 -0
  164. package/dist/page/avatars/curls.webp +0 -0
  165. package/dist/page/avatars/glasses.webp +0 -0
  166. package/dist/page/avatars/moustache.webp +0 -0
  167. package/dist/page/avatars/owl.webp +0 -0
  168. package/dist/page/avatars/short-hair.webp +0 -0
  169. package/dist/page/avatars/silver-bob.webp +0 -0
  170. package/dist/page/avatars/thought.js +10 -0
  171. package/dist/page/avatars/torretta.js +38 -0
  172. package/dist/page/base.css +160 -0
  173. package/dist/page/board/board.css +959 -0
  174. package/dist/page/board/board.js +125 -0
  175. package/dist/page/board/explain.js +58 -0
  176. package/dist/page/board/marks.js +160 -0
  177. package/dist/page/board/motion.js +71 -0
  178. package/dist/page/board/pointer.js +239 -0
  179. package/dist/page/board/squares.js +26 -0
  180. package/dist/page/dialogs/analyses.js +195 -0
  181. package/dist/page/dialogs/dialog.js +26 -0
  182. package/dist/page/dialogs/dialogs.css +1228 -0
  183. package/dist/page/dialogs/new-game.js +42 -0
  184. package/dist/page/dialogs/profiles.js +152 -0
  185. package/dist/page/dialogs/search.js +31 -0
  186. package/dist/page/dialogs/settings.js +42 -0
  187. package/dist/page/dialogs/studied.js +39 -0
  188. package/dist/page/dialogs/study.js +51 -0
  189. package/dist/page/game/badges.js +50 -0
  190. package/dist/page/game/browse.js +17 -0
  191. package/dist/page/game/card-fold.js +40 -0
  192. package/dist/page/game/column.js +51 -0
  193. package/dist/page/game/ending.js +73 -0
  194. package/dist/page/game/game.css +577 -0
  195. package/dist/page/game/move-list.js +72 -0
  196. package/dist/page/game/opening-book.js +14 -0
  197. package/dist/page/game/plies.js +82 -0
  198. package/dist/page/game/result-tile.js +14 -0
  199. package/dist/page/helps/helps.css +689 -0
  200. package/dist/page/helps/helps.js +220 -0
  201. package/dist/page/helps/view.js +127 -0
  202. package/dist/page/layout/fold-tab.js +11 -0
  203. package/dist/page/layout/folds.js +43 -0
  204. package/dist/page/layout/header.js +28 -0
  205. package/dist/page/layout/layout.css +834 -0
  206. package/dist/page/lead/lead.js +82 -0
  207. package/dist/page/lead/view.js +38 -0
  208. package/dist/page/main.js +8 -0
  209. package/dist/page/pieces/CREDITS.md +19 -0
  210. package/dist/page/pieces/capablanca-small.svg +20 -0
  211. package/dist/page/pieces/capablanca.svg +22 -0
  212. package/dist/page/pieces/nitida-small.svg +20 -0
  213. package/dist/page/pieces/nitida.svg +21 -0
  214. package/dist/page/pieces/pieces.js +28 -0
  215. package/dist/page/pieces/torretta-small.svg +20 -0
  216. package/dist/page/pieces/torretta.svg +21 -0
  217. package/dist/page/players/card.js +56 -0
  218. package/dist/page/players/clock-time.js +12 -0
  219. package/dist/page/players/model-name.js +20 -0
  220. package/dist/page/profile/profile.js +99 -0
  221. package/dist/page/profile/settings.js +77 -0
  222. package/dist/page/sounds/capture.ogg +0 -0
  223. package/dist/page/sounds/check.ogg +0 -0
  224. package/dist/page/sounds/draw.ogg +0 -0
  225. package/dist/page/sounds/flag.ogg +0 -0
  226. package/dist/page/sounds/mate.ogg +0 -0
  227. package/dist/page/sounds/move.ogg +0 -0
  228. package/dist/page/sounds/offer.ogg +0 -0
  229. package/dist/page/sounds/resign.ogg +0 -0
  230. package/dist/page/sounds/sounds.js +105 -0
  231. package/dist/page/style.css +9 -0
  232. package/dist/page/talk/talk.css +958 -0
  233. package/dist/page/talk/talk.js +165 -0
  234. package/dist/page/talk/voice.js +38 -0
  235. package/dist/page/text.js +711 -0
  236. package/dist/page/theme.css +292 -0
  237. package/dist/profiles/avatar.d.ts +23 -0
  238. package/dist/profiles/avatar.js +84 -0
  239. package/dist/profiles/front-matter.d.ts +9 -0
  240. package/dist/profiles/front-matter.js +33 -0
  241. package/dist/profiles/index.d.ts +3 -0
  242. package/dist/profiles/index.js +5 -0
  243. package/dist/profiles/profiles.d.ts +69 -0
  244. package/dist/profiles/profiles.js +254 -0
  245. package/dist/profiles/settings.d.ts +12 -0
  246. package/dist/profiles/settings.js +46 -0
  247. package/dist/server/bell.d.ts +68 -0
  248. package/dist/server/bell.js +225 -0
  249. package/dist/server/caller.d.ts +21 -0
  250. package/dist/server/caller.js +132 -0
  251. package/dist/server/mcp.d.ts +13 -0
  252. package/dist/server/mcp.js +207 -0
  253. package/dist/server/page/analyses.d.ts +23 -0
  254. package/dist/server/page/analyses.js +65 -0
  255. package/dist/server/page/files.d.ts +5 -0
  256. package/dist/server/page/files.js +92 -0
  257. package/dist/server/page/game.d.ts +6 -0
  258. package/dist/server/page/game.js +381 -0
  259. package/dist/server/page/http.d.ts +29 -0
  260. package/dist/server/page/http.js +68 -0
  261. package/dist/server/page/page.d.ts +41 -0
  262. package/dist/server/page/page.js +229 -0
  263. package/dist/server/page/profiles.d.ts +19 -0
  264. package/dist/server/page/profiles.js +215 -0
  265. package/dist/version.d.ts +2 -0
  266. package/dist/version.js +3 -0
  267. package/instructions/analysis.md +4 -0
  268. package/instructions/analyst-agent.md +8 -0
  269. package/instructions/analyst.md +4 -0
  270. package/instructions/coach.md +11 -0
  271. package/instructions/opponent.md +15 -0
  272. package/instructions/ponder.md +9 -0
  273. package/package.json +66 -5
@@ -0,0 +1,73 @@
1
+ // How a game ended, as the page names it: by the board, or by a resignation or a draw agreed, which only the record's Termination tag says (D-37).
2
+ import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
3
+ /** How the game ended, from the board or the record's Termination tag; undefined while it goes on, or when the record does not say. */
4
+ export function howEnded(outcome, termination) {
5
+ if (outcome.over) {
6
+ return outcome.ending;
7
+ }
8
+ // Ours, and those of games played elsewhere (D-68): "Game drawn by agreement", Lichess's "Time forfeit", chess.com's "X won by resignation" in any of
9
+ // its languages, "X ha vinto per abbandono".
10
+ if (/^draw agreed$|by agreement|per accordo/i.test(termination ?? "")) {
11
+ return "agreement";
12
+ }
13
+ // A flag that fell: "Black lost on time", "Black ran out of time and White cannot mate".
14
+ if (/ (lost on|ran out of|won on) time\b|time forfeit|per tempo/i.test(termination ?? "")) {
15
+ return "time";
16
+ }
17
+ // "White resigns", or a draw (D-65): "White resigns and Black cannot mate".
18
+ return / resigns\b|by resignation|per abbandono/i.test(termination ?? "") ? "resignation" : undefined;
19
+ }
20
+ /**
21
+ * Whether the game ended a moment ago under the player's eyes, from going on to over, for as long as the page's effects on it last; a game already over when
22
+ * the page reads it does not count. `state` is undefined until the page has the game.
23
+ */
24
+ export function useJustEnded(state) {
25
+ const before = useRef(state);
26
+ const [just, setJust] = useState(false);
27
+ // Before the page paints: a frame of the end at rest would show before its effects.
28
+ useLayoutEffect(() => {
29
+ const ended = before.current === "going" && state === "over";
30
+ before.current = state;
31
+ if (!ended) {
32
+ return;
33
+ }
34
+ setJust(true);
35
+ const timer = setTimeout(() => setJust(false), effectsLast);
36
+ return () => {
37
+ clearTimeout(timer);
38
+ setJust(false);
39
+ };
40
+ }, [state]);
41
+ return just;
42
+ }
43
+ /**
44
+ * Whether the page saw the game end, from going on to over, while it stays over (D-77): its final position stays on the board until the next game. A game
45
+ * already over when the page reads it does not count. `state` is undefined until the page has the game.
46
+ */
47
+ export function useSawEnd(state) {
48
+ // Known in the render itself: a frame of the table set in place of the final position would cost the last move its slide.
49
+ const seen = useRef({ state, saw: false });
50
+ seen.current = seeEnd(seen.current, state);
51
+ return seen.current.saw;
52
+ }
53
+ /** What the page knows after reading the game again in `state`: it saw the end when the game went from going on to over, and while it stays over. */
54
+ export function seeEnd(before, state) {
55
+ return { state, saw: state === "over" && (before.saw || before.state === "going") };
56
+ }
57
+ /**
58
+ * Whether the AI declined the player's draw offer by its move (D-65): their offer gone with a move more and the game going on, until the next move. `moves`
59
+ * is how many the game has.
60
+ */
61
+ export function useDeclined(offer, moves, over) {
62
+ const before = useRef({ offer, moves });
63
+ const [declinedAt, setDeclinedAt] = useState(undefined);
64
+ useEffect(() => {
65
+ if (before.current.offer === "player" && offer === undefined && moves > before.current.moves && !over) {
66
+ setDeclinedAt(moves);
67
+ }
68
+ before.current = { offer, moves };
69
+ }, [offer, moves, over]);
70
+ return declinedAt === moves && !over;
71
+ }
72
+ /** How long the effects of a game over last, the longest of the style's: the board's, then the card's light. */
73
+ const effectsLast = 2800;
@@ -0,0 +1,577 @@
1
+ /* The game's column: the moves, the lead, the game's card and its commands */
2
+
3
+ /* The game's card, as tall as a player's across the board: a little board where the player's card has their face, round people, a square game */
4
+ .game-card {
5
+ margin: 0;
6
+ min-height: 74px;
7
+ display: flex;
8
+ align-items: center;
9
+ gap: 12px;
10
+ font-size: 13px;
11
+ }
12
+
13
+ .tile {
14
+ position: relative;
15
+ flex: none;
16
+ display: grid;
17
+ place-items: center;
18
+ width: 48px;
19
+ height: 48px;
20
+ border-radius: var(--radius);
21
+ /* A board of four squares in the skin's colours, the dark one at the bottom left as on a board */
22
+ background: conic-gradient(var(--dark-square) 0 25%, var(--light-square) 0 50%, var(--dark-square) 0 75%, var(--light-square) 0);
23
+ overflow: hidden;
24
+ }
25
+
26
+ .tile .piece {
27
+ --piece-edge-width: 7px;
28
+ width: 40px;
29
+ height: 40px;
30
+ }
31
+
32
+ /* The king to move, edged in the accent like the coin of whoever moves */
33
+ .tile.moving {
34
+ box-shadow: 0 0 0 2px var(--card), 0 0 0 4px var(--accent);
35
+ }
36
+
37
+ /* At the end both kings: side by side in a draw, the loser laid at the winner's feet */
38
+ .tile.over {
39
+ display: flex;
40
+ justify-content: center;
41
+ align-items: flex-end;
42
+ padding-bottom: 4px;
43
+ }
44
+
45
+ .tile.over .piece {
46
+ --piece-edge-width: 8px;
47
+ width: 30px;
48
+ height: 30px;
49
+ }
50
+
51
+ .tile.draw .piece + .piece {
52
+ margin-left: -12px;
53
+ }
54
+
55
+ .tile.win > span {
56
+ position: absolute;
57
+ display: grid;
58
+ }
59
+
60
+ .tile.win .piece {
61
+ width: 100%;
62
+ height: 100%;
63
+ }
64
+
65
+ .tile.win .up {
66
+ right: 5px;
67
+ bottom: 4px;
68
+ width: 28px;
69
+ height: 28px;
70
+ }
71
+
72
+ /* Laid down, the king is as wide as it was tall: it drops 5px to rest where the other stands */
73
+ .tile.win .down {
74
+ left: 4px;
75
+ bottom: -1px;
76
+ width: 24px;
77
+ height: 24px;
78
+ rotate: -90deg;
79
+ }
80
+
81
+ .game-card .what {
82
+ flex: 1;
83
+ min-width: 0;
84
+ line-height: 1.25;
85
+ }
86
+
87
+ .game-card p {
88
+ margin: 0;
89
+ }
90
+
91
+ .game-card .head,
92
+ .game-card .when {
93
+ color: var(--soft);
94
+ }
95
+
96
+ .game-card .big {
97
+ color: var(--ink);
98
+ font-size: 20px;
99
+ font-weight: 600;
100
+ font-variant-numeric: tabular-nums;
101
+ letter-spacing: -0.01em;
102
+ }
103
+
104
+ .game-card .when {
105
+ margin-top: 2px;
106
+ }
107
+
108
+ /* The game ended under the player's eyes: once the board has shown it, with the kings' badges, the card lights up in the accent and fades back */
109
+ .game-card.lit {
110
+ animation: lit 1200ms ease-out 1350ms;
111
+ }
112
+
113
+ @keyframes lit {
114
+ 20% {
115
+ box-shadow: 0 0 0 2px var(--accent), 0 0 18px color-mix(in srgb, var(--accent) 55%, transparent);
116
+ }
117
+ }
118
+
119
+ @media (prefers-reduced-motion: reduce) {
120
+ .game-card.lit {
121
+ animation: none;
122
+ }
123
+ }
124
+
125
+ /* Who is ahead, as the AI estimates it (D-90): White's share from the left, Black's from the right, the figure on the side ahead, as chess.com's bar; an edge
126
+ and a mark of the even game in the middle keep it a bar of two sides in both themes, never one of progress (Zoe) */
127
+ .lead-bar {
128
+ position: relative;
129
+ height: 14px;
130
+ margin-top: 6px;
131
+ border-radius: 7px;
132
+ background: #3b4048;
133
+ box-shadow: 0 0 0 1px rgb(138 144 153 / 0.6);
134
+ overflow: hidden;
135
+ }
136
+
137
+ .lead-bar::after {
138
+ content: "";
139
+ position: absolute;
140
+ inset: 3px auto 3px calc(50% - 0.5px);
141
+ width: 1px;
142
+ background: #8a9099;
143
+ }
144
+
145
+ /* On a position after the one the AI estimated: the player's move, until the coach speaks again */
146
+ .lead-bar.earlier {
147
+ opacity: 0.55;
148
+ }
149
+
150
+ .lead-bar .white {
151
+ position: absolute;
152
+ inset: 0 auto 0 0;
153
+ background: #f5f5f2;
154
+ transition: width 400ms ease;
155
+ }
156
+
157
+ @media (prefers-reduced-motion: reduce) {
158
+ .lead-bar .white {
159
+ transition: none;
160
+ }
161
+ }
162
+
163
+ .lead-bar .figure {
164
+ position: absolute;
165
+ top: 0;
166
+ font-size: 10px;
167
+ font-weight: 700;
168
+ line-height: 14px;
169
+ font-variant-numeric: tabular-nums;
170
+ }
171
+
172
+ .lead-bar .figure.white,
173
+ .lead-bar .figure.even {
174
+ left: 6px;
175
+ color: #2a2f36;
176
+ }
177
+
178
+ .lead-bar .figure.black {
179
+ right: 6px;
180
+ color: #f5f5f2;
181
+ }
182
+
183
+ /* The chart of the game in analysis: the white area is White's share, the line in the middle an even game; a dot on a move a badge marks, a line on the move
184
+ shown, gold as on the board and in the moves (Zoe) */
185
+ .lead-card {
186
+ display: grid;
187
+ gap: 8px;
188
+ }
189
+
190
+ .lead-chart {
191
+ position: relative;
192
+ height: 72px;
193
+ border-radius: 6px;
194
+ background: #3b4048;
195
+ box-shadow: 0 0 0 1px rgb(138 144 153 / 0.6);
196
+ overflow: hidden;
197
+ cursor: pointer;
198
+ }
199
+
200
+ .lead-chart svg {
201
+ display: block;
202
+ width: 100%;
203
+ height: 100%;
204
+ }
205
+
206
+ .lead-chart .white-area {
207
+ fill: #f5f5f2;
208
+ }
209
+
210
+ .lead-chart .pending {
211
+ fill: #5a606a;
212
+ }
213
+
214
+ .lead-chart .even {
215
+ stroke: #8a9099;
216
+ stroke-width: 1;
217
+ stroke-dasharray: 3 3;
218
+ fill: none;
219
+ }
220
+
221
+ .lead-chart .shown {
222
+ position: absolute;
223
+ top: 0;
224
+ bottom: 0;
225
+ width: 2px;
226
+ margin-left: -1px;
227
+ background: #ffc450;
228
+ box-shadow: 0 0 0 1px rgb(20 23 27 / 0.6);
229
+ pointer-events: none;
230
+ }
231
+
232
+ .lead-chart .dot {
233
+ position: absolute;
234
+ width: 8px;
235
+ height: 8px;
236
+ margin: -4px 0 0 -4px;
237
+ border-radius: 50%;
238
+ box-shadow: 0 0 0 1.5px #ffffff;
239
+ pointer-events: none;
240
+ }
241
+
242
+ .lead-chart .dot.brilliant {
243
+ background: var(--badge-brilliant);
244
+ }
245
+
246
+ .lead-chart .dot.great {
247
+ background: var(--badge-great);
248
+ }
249
+
250
+ .lead-chart .dot.miss {
251
+ background: var(--badge-miss);
252
+ }
253
+
254
+ .lead-chart .dot.mistake {
255
+ background: var(--badge-mistake);
256
+ }
257
+
258
+ .lead-chart .dot.blunder {
259
+ background: var(--badge-blunder);
260
+ }
261
+
262
+ .opening {
263
+ display: grid;
264
+ gap: 2px;
265
+ font-size: 13px;
266
+ }
267
+
268
+ .opening p {
269
+ margin: 0;
270
+ }
271
+
272
+ .opening .family {
273
+ display: flex;
274
+ align-items: center;
275
+ gap: 7px;
276
+ margin: 0;
277
+ font-size: inherit;
278
+ font-weight: inherit;
279
+ }
280
+
281
+ .opening .book {
282
+ display: grid;
283
+ align-self: center;
284
+ color: var(--accent);
285
+ }
286
+
287
+ .opening .book .icon {
288
+ width: 21px;
289
+ height: 21px;
290
+ stroke-width: 2.3;
291
+ }
292
+
293
+ .opening .book.out {
294
+ color: var(--ink);
295
+ }
296
+
297
+ .opening .variation {
298
+ color: var(--ink);
299
+ }
300
+
301
+ .opening .out {
302
+ color: var(--soft);
303
+ font-size: 12px;
304
+ }
305
+
306
+ /* A game in analysis (D-69): the AI's word on the whole game above the moves, and its note on the move shown in the talk, under the Torretta */
307
+ .review {
308
+ display: grid;
309
+ gap: 4px;
310
+ font-size: 13.5px;
311
+ line-height: 1.45;
312
+ }
313
+
314
+ .review.waiting,
315
+ .say.reviewing {
316
+ display: flex;
317
+ align-items: center;
318
+ gap: 8px;
319
+ margin: 0;
320
+ color: var(--soft);
321
+ }
322
+
323
+ .review ul {
324
+ margin: 0;
325
+ padding-left: 18px;
326
+ }
327
+
328
+ .review p,
329
+ .ai-note p {
330
+ margin: 0;
331
+ }
332
+
333
+ .review .head {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 6px;
337
+ color: var(--soft);
338
+ font-size: 12px;
339
+ }
340
+
341
+ /* The moves' card takes the column's room left: its title, then the list */
342
+ .moves-card {
343
+ flex: 1;
344
+ min-height: 120px;
345
+ display: flex;
346
+ flex-direction: column;
347
+ gap: 6px;
348
+ padding: 8px 10px;
349
+ }
350
+
351
+ .moves-card .card-title {
352
+ padding: 2px 4px 0;
353
+ }
354
+
355
+ /* Positioned, so that the moves' hidden names scroll with the list instead of stretching the page */
356
+ .moves {
357
+ position: relative;
358
+ flex: 1;
359
+ min-height: 0;
360
+ /* It scrolls with no scrollbar, kept on the move shown */
361
+ overflow: hidden auto;
362
+ scrollbar-width: none;
363
+ font-size: 14px;
364
+ }
365
+
366
+ .moves ol {
367
+ list-style: none;
368
+ margin: 0;
369
+ padding: 0;
370
+ }
371
+
372
+ .moves li {
373
+ display: grid;
374
+ grid-template-columns: 30px 1fr 1fr;
375
+ padding: 3px 6px;
376
+ border-radius: 5px;
377
+ }
378
+
379
+ .moves .result {
380
+ margin: 6px;
381
+ font-weight: 600;
382
+ }
383
+
384
+ .moves li:nth-child(even) {
385
+ background: var(--page);
386
+ }
387
+
388
+ .moves .number {
389
+ color: var(--soft);
390
+ }
391
+
392
+ /* A move is a button that shows it on the board; shown or not it keeps the same room, so stepping with the arrows never shifts the line (Stefano) */
393
+ .moves .ply {
394
+ justify-self: start;
395
+ display: inline-flex;
396
+ align-items: center;
397
+ gap: 4px;
398
+ padding: 1px 6px;
399
+ margin-left: -6px;
400
+ background: none;
401
+ border: 0;
402
+ border-radius: 5px;
403
+ color: inherit;
404
+ font: inherit;
405
+ cursor: pointer;
406
+ }
407
+
408
+ /* The move under the pointer in a neutral grey, never the accent, so it never reads as the move shown (Stefano) */
409
+ .moves .ply:hover {
410
+ background: color-mix(in oklab, var(--ink) 9%, transparent);
411
+ }
412
+
413
+ /* The move shown in the board's gold of the last move, laid on the light square as there, with dark ink in both themes: the yellow move in the list is the yellow
414
+ move on the board, and it follows the skin (Stefano) */
415
+ .moves .ply.current {
416
+ background: var(--light-square) linear-gradient(var(--last-move), var(--last-move));
417
+ color: var(--fixed-ink);
418
+ }
419
+
420
+ .moves .current .takes {
421
+ color: #4d5866;
422
+ }
423
+
424
+ /* A ring in the card's colour keeps a badge's disc whole on the gold */
425
+ .moves .current .move-badge {
426
+ border-radius: 50%;
427
+ box-shadow: 0 0 0 1.5px var(--card);
428
+ }
429
+
430
+ /* The buttons that step through the moves, under them as on Lichess and chess.com */
431
+ .steps {
432
+ display: flex;
433
+ gap: 4px;
434
+ padding: 4px;
435
+ }
436
+
437
+ .steps button {
438
+ flex: 1;
439
+ display: grid;
440
+ place-items: center;
441
+ padding: 6px 0;
442
+ background: none;
443
+ border: 1px solid transparent;
444
+ border-radius: 6px;
445
+ color: var(--ink);
446
+ cursor: pointer;
447
+ }
448
+
449
+ .steps button:hover:not(:disabled) {
450
+ background: var(--page);
451
+ border-color: var(--line);
452
+ }
453
+
454
+ .steps button:disabled {
455
+ color: var(--soft);
456
+ opacity: 0.5;
457
+ cursor: default;
458
+ }
459
+
460
+ .steps .icon {
461
+ width: 20px;
462
+ height: 20px;
463
+ stroke-width: 2;
464
+ }
465
+
466
+ /* A piece in a move: the set's small one, White's white and Black's black, edged so either shows on either theme */
467
+ .figurine {
468
+ display: inline-block;
469
+ width: 1.15em;
470
+ height: 1.15em;
471
+ margin-right: 0.05em;
472
+ vertical-align: -0.22em;
473
+ }
474
+
475
+ /* A capture's x is grey, so the squares of a move read first */
476
+ .takes {
477
+ color: var(--soft);
478
+ font-weight: 400;
479
+ }
480
+
481
+ /* In analysis, the game's own commands in the right column: save its PGN with the review, open the other analyses */
482
+ .analysis-actions {
483
+ display: flex;
484
+ gap: 8px;
485
+ padding: 8px;
486
+ }
487
+
488
+ .analysis-actions button {
489
+ flex: 1;
490
+ display: inline-flex;
491
+ align-items: center;
492
+ justify-content: center;
493
+ gap: 6px;
494
+ padding: 7px 10px;
495
+ border: 1px solid var(--line);
496
+ border-radius: 8px;
497
+ background: transparent;
498
+ color: var(--ink);
499
+ font: inherit;
500
+ font-size: 13px;
501
+ cursor: pointer;
502
+ }
503
+
504
+ .analysis-actions button:hover {
505
+ border-color: var(--accent);
506
+ }
507
+
508
+ /* Where the game's column runs under the board, the moves in two columns */
509
+ @media (max-width: 1099px) {
510
+ .moves ol {
511
+ columns: 2;
512
+ column-gap: 12px;
513
+ }
514
+
515
+ .moves li {
516
+ break-inside: avoid;
517
+ }
518
+ }
519
+
520
+ /* A card's title in the game's column, its icon in the accent as the opening's book: the helps' lifebuoy, the moves' score sheet (Stefano) */
521
+ .card-title {
522
+ display: flex;
523
+ align-items: center;
524
+ gap: 7px;
525
+ margin: 0;
526
+ font-size: 13px;
527
+ font-weight: 700;
528
+ color: var(--ink);
529
+ }
530
+
531
+ .card-title .icon {
532
+ width: 19px;
533
+ height: 19px;
534
+ stroke-width: 2.1;
535
+ color: var(--accent);
536
+ }
537
+
538
+ /* A card's title is the button that folds the card to it and opens it again, a chevron after the name (Stefano) */
539
+ .card-fold {
540
+ display: inline-flex;
541
+ align-items: center;
542
+ gap: 7px;
543
+ padding: 0;
544
+ border: 0;
545
+ background: none;
546
+ color: inherit;
547
+ font: inherit;
548
+ text-align: left;
549
+ cursor: pointer;
550
+ }
551
+
552
+ .card-fold .chevron {
553
+ flex: none;
554
+ width: 14px;
555
+ height: 14px;
556
+ fill: none;
557
+ stroke: var(--soft);
558
+ stroke-width: 1.8;
559
+ stroke-linecap: round;
560
+ stroke-linejoin: round;
561
+ }
562
+
563
+ .card-fold:hover .chevron,
564
+ .card-fold:focus-visible .chevron {
565
+ stroke: var(--accent);
566
+ }
567
+
568
+ /* A folded card is its title alone: the moves' gives the column's room back to the cards above */
569
+ .moves-card.folded {
570
+ flex: none;
571
+ min-height: 0;
572
+ }
573
+
574
+ /* The saves and the steps stay at the foot of the column, with the moves folded too (Stefano) */
575
+ .side > .moves-card + * {
576
+ margin-top: auto;
577
+ }