kward 0.69.1 → 0.71.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/pages.yml +1 -1
  3. data/CHANGELOG.md +68 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +90 -2
  6. data/README.md +30 -6
  7. data/Rakefile +96 -0
  8. data/doc/agent-tools.md +43 -0
  9. data/doc/api.md +92 -0
  10. data/doc/authentication.md +39 -25
  11. data/doc/configuration.md +2 -16
  12. data/doc/context-tools.md +70 -0
  13. data/doc/getting-started.md +3 -1
  14. data/doc/plugins.md +2 -2
  15. data/doc/releasing.md +14 -5
  16. data/doc/rpc.md +3 -11
  17. data/doc/session-management.md +220 -0
  18. data/doc/usage.md +13 -7
  19. data/doc/workspace-tools.md +105 -0
  20. data/lib/kward/cli/commands.rb +8 -0
  21. data/lib/kward/cli/openrouter_commands.rb +55 -0
  22. data/lib/kward/cli/prompt_interface.rb +85 -7
  23. data/lib/kward/cli/rendering.rb +11 -6
  24. data/lib/kward/cli/sessions.rb +454 -15
  25. data/lib/kward/cli/settings.rb +0 -30
  26. data/lib/kward/cli/slash_commands.rb +38 -11
  27. data/lib/kward/cli.rb +14 -0
  28. data/lib/kward/compactor.rb +4 -1
  29. data/lib/kward/config_files.rb +4 -6
  30. data/lib/kward/conversation.rb +49 -5
  31. data/lib/kward/model/client.rb +37 -50
  32. data/lib/kward/model/context_usage.rb +13 -6
  33. data/lib/kward/model/model_info.rb +92 -9
  34. data/lib/kward/model/payloads.rb +2 -0
  35. data/lib/kward/openrouter_model_cache.rb +120 -0
  36. data/lib/kward/plugin_registry.rb +47 -1
  37. data/lib/kward/prompt_interface/banner.rb +16 -51
  38. data/lib/kward/prompt_interface/composer_controller.rb +60 -87
  39. data/lib/kward/prompt_interface/composer_renderer.rb +7 -1
  40. data/lib/kward/prompt_interface/key_handler.rb +31 -10
  41. data/lib/kward/prompt_interface/layout.rb +2 -2
  42. data/lib/kward/prompt_interface/overlay_renderer.rb +24 -0
  43. data/lib/kward/prompt_interface/prompt_renderer.rb +23 -2
  44. data/lib/kward/prompt_interface/question_prompt.rb +34 -42
  45. data/lib/kward/prompt_interface/runtime_state.rb +6 -1
  46. data/lib/kward/prompt_interface/screen.rb +10 -4
  47. data/lib/kward/prompt_interface/selection_prompt.rb +518 -61
  48. data/lib/kward/prompt_interface/slash_overlay.rb +4 -4
  49. data/lib/kward/prompt_interface/transcript_buffer.rb +7 -16
  50. data/lib/kward/prompt_interface/transcript_renderer.rb +3 -3
  51. data/lib/kward/prompt_interface.rb +31 -32
  52. data/lib/kward/prompts/commands.rb +6 -3
  53. data/lib/kward/prompts.rb +2 -2
  54. data/lib/kward/rpc/server.rb +3 -8
  55. data/lib/kward/rpc/session_manager.rb +19 -8
  56. data/lib/kward/session_diff.rb +106 -9
  57. data/lib/kward/session_store.rb +23 -4
  58. data/lib/kward/session_tree_renderer.rb +2 -1
  59. data/lib/kward/telemetry/logger.rb +5 -3
  60. data/lib/kward/tool_output_compactor.rb +127 -0
  61. data/lib/kward/tools/base.rb +8 -2
  62. data/lib/kward/tools/registry.rb +37 -6
  63. data/lib/kward/tools/retrieve_tool_output.rb +71 -0
  64. data/lib/kward/tools/search/web.rb +2 -2
  65. data/lib/kward/tools/summarize_file_structure.rb +29 -0
  66. data/lib/kward/tools/tool_call.rb +2 -0
  67. data/lib/kward/version.rb +1 -1
  68. data/lib/kward/workspace.rb +58 -2
  69. data/templates/default/fulldoc/html/css/kward.css +570 -78
  70. data/templates/default/fulldoc/html/full_list.erb +107 -0
  71. data/templates/default/fulldoc/html/js/kward.js +259 -97
  72. data/templates/default/fulldoc/html/setup.rb +8 -0
  73. data/templates/default/kward_navigation.rb +91 -0
  74. data/templates/default/layout/html/layout.erb +59 -13
  75. data/templates/default/layout/html/setup.rb +34 -39
  76. metadata +13 -3
  77. data/lib/kward/resources/avatar_kward_logo.rb +0 -50
  78. data/lib/kward/resources/pixel_logo.rb +0 -232
@@ -10,10 +10,37 @@
10
10
  --kward-accent: #9caf35;
11
11
  --kward-accent-bright: #d2df62;
12
12
  --kward-code: #030604;
13
+ --kward-syntax-comment: #7f8b67;
14
+ --kward-syntax-constant: #f0bf6a;
15
+ --kward-syntax-keyword: #d2df62;
16
+ --kward-syntax-method: #b8d852;
17
+ --kward-syntax-string: #8fd15b;
18
+ --kward-syntax-symbol: #ff7f6f;
19
+ --kward-syntax-variable: #a7c884;
13
20
  }
14
21
 
15
22
  html {
16
23
  background: var(--kward-bg);
24
+ color-scheme: dark;
25
+ }
26
+
27
+ .kward-skip-link {
28
+ background: var(--kward-accent);
29
+ border-radius: 0 0 8px 8px;
30
+ color: #030604;
31
+ font-weight: 700;
32
+ left: 50%;
33
+ padding: 10px 20px;
34
+ position: fixed;
35
+ text-decoration: none;
36
+ top: 0;
37
+ transform: translateY(-100%);
38
+ transition: transform 120ms ease;
39
+ z-index: 9400;
40
+ }
41
+
42
+ .kward-skip-link:focus {
43
+ transform: translateY(0);
17
44
  }
18
45
 
19
46
  body.kward-docs {
@@ -28,15 +55,9 @@ body.kward-docs {
28
55
  min-height: 100%;
29
56
  opacity: 1;
30
57
  overflow: auto;
31
- transition: opacity 120ms ease;
32
58
  width: 100%;
33
59
  }
34
60
 
35
- html.kward-page-loading body.kward-docs {
36
- cursor: progress;
37
- opacity: 0.72;
38
- }
39
-
40
61
  body.kward-docs::before {
41
62
  background-image:
42
63
  linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px),
@@ -117,12 +138,31 @@ body.kward-docs::before {
117
138
  width: 1px;
118
139
  }
119
140
 
120
- .kward-guide-search {
141
+ .kward-guide-search,
142
+ .kward-api-index-link {
121
143
  justify-self: end;
144
+ }
145
+
146
+ .kward-guide-search {
122
147
  position: relative;
123
148
  width: min(280px, 24vw);
124
149
  }
125
150
 
151
+ .kward-api-index-link {
152
+ border: 1px solid rgba(156, 175, 53, 0.42);
153
+ border-radius: 999px;
154
+ color: var(--kward-ink);
155
+ padding: 10px 14px;
156
+ text-decoration: none;
157
+ white-space: nowrap;
158
+ }
159
+
160
+ .kward-api-index-link:hover,
161
+ .kward-api-index-link:focus {
162
+ background: rgba(156, 175, 53, 0.13);
163
+ color: var(--kward-accent-bright);
164
+ }
165
+
126
166
  .kward-guide-search input {
127
167
  background: rgba(3, 6, 4, 0.72);
128
168
  border: 1px solid rgba(156, 175, 53, 0.42);
@@ -180,6 +220,11 @@ body.kward-docs::before {
180
220
  color: var(--kward-ink);
181
221
  }
182
222
 
223
+ .kward-guide-search-results a.kward-search-active {
224
+ background: rgba(156, 175, 53, 0.2);
225
+ color: var(--kward-accent-bright);
226
+ }
227
+
183
228
  .kward-guide-search-results strong {
184
229
  color: var(--kward-accent-bright);
185
230
  display: block;
@@ -195,23 +240,58 @@ body.kward-docs::before {
195
240
  }
196
241
 
197
242
  .kward-nav-toggle {
243
+ align-items: center;
198
244
  background: transparent;
199
245
  border: 1px solid rgba(156, 175, 53, 0.52);
200
246
  border-radius: 8px;
201
247
  color: var(--kward-accent-bright);
202
248
  cursor: pointer;
203
249
  display: none;
250
+ flex-direction: column;
204
251
  font: inherit;
252
+ gap: 5px;
253
+ justify-content: center;
205
254
  justify-self: end;
206
- padding: 12px 16px;
255
+ padding: 10px 12px;
207
256
  text-decoration: none;
208
257
  }
209
258
 
259
+ .kward-nav-toggle-bar {
260
+ background: var(--kward-accent-bright);
261
+ border-radius: 2px;
262
+ display: block;
263
+ height: 2px;
264
+ transition: transform 140ms ease, opacity 140ms ease;
265
+ width: 22px;
266
+ }
267
+
268
+ body.kward-nav-open .kward-nav-toggle-bar:nth-child(1) {
269
+ transform: translateY(7px) rotate(45deg);
270
+ }
271
+
272
+ body.kward-nav-open .kward-nav-toggle-bar:nth-child(2) {
273
+ opacity: 0;
274
+ }
275
+
276
+ body.kward-nav-open .kward-nav-toggle-bar:nth-child(3) {
277
+ transform: translateY(-7px) rotate(-45deg);
278
+ }
279
+
210
280
  .kward-nav-toggle:hover {
211
281
  background: rgba(156, 175, 53, 0.12);
212
282
  color: var(--kward-accent-bright);
213
283
  }
214
284
 
285
+ /* Keyboard focus indicators for interactive elements. */
286
+ body.kward-docs a:focus-visible,
287
+ body.kward-docs button:focus-visible,
288
+ body.kward-docs input:focus-visible,
289
+ body.kward-docs .kward-nav-toggle:focus-visible,
290
+ body.kward-docs .kward-nav-menu-button:focus-visible {
291
+ outline: 2px solid var(--kward-accent-bright);
292
+ outline-offset: 2px;
293
+ }
294
+
215
295
  body.kward-docs .nav_wrap,
216
296
  body.kward-docs #resizer {
217
297
  display: none;
@@ -274,6 +354,90 @@ body.kward-docs code {
274
354
  border-radius: 6px;
275
355
  }
276
356
 
357
+ body.kward-docs pre.code .comment {
358
+ color: var(--kward-syntax-comment);
359
+ font-style: italic;
360
+ }
361
+
362
+ body.kward-docs pre.code .const,
363
+ body.kward-docs pre.code .constant,
364
+ body.kward-docs #content .summary_desc pre.code .const > .object_link a,
365
+ body.kward-docs #content .docstring pre.code .const > .object_link a {
366
+ color: var(--kward-syntax-constant);
367
+ }
368
+
369
+ body.kward-docs pre.code .kw,
370
+ body.kward-docs pre.code .rubyid_require,
371
+ body.kward-docs pre.code .rubyid_extend,
372
+ body.kward-docs pre.code .rubyid_include {
373
+ color: var(--kward-syntax-keyword);
374
+ font-weight: 700;
375
+ }
376
+
377
+ body.kward-docs pre.code .id,
378
+ body.kward-docs #content .summary_desc pre.code .id > .object_link a,
379
+ body.kward-docs #content .docstring pre.code .id > .object_link a {
380
+ color: var(--kward-syntax-method);
381
+ }
382
+
383
+ body.kward-docs pre.code .tstring_content,
384
+ body.kward-docs pre.code .heredoc_beg,
385
+ body.kward-docs pre.code .heredoc_end,
386
+ body.kward-docs pre.code .qwords_beg,
387
+ body.kward-docs pre.code .qwords_end,
388
+ body.kward-docs pre.code .qwords_sep,
389
+ body.kward-docs pre.code .words_beg,
390
+ body.kward-docs pre.code .words_end,
391
+ body.kward-docs pre.code .words_sep,
392
+ body.kward-docs pre.code .qsymbols_beg,
393
+ body.kward-docs pre.code .qsymbols_end,
394
+ body.kward-docs pre.code .qsymbols_sep,
395
+ body.kward-docs pre.code .symbols_beg,
396
+ body.kward-docs pre.code .symbols_end,
397
+ body.kward-docs pre.code .symbols_sep,
398
+ body.kward-docs pre.code .tstring,
399
+ body.kward-docs pre.code .dstring,
400
+ body.kward-docs pre.code .regexp,
401
+ body.kward-docs .dregexp {
402
+ color: var(--kward-syntax-string);
403
+ }
404
+
405
+ body.kward-docs pre.code .label,
406
+ body.kward-docs pre.code .symbol {
407
+ color: var(--kward-syntax-symbol);
408
+ }
409
+
410
+ body.kward-docs pre.code .ivar,
411
+ body.kward-docs pre.code .gvar,
412
+ body.kward-docs pre.code .rubyid_backref,
413
+ body.kward-docs pre.code .rubyid_nth_ref {
414
+ color: var(--kward-syntax-variable);
415
+ }
416
+
417
+ body.kward-docs pre.code .op,
418
+ body.kward-docs pre.code .period,
419
+ body.kward-docs pre.code .comma,
420
+ body.kward-docs pre.code .lparen,
421
+ body.kward-docs pre.code .rparen,
422
+ body.kward-docs pre.code .lbrace,
423
+ body.kward-docs pre.code .rbrace,
424
+ body.kward-docs pre.code .lbracket,
425
+ body.kward-docs pre.code .rbracket {
426
+ color: rgba(239, 232, 208, 0.74);
427
+ }
428
+
429
+ body.kward-docs pre.code a,
430
+ body.kward-docs pre.code a:visited {
431
+ text-decoration-color: rgba(210, 223, 98, 0.45);
432
+ text-decoration-thickness: 1px;
433
+ text-underline-offset: 2px;
434
+ }
435
+
436
+ body.kward-docs pre.code a:hover {
437
+ background: rgba(156, 175, 53, 0.16);
438
+ color: var(--kward-accent-bright);
439
+ }
440
+
277
441
  body.kward-docs .copy-code-button {
278
442
  background: transparent;
279
443
  border: 1px solid rgba(156, 175, 53, 0.48);
@@ -310,12 +474,13 @@ body.kward-docs #footer {
310
474
  }
311
475
 
312
476
  .kward-topnav,
313
- .kward-guide-search {
477
+ .kward-guide-search,
478
+ .kward-api-index-link {
314
479
  display: none;
315
480
  }
316
481
 
317
482
  .kward-nav-toggle {
318
- display: inline-block;
483
+ display: flex;
319
484
  }
320
485
 
321
486
 
@@ -371,6 +536,101 @@ body.kward-docs #footer {
371
536
  color: var(--kward-accent-bright);
372
537
  }
373
538
 
539
+ /*
540
+ Hero tagline "swosh": "Your terminal." flies out to the left and is
541
+ replaced by "Your RPC frontend." flying in from the right, then cycles
542
+ back. The second line mirrors it from the opposite side — "Your agent."
543
+ flies out to the right and is replaced by "Your engine." flying in from
544
+ the left — both lines swap in sync. Pure CSS — no JS. The global
545
+ @media (prefers-reduced-motion) rule above collapses the animation to
546
+ the static original copy ("Your terminal. Your agent.") so it remains
547
+ accessible and calm.
548
+ */
549
+ .kward-swosh {
550
+ box-sizing: content-box;
551
+ display: inline-block;
552
+ height: 0.98em;
553
+ line-height: 0.98;
554
+ margin: -0.16em -0.08em;
555
+ overflow: hidden;
556
+ padding: 0.16em 0.08em;
557
+ position: relative;
558
+ vertical-align: top;
559
+ }
560
+
561
+ .kward-hero h1 .kward-swosh-text {
562
+ color: var(--kward-ink);
563
+ display: inline-block;
564
+ line-height: 0.98;
565
+ white-space: nowrap;
566
+ will-change: transform, opacity;
567
+ }
568
+
569
+ /* The longer text ("Your RPC frontend.") stays in flow to size the box;
570
+ the shorter "Your terminal." overlays it absolutely. */
571
+ .kward-swosh-text-a {
572
+ left: 0.08em;
573
+ position: absolute;
574
+ top: 0.16em;
575
+ }
576
+
577
+ .kward-swosh-text-a {
578
+ animation: kward-swosh-a 12s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
579
+ }
580
+
581
+ .kward-swosh-text-b {
582
+ animation: kward-swosh-b 12s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
583
+ position: relative;
584
+ }
585
+
586
+ @keyframes kward-swosh-a {
587
+ 0%, 40% { transform: translateX(0); opacity: 1; filter: none; }
588
+ 50% { transform: translateX(-140%); opacity: 0; filter: blur(3px); }
589
+ 51%, 88% { transform: translateX(140%); opacity: 0; filter: none; }
590
+ 100% { transform: translateX(0); opacity: 1; filter: none; }
591
+ }
592
+
593
+ @keyframes kward-swosh-b {
594
+ 0%, 40% { transform: translateX(140%); opacity: 0; filter: none; }
595
+ 50% { transform: translateX(0); opacity: 1; filter: none; }
596
+ 88% { transform: translateX(0); opacity: 1; filter: none; }
597
+ 100% { transform: translateX(-140%); opacity: 0; filter: blur(3px); }
598
+ }
599
+
600
+ /*
601
+ Second line, mirrored: "Your agent." exits to the right while
602
+ "Your LLM engine." enters from the left (left-to-right), in sync with
603
+ the first swosh. Both texts keep the accent-bright color of the
604
+ original "Your agent." span.
605
+ */
606
+ .kward-hero h1 .kward-swosh-text-c {
607
+ animation: kward-swosh-c 12s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
608
+ color: var(--kward-accent-bright);
609
+ left: 0.08em;
610
+ position: absolute;
611
+ top: 0.16em;
612
+ }
613
+
614
+ .kward-hero h1 .kward-swosh-text-d {
615
+ animation: kward-swosh-d 12s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
616
+ color: var(--kward-accent-bright);
617
+ position: relative;
618
+ }
619
+
620
+ @keyframes kward-swosh-c {
621
+ 0%, 40% { transform: translateX(0); opacity: 1; filter: none; }
622
+ 50% { transform: translateX(140%); opacity: 0; filter: blur(3px); }
623
+ 51%, 88% { transform: translateX(-140%); opacity: 0; filter: none; }
624
+ 100% { transform: translateX(0); opacity: 1; filter: none; }
625
+ }
626
+
627
+ @keyframes kward-swosh-d {
628
+ 0%, 40% { transform: translateX(-140%); opacity: 0; filter: none; }
629
+ 50% { transform: translateX(0); opacity: 1; filter: none; }
630
+ 88% { transform: translateX(0); opacity: 1; filter: none; }
631
+ 100% { transform: translateX(140%); opacity: 0; filter: blur(3px); }
632
+ }
633
+
374
634
  .kward-lede {
375
635
  color: var(--kward-ink);
376
636
  font-size: 19px;
@@ -759,10 +1019,17 @@ body.kward-docs #content li,
759
1019
  body.kward-docs #filecontents p,
760
1020
  body.kward-docs #filecontents li {
761
1021
  color: var(--kward-ink);
1022
+ font-family: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
762
1023
  font-size: 17px;
763
1024
  line-height: 1.72;
764
1025
  }
765
1026
 
1027
+ body.kward-docs #filecontents p,
1028
+ body.kward-docs #filecontents li,
1029
+ body.kward-docs #content p {
1030
+ max-width: 72ch;
1031
+ }
1032
+
766
1033
  body.kward-docs #content ul,
767
1034
  body.kward-docs #filecontents ul,
768
1035
  body.kward-docs #content ol,
@@ -925,17 +1192,26 @@ body.kward-docs .kward-home #footer {
925
1192
  border-radius: 12px;
926
1193
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.48);
927
1194
  display: none;
928
- gap: 22px;
929
- grid-template-columns: repeat(4, minmax(170px, 1fr));
1195
+ gap: 16px;
1196
+ grid-template-columns: repeat(2, minmax(160px, 220px));
930
1197
  left: 50%;
1198
+ max-width: calc(100vw - 48px);
931
1199
  opacity: 0;
932
- padding: 28px 22px 22px;
1200
+ padding: 20px;
933
1201
  pointer-events: none;
934
1202
  position: absolute;
935
1203
  top: 100%;
936
1204
  transform: translate(-50%, -8px);
937
1205
  transition: opacity 140ms ease, transform 140ms ease;
938
- width: min(920px, calc(100vw - 48px));
1206
+ width: max-content;
1207
+ }
1208
+
1209
+ .kward-advanced-nav-dropdown {
1210
+ grid-template-columns: repeat(3, minmax(150px, 200px));
1211
+ }
1212
+
1213
+ .kward-api-nav-dropdown {
1214
+ grid-template-columns: repeat(2, minmax(170px, 210px));
939
1215
  }
940
1216
 
941
1217
  .kward-nav-dropdown::before {
@@ -991,69 +1267,107 @@ body.kward-docs .kward-home #footer {
991
1267
  }
992
1268
 
993
1269
  @media (max-width: 920px) {
994
- .kward-topnav {
1270
+ /* The nav panel: hidden until the hamburger is tapped. */
1271
+ body.kward-docs .kward-topnav {
995
1272
  background: rgba(5, 9, 5, 0.98);
996
1273
  border: 1px solid rgba(156, 175, 53, 0.32);
997
1274
  border-radius: 12px;
998
1275
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.48);
999
- display: none;
1000
- gap: 0;
1001
- height: auto;
1002
- left: 16px;
1003
- padding: 12px;
1276
+ display: none !important;
1277
+ flex-direction: column;
1278
+ gap: 2px;
1279
+ height: auto !important;
1280
+ left: 12px;
1281
+ max-height: calc(100vh - 100px);
1282
+ overflow-y: auto;
1283
+ padding: 8px;
1004
1284
  position: fixed;
1005
- right: 16px;
1285
+ right: 12px;
1006
1286
  top: 88px;
1007
1287
  z-index: 40;
1008
1288
  }
1009
1289
 
1010
- body.kward-nav-open .kward-topnav {
1011
- display: block;
1290
+ body.kward-docs.kward-nav-open .kward-topnav {
1291
+ display: flex !important;
1292
+ }
1293
+
1294
+ /* Every nav item: reset desktop stretch/height, force visibility. */
1295
+ body.kward-docs .kward-nav-menu,
1296
+ body.kward-docs .kward-topnav > a,
1297
+ body.kward-docs .kward-nav-menu-link,
1298
+ body.kward-docs .kward-nav-menu-button {
1299
+ height: auto !important;
1300
+ opacity: 1 !important;
1301
+ pointer-events: auto !important;
1302
+ visibility: visible !important;
1012
1303
  }
1013
1304
 
1014
- .kward-nav-menu {
1015
- display: block;
1305
+ body.kward-docs .kward-nav-menu {
1306
+ display: flex !important;
1307
+ flex-direction: column;
1308
+ position: relative;
1016
1309
  }
1017
1310
 
1018
- .kward-topnav > a,
1019
- .kward-nav-menu-link,
1020
- .kward-nav-menu-button {
1311
+ body.kward-docs .kward-topnav > a,
1312
+ body.kward-docs .kward-nav-menu-link {
1313
+ align-items: center;
1021
1314
  border: 0;
1022
1315
  border-radius: 8px;
1023
1316
  box-sizing: border-box;
1024
- display: inline-flex;
1025
- height: auto;
1026
- padding: 11px 12px;
1317
+ color: var(--kward-ink) !important;
1318
+ display: flex !important;
1319
+ font-weight: 700;
1320
+ padding: 14px 16px;
1321
+ text-decoration: none;
1322
+ width: 100%;
1027
1323
  }
1028
1324
 
1029
- .kward-topnav > a {
1030
- width: 100%;
1325
+ body.kward-docs .kward-nav-menu-button {
1326
+ display: none !important;
1031
1327
  }
1032
1328
 
1033
- .kward-nav-menu-link {
1034
- width: calc(100% - 48px);
1329
+ /* All dropdown links visible directly — no accordion on mobile. */
1330
+ body.kward-docs .kward-nav-dropdown {
1331
+ background: transparent !important;
1332
+ border: 0 !important;
1333
+ border-radius: 0 !important;
1334
+ box-shadow: none !important;
1335
+ display: block !important;
1336
+ grid-template-columns: 1fr !important;
1337
+ left: auto !important;
1338
+ opacity: 1 !important;
1339
+ padding: 0 0 4px 8px !important;
1340
+ pointer-events: auto !important;
1341
+ position: static !important;
1342
+ top: auto !important;
1343
+ transform: none !important;
1344
+ transition: none !important;
1345
+ width: auto !important;
1035
1346
  }
1036
1347
 
1037
- .kward-nav-menu-button {
1038
- justify-content: center;
1039
- width: 44px;
1348
+ body.kward-docs .kward-nav-dropdown section {
1349
+ margin-bottom: 2px;
1040
1350
  }
1041
1351
 
1042
- .kward-nav-dropdown {
1043
- background: rgba(255, 255, 255, 0.03);
1044
- border: 0;
1045
- box-shadow: none;
1046
- grid-template-columns: 1fr;
1047
- left: auto;
1048
- opacity: 1;
1049
- padding: 8px 0 8px 14px;
1050
- pointer-events: auto;
1051
- position: static;
1052
- top: auto;
1053
- transform: none;
1054
- width: auto;
1352
+ body.kward-docs .kward-nav-dropdown h2 {
1353
+ border-bottom: 0;
1354
+ color: var(--kward-muted);
1355
+ font-size: 11px;
1356
+ letter-spacing: 0.1em;
1357
+ margin: 8px 10px 4px;
1358
+ padding: 0;
1055
1359
  }
1056
1360
 
1361
+ body.kward-docs .kward-nav-dropdown a {
1362
+ border-radius: 8px;
1363
+ color: var(--kward-ink) !important;
1364
+ display: block !important;
1365
+ padding: 12px 14px;
1366
+ text-decoration: none;
1367
+ }
1368
+
1369
+ /* Search is hidden on mobile; it lives only in the desktop topbar. */
1370
+
1057
1371
  .kward-page {
1058
1372
  padding: 104px 16px 42px;
1059
1373
  }
@@ -1063,6 +1377,134 @@ body.kward-docs .kward-home #footer {
1063
1377
  }
1064
1378
  }
1065
1379
 
1380
+ /* YARD's class/method/file list pages use a separate full_list template. */
1381
+ .kward-full-list-body .kward-topbar {
1382
+ position: relative;
1383
+ }
1384
+
1385
+ .kward-full-list-body .kward-page {
1386
+ padding-top: 40px;
1387
+ }
1388
+
1389
+ .kward-full-list-body #content {
1390
+ background: var(--kward-panel-strong);
1391
+ border: 1px solid var(--kward-border);
1392
+ border-radius: 14px;
1393
+ box-shadow: 0 26px 70px rgba(0, 0, 0, 0.28);
1394
+ padding: 38px;
1395
+ }
1396
+
1397
+ .kward-full-list-body .fixed_header {
1398
+ background: transparent;
1399
+ height: auto;
1400
+ margin: 0 0 24px;
1401
+ padding: 0;
1402
+ position: static;
1403
+ width: auto;
1404
+ }
1405
+
1406
+ .kward-full-list-body #full_list_header {
1407
+ color: var(--kward-ink);
1408
+ font-size: clamp(36px, 5vw, 62px);
1409
+ letter-spacing: -0.04em;
1410
+ line-height: 0.98;
1411
+ margin: 0 0 18px;
1412
+ padding: 0;
1413
+ }
1414
+
1415
+ .kward-full-list-body #full_list_nav {
1416
+ color: var(--kward-muted);
1417
+ font-size: 14px;
1418
+ margin: 0 0 18px;
1419
+ }
1420
+
1421
+ .kward-full-list-body #full_list_nav a,
1422
+ .kward-full-list-body #full_list_nav a:visited {
1423
+ color: var(--kward-accent-bright);
1424
+ }
1425
+
1426
+ .kward-full-list-body #full_list_nav a:hover {
1427
+ color: #f0f7a0;
1428
+ }
1429
+
1430
+ .kward-full-list-body #search {
1431
+ color: var(--kward-muted);
1432
+ font-size: 14px;
1433
+ margin: 0;
1434
+ padding: 0;
1435
+ width: auto;
1436
+ }
1437
+
1438
+ .kward-full-list-body #search input {
1439
+ background: rgba(3, 6, 4, 0.72);
1440
+ border: 1px solid rgba(156, 175, 53, 0.42);
1441
+ border-radius: 999px;
1442
+ color: var(--kward-ink);
1443
+ font: inherit;
1444
+ margin-left: 8px;
1445
+ outline: none;
1446
+ padding: 8px 12px;
1447
+ width: min(260px, 60vw);
1448
+ }
1449
+
1450
+ .kward-full-list-body #search input:focus {
1451
+ border-color: var(--kward-accent-bright);
1452
+ box-shadow: 0 0 0 3px rgba(156, 175, 53, 0.18);
1453
+ }
1454
+
1455
+ .kward-full-list-body #full_list {
1456
+ background: rgba(3, 6, 4, 0.42);
1457
+ border: 1px solid rgba(156, 175, 53, 0.22);
1458
+ border-radius: 12px;
1459
+ font-size: 15px;
1460
+ margin: 0;
1461
+ overflow: auto;
1462
+ padding: 8px;
1463
+ }
1464
+
1465
+ .kward-full-list-body #full_list li {
1466
+ color: var(--kward-muted);
1467
+ }
1468
+
1469
+ .kward-full-list-body #full_list li.odd,
1470
+ .kward-full-list-body #full_list li.even {
1471
+ background: transparent;
1472
+ }
1473
+
1474
+ .kward-full-list-body #full_list li .item {
1475
+ border-radius: 8px;
1476
+ padding-bottom: 7px;
1477
+ padding-top: 7px;
1478
+ }
1479
+
1480
+ .kward-full-list-body #full_list .item:hover {
1481
+ background: rgba(156, 175, 53, 0.13);
1482
+ }
1483
+
1484
+ .kward-full-list-body #full_list a,
1485
+ .kward-full-list-body #full_list a:visited {
1486
+ color: var(--kward-ink);
1487
+ }
1488
+
1489
+ .kward-full-list-body #full_list a:hover {
1490
+ color: var(--kward-accent-bright);
1491
+ }
1492
+
1493
+ .kward-full-list-body #full_list li.clicked > .item {
1494
+ background: rgba(156, 175, 53, 0.22);
1495
+ color: var(--kward-ink);
1496
+ }
1497
+
1498
+ .kward-full-list-body #full_list li.clicked > .item a,
1499
+ .kward-full-list-body #full_list li.clicked > .item a:visited {
1500
+ color: var(--kward-accent-bright);
1501
+ }
1502
+
1503
+ .kward-full-list-body #noresults {
1504
+ background: transparent;
1505
+ color: var(--kward-muted);
1506
+ }
1507
+
1066
1508
  /* Pages no longer use YARD's iframe/sidebar layout. */
1067
1509
  .kward-page {
1068
1510
  box-sizing: border-box;
@@ -1295,37 +1737,12 @@ body.kward-docs .kward-nav-toggle {
1295
1737
  z-index: 9200;
1296
1738
  }
1297
1739
 
1298
- /* Mobile navigation fallback: make the toggle independent of YARD JS timing. */
1740
+ /* Mobile navigation: z-index and color highlights. */
1299
1741
  @media (max-width: 920px) {
1300
1742
  body.kward-docs .kward-topnav {
1301
1743
  z-index: 9300;
1302
1744
  }
1303
1745
 
1304
- body.kward-docs.kward-nav-open #kward-primary-nav,
1305
- body.kward-docs.kward-nav-open .kward-topnav {
1306
- display: block !important;
1307
- }
1308
- }
1309
-
1310
- /* Mobile uses tap state, not hover, for the Guides dropdown. */
1311
- @media (max-width: 920px) {
1312
- body.kward-docs .kward-nav-menu:hover .kward-nav-dropdown,
1313
- body.kward-docs .kward-nav-menu:focus-within .kward-nav-dropdown {
1314
- display: none;
1315
- }
1316
-
1317
- body.kward-docs .kward-nav-menu.open .kward-nav-dropdown {
1318
- display: grid;
1319
- opacity: 1;
1320
- pointer-events: auto;
1321
- transform: none;
1322
- }
1323
-
1324
- body.kward-docs .kward-nav-menu:hover .kward-nav-menu-link,
1325
- body.kward-docs .kward-nav-menu:hover .kward-nav-menu-button {
1326
- border-bottom-color: transparent;
1327
- }
1328
-
1329
1746
  body.kward-docs .kward-nav-menu.open .kward-nav-menu-link,
1330
1747
  body.kward-docs .kward-nav-menu.open .kward-nav-menu-button,
1331
1748
  body.kward-docs .kward-nav-menu.active .kward-nav-menu-link,
@@ -1418,7 +1835,10 @@ body.kward-docs #filecontents table {
1418
1835
  border: 1px solid rgba(149, 169, 52, 0.34);
1419
1836
  border-collapse: collapse;
1420
1837
  color: var(--kward-ink);
1421
- width: 100%;
1838
+ display: block;
1839
+ max-width: 100%;
1840
+ overflow-x: auto;
1841
+ width: fit-content;
1422
1842
  }
1423
1843
 
1424
1844
  body.kward-docs #content th,
@@ -1499,3 +1919,75 @@ body.kward-docs ul.toplevel a:active {
1499
1919
  color: #f0f7a0 !important;
1500
1920
  text-decoration: none;
1501
1921
  }
1922
+
1923
+ /* Respect users who prefer reduced motion. */
1924
+ @media (prefers-reduced-motion: reduce) {
1925
+ *,
1926
+ *::before,
1927
+ *::after {
1928
+ animation-duration: 0.01ms !important;
1929
+ animation-iteration-count: 1 !important;
1930
+ scroll-behavior: auto !important;
1931
+ transition-duration: 0.01ms !important;
1932
+ }
1933
+ }
1934
+
1935
+ /* Printable documentation: white background, black text, hide navigation. */
1936
+ @media print {
1937
+ body.kward-docs {
1938
+ background: #fff;
1939
+ color: #000;
1940
+ }
1941
+
1942
+ .kward-topbar,
1943
+ .kward-skip-link,
1944
+ .kward-guide-search,
1945
+ .kward-nav-toggle,
1946
+ #toc,
1947
+ .copy-code-button,
1948
+ .code-copy-wrapper .copy-code-button {
1949
+ display: none !important;
1950
+ }
1951
+
1952
+ body.kward-docs #content,
1953
+ body.kward-docs #filecontents {
1954
+ background: #fff;
1955
+ border: 0;
1956
+ box-shadow: none;
1957
+ color: #000;
1958
+ padding: 0;
1959
+ }
1960
+
1961
+ body.kward-docs #content h1,
1962
+ body.kward-docs #content h2,
1963
+ body.kward-docs #content h3,
1964
+ body.kward-docs #filecontents h1,
1965
+ body.kward-docs #filecontents h2,
1966
+ body.kward-docs #filecontents h3 {
1967
+ color: #000;
1968
+ }
1969
+
1970
+ body.kward-docs #content p,
1971
+ body.kward-docs #content li,
1972
+ body.kward-docs #filecontents p,
1973
+ body.kward-docs #filecontents li {
1974
+ color: #000;
1975
+ }
1976
+
1977
+ body.kward-docs #content a,
1978
+ body.kward-docs #filecontents a {
1979
+ color: #000;
1980
+ text-decoration: underline;
1981
+ }
1982
+
1983
+ body.kward-docs pre {
1984
+ background: #f4f4f4;
1985
+ border: 1px solid #ccc;
1986
+ color: #000;
1987
+ }
1988
+
1989
+ .kward-page {
1990
+ padding: 0;
1991
+ max-width: none;
1992
+ }
1993
+ }