kash-shell 0.3.25__py3-none-any.whl → 0.3.27__py3-none-any.whl

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 (46) hide show
  1. kash/actions/__init__.py +51 -6
  2. kash/actions/core/minify_html.py +2 -2
  3. kash/commands/base/general_commands.py +4 -2
  4. kash/commands/help/assistant_commands.py +4 -3
  5. kash/commands/help/welcome.py +1 -1
  6. kash/config/colors.py +7 -3
  7. kash/config/logger.py +4 -0
  8. kash/config/text_styles.py +1 -0
  9. kash/config/unified_live.py +249 -0
  10. kash/docs/markdown/assistant_instructions_template.md +3 -3
  11. kash/docs/markdown/topics/a1_what_is_kash.md +22 -20
  12. kash/docs/markdown/topics/a2_installation.md +10 -10
  13. kash/docs/markdown/topics/a3_getting_started.md +8 -8
  14. kash/docs/markdown/topics/a4_elements.md +3 -3
  15. kash/docs/markdown/topics/a5_tips_for_use_with_other_tools.md +12 -12
  16. kash/docs/markdown/topics/b0_philosophy_of_kash.md +17 -17
  17. kash/docs/markdown/topics/b1_kash_overview.md +7 -7
  18. kash/docs/markdown/topics/b2_workspace_and_file_formats.md +1 -1
  19. kash/docs/markdown/topics/b3_modern_shell_tool_recommendations.md +1 -1
  20. kash/docs/markdown/topics/b4_faq.md +7 -7
  21. kash/docs/markdown/welcome.md +1 -1
  22. kash/embeddings/embeddings.py +110 -39
  23. kash/embeddings/text_similarity.py +2 -2
  24. kash/exec/shell_callable_action.py +4 -3
  25. kash/help/help_embeddings.py +5 -2
  26. kash/mcp/mcp_server_sse.py +0 -5
  27. kash/model/graph_model.py +2 -0
  28. kash/model/items_model.py +4 -4
  29. kash/shell/output/shell_output.py +2 -2
  30. kash/shell/shell_main.py +64 -6
  31. kash/shell/version.py +18 -2
  32. kash/utils/file_utils/csv_utils.py +105 -0
  33. kash/utils/rich_custom/multitask_status.py +19 -5
  34. kash/web_gen/templates/base_styles.css.jinja +384 -31
  35. kash/web_gen/templates/base_webpage.html.jinja +43 -0
  36. kash/web_gen/templates/components/toc_styles.css.jinja +25 -4
  37. kash/web_gen/templates/components/tooltip_styles.css.jinja +2 -0
  38. kash/web_gen/templates/content_styles.css.jinja +23 -9
  39. kash/web_gen/templates/item_view.html.jinja +12 -4
  40. kash/web_gen/templates/simple_webpage.html.jinja +2 -2
  41. kash/xonsh_custom/custom_shell.py +6 -6
  42. {kash_shell-0.3.25.dist-info → kash_shell-0.3.27.dist-info}/METADATA +59 -56
  43. {kash_shell-0.3.25.dist-info → kash_shell-0.3.27.dist-info}/RECORD +46 -44
  44. {kash_shell-0.3.25.dist-info → kash_shell-0.3.27.dist-info}/WHEEL +0 -0
  45. {kash_shell-0.3.25.dist-info → kash_shell-0.3.27.dist-info}/entry_points.txt +0 -0
  46. {kash_shell-0.3.25.dist-info → kash_shell-0.3.27.dist-info}/licenses/LICENSE +0 -0
@@ -3,20 +3,49 @@
3
3
  font-size: 16px;
4
4
  /* Adding Hack Nerd Font to all fonts for icon support, if it is installed. */
5
5
  --font-sans: "Source Sans 3 Variable", sans-serif, "Hack Nerd Font";
6
- --font-serif: "PT Serif", serif, "Hack Nerd Font";
6
+ --font-serif: "LocalPunct", "PT Serif", serif, "Hack Nerd Font";
7
7
  /* Source Sans 3 Variable better at these weights. */
8
8
  --font-weight-sans-medium: 550;
9
9
  --font-weight-sans-bold: 650;
10
10
  --font-mono: "Hack Nerd Font", "Menlo", "DejaVu Sans Mono", Consolas, "Lucida Console", monospace;
11
11
 
12
+ --font-features-sans: normal;
13
+ {#
14
+ /* TODO: FontSource builds don't seem to support these. Might be nice to use. */
15
+ --font-features-sans:
16
+ "ss01" 0, /* Flat-tailed l */
17
+ "ss02" 1, /* Single-storey a */
18
+ "ss03" 0, /* Single-storey g */
19
+ "ss04" 0; /* Sans-bar I */
20
+ #}
21
+
12
22
  --font-size-large: 1.2rem;
13
23
  --font-size-normal: 1rem;
14
24
  --font-size-small: 0.95rem;
15
- --font-size-smaller: 0.85rem;
25
+ --font-size-smaller: 0.9rem;
26
+ --font-size-tiny: 0.85rem;
16
27
  --font-size-mono: 0.82rem;
17
28
  --font-size-mono-small: 0.75rem;
18
29
  --font-size-mono-tiny: 0.7rem;
19
30
 
31
+ --line-height-normal: 1.5;
32
+ --line-height-tight: 1.2;
33
+
34
+ /* Both Source Sans 3 and PT Serif have small caps, so we use this instead of text-transform. */
35
+ --caps-transform: none;
36
+ --caps-caps-variant: all-small-caps;
37
+ --caps-spacing: 0.021em;
38
+ /* Compensate for small caps (Source Sans small caps are quite small) */
39
+ --caps-heading-size-multiplier: 1.42;
40
+ --caps-heading-line-height: calc(1.2 / var(--caps-heading-size-multiplier));
41
+
42
+ {#
43
+ /* Option to handle small caps manually. */
44
+ --caps-transform: uppercase;
45
+ --caps-caps-variant: none;
46
+ --caps-spacing: 0.025em;
47
+ #}
48
+
20
49
  --console-char-width: 88;
21
50
  --console-width: calc(var(--console-char-width) + 2rem);
22
51
  {% endblock root_variables %}
@@ -82,7 +111,7 @@ html {
82
111
  body {
83
112
  font-family: var(--font-serif);
84
113
  color: var(--color-text);
85
- line-height: 1.5;
114
+ line-height: var(--line-height-normal);
86
115
  padding: 0; /* No padding so we can have full width elements. */
87
116
  margin: auto;
88
117
  background-color: var(--color-bg);
@@ -116,13 +145,8 @@ a:hover {
116
145
  transition: all 0.15s ease-in-out;
117
146
  }
118
147
 
119
- h1,
120
- h2,
121
- h3,
122
- h4,
123
- h5,
124
- h6 {
125
- line-height: 1.2;
148
+ h1, h2, h3, h4, h5, h6 {
149
+ line-height: var(--line-height-tight);
126
150
  }
127
151
 
128
152
  h1 {
@@ -132,7 +156,7 @@ h1 {
132
156
  }
133
157
 
134
158
  h2 {
135
- font-size: 1.42rem;
159
+ font-size: 1.32rem;
136
160
  margin-top: 2rem;
137
161
  margin-bottom: 1rem;
138
162
  }
@@ -152,7 +176,7 @@ h3 {
152
176
  }
153
177
 
154
178
  h4 {
155
- font-size: 1.1rem;
179
+ font-size: 1.12rem;
156
180
  margin-top: 1rem;
157
181
  margin-bottom: 0.7rem;
158
182
  }
@@ -176,7 +200,7 @@ h4+p, h5+p, h6+p {
176
200
  ul {
177
201
  list-style-type: none;
178
202
  margin-left: 1.8rem;
179
- margin-bottom: 1rem;
203
+ margin-bottom: 0.7rem;
180
204
  padding-left: 0;
181
205
  }
182
206
 
@@ -187,6 +211,7 @@ li {
187
211
  }
188
212
 
189
213
  li > p {
214
+ /* No extra padding for paragraphs inside list items. */
190
215
  margin-bottom: 0;
191
216
  }
192
217
 
@@ -209,10 +234,9 @@ ol > li {
209
234
  }
210
235
 
211
236
  blockquote {
212
- border-left: 2px solid var(--color-primary);
237
+ {# border-left: 1px solid var(--color-border-hairline); #}
213
238
  padding-left: 1rem;
214
- margin-left: 0;
215
- margin-right: 0;
239
+ margin: 1.5rem 4rem 1.5rem 1rem;
216
240
  }
217
241
 
218
242
  /* Inline code styling */
@@ -220,7 +244,6 @@ code {
220
244
  font-family: var(--font-mono);
221
245
  font-size: var(--font-size-mono);
222
246
  letter-spacing: -0.025em;
223
-
224
247
  transition: color 0.4s ease-in-out;
225
248
  }
226
249
  /* For code inside pre we style the pre tag */
@@ -301,13 +324,17 @@ img {
301
324
 
302
325
  details {
303
326
  font-family: var(--font-sans);
327
+ font-feature-settings: var(--font-features-sans);
304
328
  color: var(--color-text);
305
329
 
306
330
  border: 1px solid var(--color-hint-gentle);
307
- border-radius: 3px;
308
331
  margin: 0.75rem 0;
309
332
  }
310
333
 
334
+ details > :not(summary) {
335
+ padding: 0 0.75rem;
336
+ }
337
+
311
338
  summary {
312
339
  color: var(--color-secondary);
313
340
  padding: .5rem 1rem;
@@ -317,9 +344,12 @@ summary {
317
344
  transition: all 0.15s ease-in-out;
318
345
  }
319
346
 
347
+ summary::marker {
348
+ font-size: 0.85rem;
349
+ }
350
+
320
351
  summary:hover {
321
352
  color: var(--color-primary-light);
322
- {# background: var(--color-hover-bg); #}
323
353
  }
324
354
 
325
355
  /* keep the border on the summary when open so it blends */
@@ -332,6 +362,36 @@ summary:focus-visible {
332
362
  outline-offset: 2px;
333
363
  }
334
364
 
365
+ /* Special formatting for document metadata details */
366
+ details.metadata {
367
+ color: var(--color-tertiary);
368
+ }
369
+
370
+ details.metadata > :not(summary) {
371
+ color: var(--color-secondary);
372
+ }
373
+
374
+ details.metadata summary {
375
+ font-weight: 550;
376
+ font-size: calc(var(--font-size-small) * var(--caps-heading-size-multiplier));
377
+ line-height: var(--caps-heading-line-height);
378
+ text-transform: var(--caps-transform);
379
+ font-variant-caps: var(--caps-caps-variant);
380
+ letter-spacing: var(--caps-spacing);
381
+ color: var(--color-tertiary);
382
+ }
383
+
384
+ details.metadata summary:hover {
385
+ color: var(--color-primary-light);
386
+ }
387
+
388
+ details.metadata blockquote {
389
+ border-left: none;
390
+ margin: 0 0.75rem;
391
+ font-size: var(--font-size-small);
392
+ font-style: italic;
393
+ }
394
+
335
395
 
336
396
  hr {
337
397
  border: none;
@@ -375,15 +435,21 @@ hr:before {
375
435
 
376
436
  .long-text h3 {
377
437
  font-family: var(--font-sans);
438
+ font-feature-settings: var(--font-features-sans);
378
439
  font-weight: 550;
379
- text-transform: uppercase;
380
- letter-spacing: 0.025em;
440
+ font-size: calc(1.15rem * var(--caps-heading-size-multiplier));
441
+ line-height: var(--caps-heading-line-height);
442
+ text-transform: var(--caps-transform);
443
+ font-variant-caps: var(--caps-caps-variant);
444
+ letter-spacing: var(--caps-spacing);
381
445
  }
382
446
 
383
447
  .long-text h4 {
384
- font-family: var(--font-serif);
385
- font-weight: 400;
448
+ font-family: var(--font-sans);
449
+ font-feature-settings: var(--font-features-sans);
450
+ font-weight: 540;
386
451
  font-style: italic;
452
+ letter-spacing: 0.015em;
387
453
  }
388
454
 
389
455
  .long-text h5 {
@@ -407,6 +473,7 @@ hr:before {
407
473
 
408
474
  .long-text .sans-text {
409
475
  font-family: var(--font-sans);
476
+ font-feature-settings: var(--font-features-sans);
410
477
  }
411
478
 
412
479
  .long-text .sans-text p {
@@ -416,6 +483,7 @@ hr:before {
416
483
 
417
484
  .long-text .sans-text h1 {
418
485
  font-family: var(--font-sans);
486
+ font-feature-settings: var(--font-features-sans);
419
487
  font-size: 1.75rem;
420
488
  font-weight: 380;
421
489
  margin-top: 1rem;
@@ -424,6 +492,7 @@ hr:before {
424
492
 
425
493
  .long-text .sans-text h2 {
426
494
  font-family: var(--font-sans);
495
+ font-feature-settings: var(--font-features-sans);
427
496
  font-size: 1.25rem;
428
497
  font-weight: 440;
429
498
  margin-top: 1rem;
@@ -432,10 +501,13 @@ hr:before {
432
501
 
433
502
  .long-text .sans-text h3 {
434
503
  font-family: var(--font-sans);
435
- font-size: 1.1rem;
504
+ font-feature-settings: var(--font-features-sans);
436
505
  font-weight: var(--font-weight-sans-bold);
437
- text-transform: uppercase;
438
- letter-spacing: 0.03em;
506
+ font-size: calc(1.1rem * var(--caps-heading-size-multiplier));
507
+ line-height: var(--caps-heading-line-height);
508
+ text-transform: var(--caps-transform);
509
+ font-variant-caps: var(--caps-caps-variant);
510
+ letter-spacing: var(--caps-spacing);
439
511
  margin-top: 1rem;
440
512
  margin-bottom: 0.8rem;
441
513
  }
@@ -448,6 +520,7 @@ table, th, td, tbody tr {
448
520
 
449
521
  table {
450
522
  font-family: var(--font-sans);
523
+ font-feature-settings: var(--font-features-sans);
451
524
  font-size: var(--font-size-small);
452
525
  width: auto;
453
526
  margin-left: auto;
@@ -460,10 +533,12 @@ table {
460
533
 
461
534
  th {
462
535
  font-weight: var(--font-weight-sans-bold);
463
- text-transform: uppercase;
464
- letter-spacing: 0.03em;
536
+ font-size: calc(var(--font-size-small) * var(--caps-heading-size-multiplier));
537
+ line-height: var(--caps-heading-line-height);
538
+ text-transform: var(--caps-transform);
539
+ font-variant-caps: var(--caps-caps-variant);
540
+ letter-spacing: var(--caps-spacing);
465
541
  border-bottom: 1px solid var(--color-border-hint);
466
- line-height: 1.2;
467
542
  background-color: var(--color-bg-alt-solid);
468
543
  }
469
544
 
@@ -527,12 +602,16 @@ sup {
527
602
 
528
603
  .footnote-ref a, .footnote {
529
604
  font-family: var(--font-sans);
605
+ font-feature-settings: var(--font-features-sans);
606
+ background-color: var(--color-bg-meta-solid);
607
+ color: var(--color-hint-strong);
530
608
  text-decoration: none;
531
609
  padding: 0 0.15rem;
532
- border-radius: 4px;
610
+ margin-right: 0.15rem;
611
+ border-radius: 6px;
533
612
  transition: all 0.15s ease-in-out;
534
613
  font-style: normal;
535
- font-weight: 500;
614
+ font-weight: 600;
536
615
  }
537
616
 
538
617
  .footnote-ref a:hover, .footnote:hover {
@@ -540,8 +619,282 @@ sup {
540
619
  color: var(--color-primary-light);
541
620
  text-decoration: none;
542
621
  }
622
+
623
+ @media print {
624
+ sup {
625
+ /* Using small-caps so this is a bit larger */
626
+ font-size: 110% !important;
627
+ }
628
+
629
+ /* Don't use stylized footnotes in print. */
630
+ .footnote-ref a, .footnote {
631
+ font-family: var(--font-serif);
632
+ font-variant-caps: all-small-caps !important;
633
+ font-feature-settings: normal !important;
634
+ background-color: transparent !important;
635
+ color: var(--color-text) !important;
636
+ padding: 0 0.05rem !important;
637
+ font-weight: 400 !important;
638
+ }
639
+
640
+ .footnote-ref a:hover, .footnote:hover {
641
+ background-color: transparent !important;
642
+ color: var(--color-text) !important;
643
+ }
644
+
645
+ /* Hide footnote return arrows/links in print */
646
+ .footnote-backref,
647
+ .footnote-return,
648
+ a[href^="#fnref"],
649
+ .reversefootnote {
650
+ display: none !important;
651
+ }
652
+
653
+ /* Also hide common up arrow characters */
654
+ .footnote::after[content*="↩"],
655
+ .footnote::after[content*="↑"] {
656
+ display: none !important;
657
+ }
658
+ }
659
+
543
660
  {% endblock footnote_styles %}
544
661
 
662
+ {% block print_styles %}
663
+ /* Print media adjustments for better readability and layout */
664
+ @media print {
665
+ @page {
666
+ /* Set page margins for physical page */
667
+ margin: 0.7in 0.95in 0.8in 0.95in;
668
+
669
+ @top-center {
670
+ content: "";
671
+ }
672
+
673
+ @bottom-left {
674
+ content: "Formatted by Kash — github.com/jlevy/kash";
675
+ font-family: var(--font-sans) !important;
676
+ font-size: var(--font-size-small);
677
+ color: var(--color-tertiary) !important;
678
+ margin: 0 0 0.2in 0 !important;
679
+ }
680
+
681
+ @bottom-right {
682
+ content: counter(page);
683
+ font-family: var(--font-serif) !important;
684
+ font-size: var(--font-size-small);
685
+ color: var(--color-text) !important;
686
+ margin: 0 0 0.2in 0 !important;
687
+ }
688
+ }
689
+
690
+ :root {
691
+ /* Slightly larger fonts for print readability */
692
+ --font-size-normal: 1.1rem;
693
+ --font-size-small: 1.0rem;
694
+ --font-size-smaller: 0.9rem;
695
+ --font-size-mono: 0.9rem;
696
+
697
+ /* Tighter line height for print readability */
698
+ --line-height-normal: 1.4;
699
+ --line-height-tight: 1.15;
700
+ }
701
+
702
+ body {
703
+ /* Remove body margin since @page handles it */
704
+ margin: 0;
705
+ }
706
+
707
+ /* Reduce spacing between block elements to match tighter line height */
708
+ p {
709
+ margin-top: 0.65rem;
710
+ margin-bottom: 0.65rem;
711
+ }
712
+
713
+ li {
714
+ margin-top: 0.6rem;
715
+ }
716
+
717
+ /* Enable hyphenation and justification for main text content only */
718
+ p, blockquote {
719
+ hyphens: auto;
720
+ text-align: justify;
721
+ }
722
+
723
+ .long-text {
724
+ /* Remove shadows and borders that don't work well in print */
725
+ box-shadow: none !important;
726
+ border: none !important;
727
+ /* Add print-specific margins */
728
+ padding: 0;
729
+ }
730
+
731
+ /* Slightly darker sans-serif headings look better in print. */
732
+ .long-text h3 {
733
+ font-weight: 580;
734
+ }
735
+
736
+ .long-text h4 {
737
+ font-weight: 580;
738
+ }
739
+
740
+ /* Ensure tables don't break layout in print */
741
+ .table-container {
742
+ position: static;
743
+ transform: none;
744
+ left: auto;
745
+ width: 100%;
746
+ max-width: 100%;
747
+ overflow: visible;
748
+ }
749
+
750
+ table {
751
+ width: 100%;
752
+ max-width: 100%;
753
+ font-size: 0.9rem;
754
+ }
755
+
756
+ /* Adjust code blocks for print */
757
+ pre {
758
+ white-space: pre-wrap;
759
+ word-wrap: break-word;
760
+ background-color: transparent !important;
761
+ border: none !important;
762
+ font-weight: normal !important;
763
+ }
764
+
765
+ code {
766
+ background-color: transparent !important;
767
+ border: none !important;
768
+ font-weight: normal !important;
769
+ }
770
+
771
+ /* Hide interactive elements that don't work in print */
772
+ .code-copy-button {
773
+ display: none !important;
774
+ }
775
+
776
+ /* Page break controls */
777
+ h1, h2, h3, h4, h5, h6 {
778
+ break-after: avoid;
779
+ page-break-after: avoid; /* Fallback for older browsers */
780
+ break-inside: avoid;
781
+ page-break-inside: avoid; /* Fallback for older browsers */
782
+ }
783
+
784
+ /* Avoid breaking these elements */
785
+ blockquote, pre, .code-block-wrapper, figure, .table-container {
786
+ break-inside: avoid;
787
+ page-break-inside: avoid; /* Fallback for older browsers */
788
+ }
789
+
790
+ /* Control text flow */
791
+ p {
792
+ orphans: 3; /* Minimum lines at bottom of page */
793
+ widows: 3; /* Minimum lines at top of page */
794
+ }
795
+
796
+
797
+ /* Hide doc metadata details in print (for now) */
798
+ details.metadata {
799
+ display: none !important;
800
+ }
801
+
802
+ /* XXX: long endnote lists cut off the numbers. This is a workaround:
803
+ * Custom numbering system for ordered lists using Grid for alignment */
804
+ ol {
805
+ list-style: none;
806
+ counter-reset: list-counter;
807
+ padding-left: 0;
808
+ margin-left: 1rem;
809
+ }
810
+
811
+ ol > li {
812
+ display: grid;
813
+ /* col 1: fixed width for numbers up to 999. col 2: for the content */
814
+ grid-template-columns: 2.5rem 1fr;
815
+ gap: 0 0.5rem; /* Space between number and content */
816
+ align-items: baseline; /* Aligns number with first line of text */
817
+ counter-increment: list-counter;
818
+ /* Override global li styles for grid layout */
819
+ margin-top: 0;
820
+ margin-bottom: 0.5rem;
821
+ position: static;
822
+ }
823
+
824
+ ol > li::before {
825
+ content: counter(list-counter) ".";
826
+ text-align: right;
827
+ font-family: var(--font-serif);
828
+ }
829
+
830
+ /* Place all direct children of li into the second grid column */
831
+ /* This makes p, ul, etc. stack vertically as intended */
832
+ ol > li > * {
833
+ grid-column: 2;
834
+ word-break: break-word;
835
+ overflow-wrap: break-word;
836
+ hyphens: auto;
837
+ }
838
+
839
+ /* Override justification for content within list items */
840
+ ol > li p,
841
+ ol > li blockquote {
842
+ text-align: left !important;
843
+ text-justify: none !important;
844
+ margin-top: 0; /* Tighter spacing inside list items */
845
+ }
846
+
847
+ /* --- Reset for Nested Lists --- */
848
+ /* This prevents nested lists from inheriting the grid layout */
849
+ ol ol {
850
+ margin-left: 1.5rem;
851
+ margin-top: 0.5rem;
852
+ list-style: decimal outside;
853
+ counter-reset: initial; /* Don't inherit parent counter */
854
+ }
855
+
856
+ ol ul {
857
+ margin-left: 1.5rem;
858
+ margin-top: 0.5rem;
859
+ list-style: none; /* We'll restore bullets with ::before */
860
+ }
861
+
862
+ ol ol > li {
863
+ display: list-item !important; /* Revert from grid to standard list item */
864
+ padding-left: 0.25rem;
865
+ margin-top: 0.4rem; /* Override global li margin for tighter spacing */
866
+ position: static; /* Override global li position */
867
+ /* Override justification from parent rules */
868
+ text-align: left !important;
869
+ text-justify: none !important;
870
+ }
871
+
872
+ ol ul > li {
873
+ display: list-item !important; /* Revert from grid to standard list item */
874
+ padding-left: 0.25rem;
875
+ margin-top: 0.4rem; /* Override global li margin for tighter spacing */
876
+ position: relative; /* Need relative positioning for bullet ::before */
877
+ /* Override justification from parent rules */
878
+ text-align: left !important;
879
+ text-justify: none !important;
880
+ }
881
+
882
+ /* Remove the custom counter from nested ol */
883
+ ol ol > li::before {
884
+ content: "" !important;
885
+ }
886
+
887
+ /* Restore bullets for nested ul within ol */
888
+ ol ul > li::before {
889
+ content: "▪︎";
890
+ position: absolute;
891
+ left: -.85rem;
892
+ top: .25rem;
893
+ font-size: 0.62rem;
894
+ }
895
+ }
896
+ {% endblock print_styles %}
897
+
545
898
  {% block responsive_styles %}
546
899
  /* Bleed wide on larger screens. */
547
900
  /* TODO: Don't make so wide if table itself isn't large? */
@@ -10,6 +10,38 @@
10
10
 
11
11
  {% block title %}<title>{{ title }}</title>{% endblock title %}
12
12
 
13
+ {% block social_meta %}
14
+ {% if social_meta %}
15
+ <!-- Open Graph meta tags -->
16
+ <meta property="og:title" content="{{ social_meta.title or title }}" />
17
+ {% if social_meta.description %}
18
+ <meta property="og:description" content="{{ social_meta.description }}" />
19
+ {% endif %}
20
+ {% if social_meta.image %}
21
+ <meta property="og:image" content="{{ social_meta.image }}" />
22
+ {% endif %}
23
+ {% if social_meta.url %}
24
+ <meta property="og:url" content="{{ social_meta.url }}" />
25
+ {% endif %}
26
+ <meta property="og:type" content="{{ social_meta.type or 'website' }}" />
27
+ {% if social_meta.site_name %}
28
+ <meta property="og:site_name" content="{{ social_meta.site_name }}" />
29
+ {% endif %}
30
+ <!-- Twitter Card meta tags -->
31
+ <meta name="twitter:card" content="summary_large_image" />
32
+ <meta name="twitter:title" content="{{ social_meta.title or title }}" />
33
+ {% if social_meta.description %}
34
+ <meta name="twitter:description" content="{{ social_meta.description }}" />
35
+ {% endif %}
36
+ {% if social_meta.image %}
37
+ <meta name="twitter:image" content="{{ social_meta.image }}" />
38
+ {% endif %}
39
+ {% if social_meta.twitter_handle %}
40
+ <meta name="twitter:site" content="@{{ social_meta.twitter_handle }}" />
41
+ {% endif %}
42
+ {% endif %}
43
+ {% endblock social_meta %}
44
+
13
45
  {% block dark_mode_script %}
14
46
  <script>
15
47
  // Set theme before body renders to prevent flash of unstyled content
@@ -152,6 +184,17 @@
152
184
  src: url(https://cdn.jsdelivr.net/fontsource/fonts/pt-serif@latest/latin-700-italic.woff2) format('woff2');
153
185
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
154
186
  }
187
+ /* PT Serif has a known bug with quote alignment that can look quite ugly.
188
+ * https://nedbatchelder.com/blog/201809/fixing_pt_serif.html?utm_source=chatgpt.com
189
+ * So we use a workaround to use punctuation from a different local font.
190
+ * After trying a few, it seems Georgia is workable for quote marks an non-oriented ASCII quotes. */
191
+ @font-face {
192
+ font-family: 'LocalPunct';
193
+ src: local('Georgia');
194
+ unicode-range:
195
+ U+0022, U+0027, /* " ' */
196
+ U+2018, U+2019, U+201C, U+201D; /* ‘ ’ “ ” */
197
+ }
155
198
  /* https://fontsource.org/fonts/source-sans-3/cdn */
156
199
  /* source-sans-3-latin-wght-normal */
157
200
  @font-face {
@@ -84,15 +84,18 @@
84
84
  /* TOC Styling */
85
85
  .toc {
86
86
  font-family: var(--font-sans);
87
+ font-feature-settings: var(--font-features-sans);
87
88
  color: var(--color-tertiary);
88
89
  font-variant-numeric: tabular-nums;
89
90
  }
90
91
 
91
92
  .toc-title {
92
- font-size: var(--font-size-small);
93
93
  font-weight: 550;
94
- text-transform: uppercase;
95
- letter-spacing: 0.025em;
94
+ font-size: calc(var(--font-size-smaller) * var(--caps-heading-size-multiplier));
95
+ line-height: var(--caps-heading-line-height);
96
+ text-transform: var(--caps-transform);
97
+ font-variant-caps: var(--caps-caps-variant);
98
+ letter-spacing: var(--caps-spacing);
96
99
  padding-left: 0.3rem;
97
100
  border-bottom: 1px solid var(--color-border-hint);
98
101
  border-left: none !important; /* Override toc-link border */
@@ -102,7 +105,7 @@
102
105
  list-style: none;
103
106
  margin: 0.5rem 0 0 0;
104
107
  padding: 0;
105
- font-size: var(--font-size-small);
108
+ font-size: var(--font-size-smaller);
106
109
  line-height: 1.2;
107
110
  }
108
111
 
@@ -273,6 +276,15 @@ body.toc-open {
273
276
  .toc-link.active {
274
277
  color: var(--color-text);
275
278
  }
279
+
280
+ /* Slightly larger TOC font size on mobile */
281
+ .toc-title {
282
+ font-size: calc(var(--font-size-small) * var(--caps-heading-size-multiplier));
283
+ }
284
+
285
+ .toc-list {
286
+ font-size: var(--font-size-small);
287
+ }
276
288
 
277
289
  .toc-container.mobile-visible {
278
290
  /* Visible state */
@@ -281,4 +293,13 @@ body.toc-open {
281
293
  visibility: visible;
282
294
  pointer-events: auto; /* Re-enable interaction */
283
295
  }
296
+ }
297
+
298
+ @media print {
299
+ /* Hide TOC on print */
300
+ .toc-toggle,
301
+ .toc-backdrop,
302
+ .toc-container {
303
+ display: none !important;
304
+ }
284
305
  }
@@ -67,7 +67,9 @@
67
67
  border-left: 2px solid var(--color-primary);
68
68
  color: var(--color-text);
69
69
  font-family: var(--font-sans);
70
+ font-feature-settings: var(--font-features-sans);
70
71
  font-size: var(--font-size-small);
72
+ font-weight: 400;
71
73
  line-height: 1.4;
72
74
  padding: var(--tooltip-padding);
73
75
  border-radius: 0; /* Square corners for all tooltips */