explico 0.13.1 → 0.14.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 (239) hide show
  1. package/CHANGELOG.md +879 -1
  2. package/README.md +200 -30
  3. package/dist/compiler/astro.d.ts +15 -2
  4. package/dist/compiler/astro.js +40 -11
  5. package/dist/compiler/cli-main.d.ts +43 -0
  6. package/dist/compiler/cli-main.js +392 -0
  7. package/dist/compiler/cli.d.ts +424 -9
  8. package/dist/compiler/cli.js +1289 -8
  9. package/dist/compiler/collections.d.ts +88 -1
  10. package/dist/compiler/collections.js +170 -25
  11. package/dist/compiler/course-config.d.ts +1 -1
  12. package/dist/compiler/course-config.js +105 -1
  13. package/dist/compiler/decks.d.ts +161 -0
  14. package/dist/compiler/decks.js +235 -0
  15. package/dist/compiler/exports/combined-html.d.ts +5 -1
  16. package/dist/compiler/exports/deck-fit.d.ts +55 -0
  17. package/dist/compiler/exports/deck-fit.js +90 -0
  18. package/dist/compiler/exports/export-chapters.d.ts +37 -6
  19. package/dist/compiler/exports/export-chapters.js +64 -5
  20. package/dist/compiler/exports/export-pages.d.ts +30 -3
  21. package/dist/compiler/exports/export-pages.js +24 -1
  22. package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
  23. package/dist/compiler/exports/latex/cache.d.ts +78 -0
  24. package/dist/compiler/exports/latex/cache.js +129 -0
  25. package/dist/compiler/exports/latex/capture.d.ts +10 -1
  26. package/dist/compiler/exports/latex/capture.js +3 -1
  27. package/dist/compiler/exports/latex/compile.d.ts +13 -2
  28. package/dist/compiler/exports/latex/compile.js +12 -1
  29. package/dist/compiler/exports/latex/deck.d.ts +92 -0
  30. package/dist/compiler/exports/latex/deck.js +349 -0
  31. package/dist/compiler/exports/latex/document.d.ts +51 -6
  32. package/dist/compiler/exports/latex/document.js +71 -12
  33. package/dist/compiler/exports/latex/explico-common.sty +198 -0
  34. package/dist/compiler/exports/latex/explico.cls +13 -183
  35. package/dist/compiler/exports/latex/serialize.d.ts +60 -4
  36. package/dist/compiler/exports/latex/serialize.js +4 -2
  37. package/dist/compiler/exports/latex-export.d.ts +24 -2
  38. package/dist/compiler/exports/latex-export.js +107 -26
  39. package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
  40. package/dist/compiler/exports/markdown/serialize.js +85 -8
  41. package/dist/compiler/exports/markdown-export.d.ts +6 -1
  42. package/dist/compiler/exports/markdown-export.js +50 -11
  43. package/dist/compiler/exports/standalone-html.d.ts +10 -5
  44. package/dist/compiler/exports/standalone-html.js +3 -3
  45. package/dist/compiler/exports/static-tree.d.ts +38 -1
  46. package/dist/compiler/exports/static-tree.js +120 -4
  47. package/dist/compiler/knowledge-version.d.ts +26 -2
  48. package/dist/compiler/knowledge-version.js +27 -17
  49. package/dist/compiler/lesson-derivation.d.ts +143 -6
  50. package/dist/compiler/lesson-derivation.js +145 -13
  51. package/dist/compiler/manifest.d.ts +133 -4
  52. package/dist/compiler/manifest.js +359 -58
  53. package/dist/compiler/page-versions.d.ts +160 -0
  54. package/dist/compiler/page-versions.js +198 -0
  55. package/dist/compiler/render-diagnostics.d.ts +5 -1
  56. package/dist/compiler/resolution-report.d.ts +24 -6
  57. package/dist/compiler/resolution-report.js +22 -4
  58. package/dist/compiler/validate-content.d.ts +7 -0
  59. package/dist/compiler/validate-content.js +160 -0
  60. package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
  61. package/dist/curriculum/competency-graph.d.ts +54 -0
  62. package/dist/curriculum/competency-graph.js +41 -0
  63. package/dist/reference/base-library.d.mts +8 -0
  64. package/dist/reference/base-library.mjs +19 -0
  65. package/dist/reference/consistency.d.ts +8 -4
  66. package/dist/reference/consistency.js +76 -26
  67. package/dist/reference/deck-remark.d.mts +123 -0
  68. package/dist/reference/deck-remark.mjs +600 -0
  69. package/dist/reference/deck-source.d.ts +107 -0
  70. package/dist/reference/deck-source.js +140 -0
  71. package/dist/reference/decks-validate.d.ts +133 -0
  72. package/dist/reference/decks-validate.js +359 -0
  73. package/dist/reference/derived-entries.d.ts +5 -1
  74. package/dist/reference/diagram-fit.d.ts +1 -1
  75. package/dist/reference/figure-symbols.d.ts +23 -6
  76. package/dist/reference/figure-symbols.js +51 -15
  77. package/dist/reference/float-name.d.ts +43 -0
  78. package/dist/reference/float-name.js +58 -0
  79. package/dist/reference/folds-validate.d.ts +1 -1
  80. package/dist/reference/gate-abbreviations.d.ts +1 -1
  81. package/dist/reference/gate-indices.js +5 -4
  82. package/dist/reference/gate-math.d.ts +29 -2
  83. package/dist/reference/gate-math.js +99 -18
  84. package/dist/reference/gate-part-pages.d.ts +1 -1
  85. package/dist/reference/lab-katex-validate.d.ts +10 -6
  86. package/dist/reference/lab-katex-validate.js +17 -9
  87. package/dist/reference/lab-math-scope.js +29 -4
  88. package/dist/reference/math-glyphs.d.mts +25 -0
  89. package/dist/reference/math-glyphs.mjs +189 -25
  90. package/dist/reference/page-notation.d.ts +22 -3
  91. package/dist/reference/page-notation.js +32 -10
  92. package/dist/reference/references.d.ts +14 -1
  93. package/dist/reference/references.js +13 -0
  94. package/dist/reference/registry-scope.d.mts +33 -0
  95. package/dist/reference/registry-scope.mjs +34 -0
  96. package/dist/reference/registry.js +29 -10
  97. package/dist/reference/rehype-deck.d.mts +6 -0
  98. package/dist/reference/rehype-deck.mjs +286 -0
  99. package/dist/reference/rehype-heading-anchors.d.mts +20 -0
  100. package/dist/reference/rehype-heading-anchors.mjs +48 -6
  101. package/dist/reference/remark-notation.mjs +249 -40
  102. package/dist/reference/source-lines.d.mts +12 -0
  103. package/dist/reference/source-lines.mjs +65 -0
  104. package/dist/reference/types.d.ts +28 -0
  105. package/dist/rules/catalog.d.ts +21 -4
  106. package/dist/rules/catalog.js +221 -2
  107. package/dist/rules/course-rules.d.ts +5 -1
  108. package/dist/rules/course-rules.js +17 -3
  109. package/dist/rules/course-rules.schema.json +12 -0
  110. package/dist/rules/in-effect.d.ts +13 -3
  111. package/dist/rules/in-effect.js +30 -7
  112. package/dist/rules/rules.schema.json +259 -1
  113. package/dist/rules/settings.d.ts +1 -1
  114. package/dist/session/PreferenceStore.d.ts +6 -0
  115. package/dist/session/PreferenceStore.js +18 -1
  116. package/dist/session/deck-memory.d.ts +116 -0
  117. package/dist/session/deck-memory.js +143 -0
  118. package/dist/session/reading-memory.d.ts +96 -0
  119. package/dist/session/reading-memory.js +133 -0
  120. package/docs/VERSIONING.md +21 -18
  121. package/docs/authoring/README.md +29 -9
  122. package/docs/authoring/agents.md +63 -16
  123. package/docs/authoring/components.md +15 -0
  124. package/docs/authoring/deck.md +588 -0
  125. package/docs/authoring/migrating.md +1045 -16
  126. package/docs/authoring/notation.md +49 -6
  127. package/docs/authoring/structure.md +80 -1
  128. package/docs/authoring/versioning.md +54 -2
  129. package/docs/authoring/visualizations.md +7 -2
  130. package/docs/course-agent/AGENTS.md +37 -0
  131. package/docs/course-agent/agents/rules-reviewer.md +33 -0
  132. package/docs/course-agent/skills/draft-lesson/SKILL.md +37 -0
  133. package/docs/course-agent/skills/migrate-course/SKILL.md +31 -0
  134. package/docs/course-agent/skills/release-content/SKILL.md +24 -0
  135. package/docs/diagram-scaling.md +148 -0
  136. package/docs/privacy.md +59 -0
  137. package/package.json +8 -2
  138. package/src/compiler/astro.ts +60 -21
  139. package/src/compiler/cli-main.ts +469 -0
  140. package/src/compiler/cli.ts +1905 -16
  141. package/src/compiler/collections.ts +284 -25
  142. package/src/compiler/course-config.ts +267 -0
  143. package/src/compiler/decks.ts +455 -0
  144. package/src/compiler/exports/deck-fit.ts +127 -0
  145. package/src/compiler/exports/export-chapters.ts +105 -6
  146. package/src/compiler/exports/export-pages.ts +46 -2
  147. package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
  148. package/src/compiler/exports/latex/cache.ts +183 -0
  149. package/src/compiler/exports/latex/capture.ts +5 -2
  150. package/src/compiler/exports/latex/compile.ts +18 -0
  151. package/src/compiler/exports/latex/deck.ts +419 -0
  152. package/src/compiler/exports/latex/document.ts +117 -21
  153. package/src/compiler/exports/latex/explico-common.sty +198 -0
  154. package/src/compiler/exports/latex/explico.cls +13 -183
  155. package/src/compiler/exports/latex/serialize.ts +25 -21
  156. package/src/compiler/exports/latex/texlive-packages.txt +6 -2
  157. package/src/compiler/exports/latex-export.ts +187 -45
  158. package/src/compiler/exports/markdown/serialize.ts +118 -9
  159. package/src/compiler/exports/markdown-export.ts +56 -11
  160. package/src/compiler/exports/standalone-html.ts +8 -7
  161. package/src/compiler/exports/static-tree.ts +175 -3
  162. package/src/compiler/knowledge-version.ts +56 -21
  163. package/src/compiler/lesson-derivation.ts +282 -16
  164. package/src/compiler/manifest.ts +558 -63
  165. package/src/compiler/page-versions.ts +359 -0
  166. package/src/compiler/resolution-report.ts +38 -7
  167. package/src/compiler/validate-content.ts +212 -0
  168. package/src/components/CourseContents.astro +124 -6
  169. package/src/components/CurriculumMap.astro +49 -1
  170. package/src/components/FloatIndex.astro +1 -1
  171. package/src/components/PartOverview.astro +51 -5
  172. package/src/components/assessments/AssessmentSet.astro +41 -15
  173. package/src/components/block-heading.ts +15 -6
  174. package/src/components/card-carry.ts +7 -4
  175. package/src/components/card-manager.ts +14 -2
  176. package/src/components/card-memory.ts +13 -9
  177. package/src/components/deck/DeckEnhancer.astro +13 -0
  178. package/src/components/deck/deck-context.ts +104 -0
  179. package/src/components/deck/deck-controller.ts +1287 -0
  180. package/src/components/deck/deck-map.ts +91 -0
  181. package/src/components/deck-lane.ts +163 -0
  182. package/src/components/diagram/Diagram.astro +131 -86
  183. package/src/components/disclosure/persisted-disclosure.ts +9 -1
  184. package/src/components/figure/Figure.astro +7 -2
  185. package/src/components/figure/FloatCaption.astro +5 -3
  186. package/src/components/fold/Fold.astro +2 -2
  187. package/src/components/notation/NotationFormula.astro +81 -11
  188. package/src/components/notation/NotationGlossary.astro +132 -1
  189. package/src/components/notation/NotationLayer.astro +15 -7
  190. package/src/components/starlight/AboutPanel.astro +186 -3
  191. package/src/components/starlight/CollapsibleSections.astro +24 -3
  192. package/src/components/starlight/DiagramEnhancer.astro +5 -1
  193. package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
  194. package/src/components/starlight/LayoutHeader.astro +17 -0
  195. package/src/components/starlight/LayoutPageTitle.astro +110 -0
  196. package/src/components/starlight/LayoutSidebar.astro +807 -21
  197. package/src/components/starlight/LayoutSocialIcons.astro +62 -6
  198. package/src/components/starlight/LessonExportActions.astro +27 -9
  199. package/src/components/starlight/LessonFooter.astro +59 -0
  200. package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
  201. package/src/components/starlight/TextSizeControl.astro +24 -13
  202. package/src/components/starlight/page-marks.ts +139 -0
  203. package/src/components/starlight/section-summary.ts +1 -1
  204. package/src/components/starlight/sidebar-editions.ts +245 -0
  205. package/src/components/table/Table.astro +15 -7
  206. package/src/content-config.ts +87 -1
  207. package/src/curriculum/competency-graph.ts +95 -0
  208. package/src/reference/base-library.mjs +19 -0
  209. package/src/reference/consistency.ts +126 -39
  210. package/src/reference/deck-remark.mjs +600 -0
  211. package/src/reference/deck-source.ts +273 -0
  212. package/src/reference/decks-validate.ts +604 -0
  213. package/src/reference/diagram-layout.ts +3 -1
  214. package/src/reference/figure-symbols.ts +108 -31
  215. package/src/reference/folds-validate.ts +1 -1
  216. package/src/reference/gate-indices.ts +5 -3
  217. package/src/reference/gate-math.ts +169 -25
  218. package/src/reference/lab-katex-validate.ts +30 -15
  219. package/src/reference/lab-math-scope.ts +34 -3
  220. package/src/reference/math-glyphs.mjs +189 -25
  221. package/src/reference/page-notation.ts +69 -15
  222. package/src/reference/references.ts +28 -0
  223. package/src/reference/registry-scope.mjs +34 -0
  224. package/src/reference/registry.ts +41 -11
  225. package/src/reference/rehype-deck.mjs +286 -0
  226. package/src/reference/rehype-heading-anchors.mjs +48 -6
  227. package/src/reference/remark-notation.mjs +249 -40
  228. package/src/reference/source-lines.mjs +65 -0
  229. package/src/reference/types.ts +28 -0
  230. package/src/rules/catalog.ts +257 -4
  231. package/src/rules/course-rules.ts +21 -1
  232. package/src/rules/in-effect.ts +54 -8
  233. package/src/session/PreferenceStore.ts +23 -0
  234. package/src/session/deck-memory.ts +263 -0
  235. package/src/session/reading-memory.ts +243 -0
  236. package/src/styles/deck.css +1150 -0
  237. package/src/styles/global.css +958 -27
  238. package/src/styles/zones.css +277 -0
  239. /package/src/{components → reference}/float-name.ts +0 -0
@@ -1,5 +1,7 @@
1
1
  @import 'katex/dist/katex.min.css';
2
2
  @import './surfaces.css';
3
+ @import './zones.css';
4
+ @import './deck.css';
3
5
 
4
6
  :root {
5
7
  --sl-color-accent-low: #132f2a;
@@ -288,19 +290,31 @@ body {
288
290
 
289
291
  /* The reader's text size on a touch screen (`TextSizeControl.astro`): the
290
292
  root font size, which every `rem` follows, so the text, the math, the
291
- spacing and the cards scale together. Screen only: print keeps its own
292
- sizes, and a screen with hover has the browser's zoom instead. */
293
+ spacing and the cards scale together. The steps are a geometric series,
294
+ each 2^(1/4) (about 1.19) times the one below, from 50% to 100%.
295
+ `--explico-text-scale` is the same choice as a bare number, for what is
296
+ drawn in px and so does not follow the root: a diagram, scaled as a whole
297
+ (`Diagram.astro`). Screen only: print keeps its own sizes, and a screen
298
+ with hover has the browser's zoom instead. */
293
299
  @media screen and (hover: none) {
294
- :root[data-text-size='90'] {
295
- font-size: 90%;
300
+ :root[data-text-size='50'] {
301
+ --explico-text-scale: 0.5;
296
302
  }
297
303
 
298
- :root[data-text-size='80'] {
299
- font-size: 80%;
304
+ :root[data-text-size='59'] {
305
+ --explico-text-scale: 0.59;
300
306
  }
301
307
 
302
- :root[data-text-size='70'] {
303
- font-size: 70%;
308
+ :root[data-text-size='71'] {
309
+ --explico-text-scale: 0.71;
310
+ }
311
+
312
+ :root[data-text-size='84'] {
313
+ --explico-text-scale: 0.84;
314
+ }
315
+
316
+ :root[data-text-size] {
317
+ font-size: calc(var(--explico-text-scale, 1) * 100%);
304
318
  }
305
319
  }
306
320
 
@@ -594,8 +608,12 @@ a.explico-part-overview::before {
594
608
  /* The caret leads its part, the way a disclosure triangle leads the thing it
595
609
  opens: `>` collapsed, `v` open, in the reading direction before the name it
596
610
  applies to. Starlight parks it at the far end of the row instead, where it
597
- reads as a separate control that happens to share the line. */
598
- .layout-navigation-content summary {
611
+ reads as a separate control that happens to share the line. The three
612
+ `summary` rules here are for a part's header, and `:not(.about-toggle)`
613
+ keeps them off the `[?]` About button, which the phone menu also holds:
614
+ unlayered, they beat its own styles and made it a square with the `?`
615
+ at its start. */
616
+ .layout-navigation-content summary:not(.about-toggle) {
599
617
  justify-content: flex-start;
600
618
  gap: 0.25rem;
601
619
  }
@@ -645,6 +663,20 @@ details.layout-part-has-open > summary > .group-label {
645
663
  background: var(--sl-color-accent-low);
646
664
  }
647
665
 
666
+ /* `»` and the Overview row open the same page, so pointing at one lights
667
+ both. The control is a sibling before the part's list, so the row is
668
+ reachable from it; a compact part's tile has its own hover style (below,
669
+ in the `min-width: 50rem` block). The open part page needs no lighting. */
670
+ details.layout-part-has-open
671
+ > .layout-part-open:is(:hover, :focus-visible)
672
+ ~ ul
673
+ > li
674
+ > a.explico-part-overview:not([aria-current='page']) {
675
+ --explico-overview-gap: var(--ex-row-hover);
676
+ color: var(--sl-color-white);
677
+ background: var(--ex-row-hover);
678
+ }
679
+
648
680
  @media print {
649
681
  .layout-part-open {
650
682
  display: none;
@@ -653,18 +685,21 @@ details.layout-part-has-open > summary > .group-label {
653
685
 
654
686
  /* Both rails answer a pointer. Starlight changes only the text colour on
655
687
  hover, which on a list of 20 chapters is easy to lose track of; a filled row
656
- says which line the pointer is actually on. */
688
+ says which line the pointer is actually on. The fill is each rail's own
689
+ colour with a little ink in it (`--ex-row-hover`, `zones.css`), so it shows
690
+ on whatever colour the rail is: `gray-6` was the dark rail's own colour. */
657
691
  .layout-navigation-content a:not(.layout-part-open):hover,
658
692
  .layout-navigation-content a:not(.layout-part-open):focus-visible,
659
693
  .layout-page-sidebar-content a:hover,
660
694
  .layout-page-sidebar-content a:focus-visible {
695
+ --explico-overview-gap: var(--ex-row-hover);
661
696
  color: var(--sl-color-white);
662
- background: var(--sl-color-gray-6);
697
+ background: var(--ex-row-hover);
663
698
  }
664
699
 
665
700
  /* The part header answers a pointer like the rows under it — it is a control,
666
701
  and it was the one row in the panel that looked inert. */
667
- .layout-navigation-content summary {
702
+ .layout-navigation-content summary:not(.about-toggle) {
668
703
  border-radius: 0.25rem;
669
704
  }
670
705
 
@@ -677,9 +712,9 @@ details.layout-part-has-open > summary > .group-label {
677
712
  background: var(--sl-color-accent-low);
678
713
  }
679
714
 
680
- .layout-navigation-content summary:hover,
681
- .layout-navigation-content summary:focus-visible {
682
- background: var(--sl-color-gray-6);
715
+ .layout-navigation-content summary:not(.about-toggle):hover,
716
+ .layout-navigation-content summary:not(.about-toggle):focus-visible {
717
+ background: var(--ex-row-hover);
683
718
  }
684
719
 
685
720
  .layout-page-sidebar-content a:hover,
@@ -722,6 +757,647 @@ details.layout-part-has-open > summary > .group-label {
722
757
  }
723
758
  }
724
759
 
760
+ /* The reader's own marks (`page-marks.ts`, set by `LayoutSidebar.astro`): a
761
+ quiet ring beside a page they have not opened yet, an accent dot beside one
762
+ whose content changed since they last did. Both sit in the panel's margin
763
+ just past the row's end, out of the way of the title and the progress rail:
764
+ centred in the side padding (`--sl-sidebar-pad-x`, 1rem), so a mark takes no
765
+ room from a title and the marks line up in one column. */
766
+ .layout-navigation-content {
767
+ --page-mark-size: 0.4375rem;
768
+ }
769
+
770
+ .layout-navigation-content li[data-page-mark] {
771
+ position: relative;
772
+ }
773
+
774
+ .layout-navigation-content li[data-page-mark]::after,
775
+ .explico-page-marks-legend__item::before {
776
+ content: '';
777
+ box-sizing: border-box;
778
+ width: var(--page-mark-size);
779
+ height: var(--page-mark-size);
780
+ border-radius: 50%;
781
+ pointer-events: none;
782
+ }
783
+
784
+ .layout-navigation-content li[data-page-mark]::after {
785
+ position: absolute;
786
+ inset-block-start: 50%;
787
+ inset-inline-end: calc(var(--page-mark-size) / -2 - 0.5rem);
788
+ transform: translateY(-50%);
789
+ }
790
+
791
+ .layout-navigation-content li[data-page-mark='unopened']::after,
792
+ .explico-page-marks-legend__item[data-page-mark='unopened']::before {
793
+ border: 1.5px solid var(--sl-color-gray-4);
794
+ }
795
+
796
+ .layout-navigation-content li[data-page-mark='changed']::after,
797
+ .explico-page-marks-legend__item[data-page-mark='changed']::before {
798
+ background: var(--sl-color-text-accent);
799
+ }
800
+
801
+ /* A closed part (the phone's menu) keeps its marks out of sight; its label
802
+ carries the strongest one inside it, a change over a page not yet opened. */
803
+ .layout-navigation-content details[data-page-marks]:not([open]) > summary .group-label::after {
804
+ content: '';
805
+ display: inline-block;
806
+ box-sizing: border-box;
807
+ width: var(--page-mark-size);
808
+ height: var(--page-mark-size);
809
+ margin-inline-start: 0.45rem;
810
+ border: 1.5px solid var(--sl-color-gray-4);
811
+ border-radius: 50%;
812
+ vertical-align: 0.1em;
813
+ }
814
+
815
+ .layout-navigation-content details[data-page-marks~='changed']:not([open]) > summary .group-label::after {
816
+ border: 0;
817
+ background: var(--sl-color-text-accent);
818
+ }
819
+
820
+ /* A lesson's row (`sidebar-editions.ts`): it opens the lead edition under
821
+ the lesson's title, and the other edition is an icon at its end, as `»`
822
+ ends a part's header. The icon lies over the end of the row's own link,
823
+ which keeps room for it, so the row's hover and open-page fill run under
824
+ the icon, and pointing at the icon lights the icon alone. The icon's text
825
+ is its accessible name ("Slides: …"), shown only as the tooltip the
826
+ panel's script places; a compact part makes the icon a tile (below). */
827
+ .layout-navigation-content li[data-editions='pair'] {
828
+ position: relative;
829
+ }
830
+
831
+ .layout-navigation-content li[data-editions='pair'] > a:first-child {
832
+ padding-inline-end: 1.95rem;
833
+ }
834
+
835
+ /* Centred by its margins, not a transform: a transformed icon would hold its
836
+ tooltip's `position: fixed` inside itself, where the panel clips it. */
837
+ .layout-navigation-content li > a.layout-edition-other {
838
+ position: absolute;
839
+ inset-block: 0;
840
+ inset-inline-end: 0.25rem;
841
+ display: grid;
842
+ place-items: center;
843
+ width: 1.4rem;
844
+ height: 1.4rem;
845
+ margin-block: auto;
846
+ border-radius: 0.25rem;
847
+ padding: 0;
848
+ color: var(--sl-color-gray-3);
849
+ background: transparent;
850
+ }
851
+
852
+ /* With a part's deck open, the chapter whose section is on screen lights
853
+ its section's link (`aria-current="location"`, `LayoutSidebar.astro`) as
854
+ the open page lights its own: as a row's lead, as the icon, as a tile.
855
+ The chapter's own link beside it stays unlit. */
856
+ .layout-navigation-content li > a[data-deck-section][aria-current='location']:not(.layout-edition-other) {
857
+ font-weight: 600;
858
+ color: var(--sl-color-text-invert);
859
+ background-color: var(--sl-color-text-accent);
860
+ }
861
+
862
+ /* On the open page's row, the icon reads against the row's accent fill. */
863
+ .layout-navigation-content
864
+ li[data-editions='pair']
865
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
866
+ + a.layout-edition-other:not(:hover, :focus-visible) {
867
+ color: var(--sl-color-text-invert);
868
+ }
869
+
870
+ .layout-navigation-content li > a.layout-edition-other:hover,
871
+ .layout-navigation-content li > a.layout-edition-other:focus-visible {
872
+ color: var(--sl-color-text-accent);
873
+ background: var(--sl-color-accent-low);
874
+ }
875
+
876
+ .layout-navigation-content li > a.layout-edition-other:is([aria-current='page'], [data-deck-section][aria-current='location']) {
877
+ color: var(--sl-color-text-invert);
878
+ background: var(--sl-color-text-accent);
879
+ }
880
+
881
+ /* Overview as the icon at its part's deck's row end: its two sheets, the
882
+ sliver between them the icon's own ground. */
883
+ .layout-navigation-content li > a.layout-edition-other.explico-part-overview:is(:hover, :focus-visible) {
884
+ --explico-overview-gap: var(--sl-color-accent-low);
885
+ }
886
+
887
+ .layout-navigation-content
888
+ li[data-editions='pair']
889
+ > a[aria-current='page']
890
+ + a.layout-edition-other.explico-part-overview:not(:hover, :focus-visible) {
891
+ --explico-overview-gap: var(--sl-color-text-accent);
892
+ }
893
+
894
+ /* A link's second line (`sidebar-editions.ts`), inside its name's `<span>`:
895
+ a tooltip's quieter line (below), never a labelled row's text. */
896
+ .layout-edition-detail {
897
+ display: none;
898
+ }
899
+
900
+ .layout-navigation-content li > a.layout-edition-other > span {
901
+ position: absolute;
902
+ width: 1px;
903
+ height: 1px;
904
+ margin: -1px;
905
+ overflow: hidden;
906
+ clip-path: inset(50%);
907
+ white-space: nowrap;
908
+ }
909
+
910
+ /* The other edition's own mark, on its icon's corner as on a compact tile,
911
+ ringed in the panel's colour. An element of its own, `i.layout-edition-mark`,
912
+ since the icon's `::before` and `::after` draw its glyph. */
913
+ .layout-edition-mark {
914
+ display: none;
915
+ }
916
+
917
+ .layout-navigation-content a.layout-edition-other[data-page-mark] > .layout-edition-mark {
918
+ position: absolute;
919
+ z-index: 1;
920
+ display: block;
921
+ box-sizing: border-box;
922
+ inset-block-start: -0.15rem;
923
+ inset-inline-end: -0.15rem;
924
+ width: var(--page-mark-size);
925
+ height: var(--page-mark-size);
926
+ margin: 0;
927
+ border-radius: 50%;
928
+ background-color: var(--sl-color-bg-sidebar);
929
+ box-shadow: 0 0 0 2px var(--sl-color-bg-sidebar);
930
+ pointer-events: none;
931
+ }
932
+
933
+ .layout-navigation-content a.layout-edition-other[data-page-mark='unopened'] > .layout-edition-mark {
934
+ border: 1.5px solid var(--sl-color-gray-4);
935
+ }
936
+
937
+ .layout-navigation-content a.layout-edition-other[data-page-mark='changed'] > .layout-edition-mark {
938
+ background-color: var(--sl-color-text-accent);
939
+ }
940
+
941
+ /* On the open page's row the mark lies on the accent fill: drawn in the
942
+ fill's ink, as the icon is, ringed in the fill. */
943
+ .layout-navigation-content
944
+ li[data-editions='pair']
945
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
946
+ + a.layout-edition-other
947
+ > .layout-edition-mark {
948
+ border-color: var(--sl-color-text-invert);
949
+ background-color: var(--sl-color-text-accent);
950
+ box-shadow: 0 0 0 2px var(--sl-color-text-accent);
951
+ }
952
+
953
+ .layout-navigation-content
954
+ li[data-editions='pair']
955
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
956
+ + a.layout-edition-other[data-page-mark='changed']
957
+ > .layout-edition-mark {
958
+ background-color: var(--sl-color-text-invert);
959
+ }
960
+
961
+ /* A chapter's glyph: a sheet with lines of text on it, a mask over the
962
+ link's own colour, so it takes the link's colour in every state. A part is
963
+ two plain sheets (`a.explico-part-overview`), a deck a slide frame
964
+ (`deck.css`). */
965
+ :root {
966
+ --explico-chapter-glyph: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2015'%3E%3Cg%20fill='none'%20stroke='black'%20stroke-linecap='round'%3E%3Crect%20x='0.75'%20y='0.75'%20width='10.5'%20height='13.5'%20rx='1.6'%20stroke-width='1.5'/%3E%3Cpath%20d='M3.4%204.7h5.2M3.4%207.5h5.2M3.4%2010.3h3.2'%20stroke-width='1.3'/%3E%3C/g%3E%3C/svg%3E");
967
+ }
968
+
969
+ /* A lesson that is only a chapter while slides lead carries the chapter's
970
+ sheet before its title, as a slides-first lesson carries the deck's
971
+ (`deck.css`) while chapters lead: the exception is marked, nothing else.
972
+ The other edition's icon is the same sheet. A compact tile is a sheet
973
+ already. */
974
+ .sidebar-content a.explico-chapter-lesson,
975
+ .layout-navigation-content a.explico-chapter-lesson {
976
+ display: flex;
977
+ align-items: center;
978
+ gap: 0.45rem;
979
+ }
980
+
981
+ :is(a.explico-chapter-lesson, a.layout-edition-other[data-edition='chapter'])::before {
982
+ content: '';
983
+ flex: none;
984
+ width: 0.62rem;
985
+ height: 0.78rem;
986
+ background: currentColor;
987
+ -webkit-mask: var(--explico-chapter-glyph) center / contain no-repeat;
988
+ mask: var(--explico-chapter-glyph) center / contain no-repeat;
989
+ }
990
+
991
+ /* Forced colours paint a background as the canvas: a masked glyph keeps its
992
+ link's colour, the system's link colour then. */
993
+ @media (forced-colors: active) {
994
+ :is(a.explico-chapter-lesson, a.layout-edition-other[data-edition='chapter'])::before {
995
+ forced-color-adjust: none;
996
+ background: currentColor;
997
+ }
998
+ }
999
+
1000
+ /* The slides column: a contents list's decks (`CourseContents.astro`,
1001
+ `PartOverview.astro`, the cells from `deck-lane.ts`). When the course has
1002
+ a deck, each title starts with the glyph of what it opens, a part's
1003
+ heading with Overview's two sheets (`--explico-part-glyph`, the sidebar's
1004
+ bordered sheets as a mask), and every row ends in one 1.7rem column per
1005
+ lane. A lesson's own deck is a tile on its title line; a part's deck is a
1006
+ bar, one cell per row it covers, joined from the first covered title to
1007
+ the last. A list sets how its rows meet: `--deck-lane-rows`, the grid
1008
+ rows a bar's cell spans; `--deck-lane-down`, from a row's content to the
1009
+ line under it; `--deck-lane-up`, from that line to the next row's
1010
+ content. A cell reaches the line by negative margins, so the pieces join
1011
+ with no `subgrid`, and the line shows faintly across the bar. */
1012
+ :root {
1013
+ --explico-part-glyph: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2014%2016'%3E%3Cg%20fill='none'%20stroke='black'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3.6%200.75h7.9a1.75%201.75%200%200%201%201.75%201.75v9.6'/%3E%3Crect%20x='0.75'%20y='3.25'%20width='9.6'%20height='12'%20rx='1.6'/%3E%3C/g%3E%3C/svg%3E");
1014
+ }
1015
+
1016
+ .contents-glyph {
1017
+ display: inline-block;
1018
+ margin-inline-end: 0.45em;
1019
+ vertical-align: -0.06em;
1020
+ background: currentColor;
1021
+ -webkit-mask: var(--contents-glyph) center / contain no-repeat;
1022
+ mask: var(--contents-glyph) center / contain no-repeat;
1023
+ }
1024
+
1025
+ .contents-glyph--chapter {
1026
+ --contents-glyph: var(--explico-chapter-glyph);
1027
+ width: 0.62em;
1028
+ height: 0.78em;
1029
+ }
1030
+
1031
+ .contents-glyph--deck {
1032
+ --contents-glyph: var(--explico-deck-glyph);
1033
+ width: 1em;
1034
+ height: 0.625em;
1035
+ vertical-align: 0.02em;
1036
+ }
1037
+
1038
+ .contents-glyph--part-deck {
1039
+ --contents-glyph: var(--explico-part-deck-glyph);
1040
+ width: 1em;
1041
+ height: 0.75em;
1042
+ }
1043
+
1044
+ .contents-glyph--part {
1045
+ --contents-glyph: var(--explico-part-glyph);
1046
+ width: 0.76em;
1047
+ height: 0.87em;
1048
+ margin-inline-end: 0.35em;
1049
+ }
1050
+
1051
+ .deck-lane {
1052
+ --deck-lane-line: 1.75rem;
1053
+ --deck-lane-join: color-mix(in srgb, var(--sl-color-text-accent) 30%, transparent);
1054
+ position: relative;
1055
+ grid-row: 1;
1056
+ align-self: stretch;
1057
+ min-height: var(--deck-lane-line);
1058
+ border: 1px solid var(--sl-color-text-accent);
1059
+ border-radius: 0.4rem;
1060
+ color: var(--sl-color-text-accent);
1061
+ background: var(--sl-color-accent-low);
1062
+ text-decoration: none;
1063
+ }
1064
+
1065
+ /* The glyph sits on the row's title line, wherever the cell starts. */
1066
+ .deck-lane::before {
1067
+ content: '';
1068
+ position: absolute;
1069
+ inset-inline: 0;
1070
+ inset-block-start: calc(var(--deck-lane-lead, 0px) - 1px);
1071
+ height: var(--deck-lane-line);
1072
+ }
1073
+
1074
+ .deck-lane--tile {
1075
+ align-self: start;
1076
+ height: var(--deck-lane-line);
1077
+ }
1078
+
1079
+ .deck-lane--start,
1080
+ .deck-lane--middle {
1081
+ grid-row: 1 / span var(--deck-lane-rows, 2);
1082
+ }
1083
+
1084
+ .deck-lane--start {
1085
+ margin-block-end: calc(-1 * var(--deck-lane-down, 0px));
1086
+ border-block-end: 0;
1087
+ border-end-start-radius: 0;
1088
+ border-end-end-radius: 0;
1089
+ }
1090
+
1091
+ .deck-lane--middle,
1092
+ .deck-lane--end {
1093
+ --deck-lane-lead: var(--deck-lane-up, 0px);
1094
+ margin-block-start: calc(-1 * var(--deck-lane-up, 0px));
1095
+ border-block-start-color: var(--deck-lane-join);
1096
+ border-start-start-radius: 0;
1097
+ border-start-end-radius: 0;
1098
+ }
1099
+
1100
+ .deck-lane--middle {
1101
+ margin-block-end: calc(-1 * var(--deck-lane-down, 0px));
1102
+ border-block-end: 0;
1103
+ border-end-start-radius: 0;
1104
+ border-end-end-radius: 0;
1105
+ }
1106
+
1107
+ .deck-lane--deck::before,
1108
+ .deck-lane--part-deck::before,
1109
+ .deck-lane:is(:hover, :focus-visible)::before {
1110
+ background: currentColor;
1111
+ -webkit-mask: var(--explico-deck-glyph) center / 1rem 0.625rem no-repeat;
1112
+ mask: var(--explico-deck-glyph) center / 1rem 0.625rem no-repeat;
1113
+ }
1114
+
1115
+ .deck-lane--part-deck::before,
1116
+ .deck-lane--part-deck:is(:hover, :focus-visible)::before {
1117
+ -webkit-mask: var(--explico-part-deck-glyph) center / 1.05rem 0.79rem no-repeat;
1118
+ mask: var(--explico-part-deck-glyph) center / 1.05rem 0.79rem no-repeat;
1119
+ }
1120
+
1121
+ /* Under the pointer or focus a cell fills, and one with no glyph of its own
1122
+ shows the deck's play mark. */
1123
+ .deck-lane:is(:hover, :focus-visible) {
1124
+ color: var(--sl-color-text-invert);
1125
+ background: var(--sl-color-text-accent);
1126
+ }
1127
+
1128
+ .deck-lane:focus-visible {
1129
+ outline: 2px solid var(--sl-color-text-accent);
1130
+ outline-offset: 2px;
1131
+ }
1132
+
1133
+ @media (forced-colors: active) {
1134
+ .contents-glyph,
1135
+ :is(.deck-lane--deck, .deck-lane--part-deck, .deck-lane:is(:hover, :focus-visible))::before {
1136
+ forced-color-adjust: none;
1137
+ background: currentColor;
1138
+ }
1139
+ }
1140
+
1141
+ /* The reading-memory question (`ReadingMemoryNotice.astro`): a card at the
1142
+ bottom of the window, over nothing the reader needs, until they answer.
1143
+ Its two answers are the same size and weight: neither is the easy one.
1144
+ Above the explanation cards' layer (`--sl-z-index-navbar`), below the skip
1145
+ link; a phone's menu is a popover in the top layer, above it. */
1146
+ .explico-reading-notice {
1147
+ position: fixed;
1148
+ z-index: calc(var(--sl-z-index-navbar) + 2);
1149
+ inset-block-end: calc(1rem + env(safe-area-inset-bottom, 0px));
1150
+ inset-inline-start: 1rem;
1151
+ width: min(25rem, calc(100vw - 2rem));
1152
+ display: grid;
1153
+ gap: 0.65rem;
1154
+ border: 1px solid var(--sl-color-gray-5);
1155
+ border-radius: 0.6rem;
1156
+ padding: 0.9rem 1rem;
1157
+ color: var(--sl-color-text);
1158
+ background: var(--sl-color-bg-nav);
1159
+ box-shadow: var(--sl-shadow-lg);
1160
+ font-size: var(--sl-text-sm);
1161
+ line-height: 1.45;
1162
+ }
1163
+
1164
+ .explico-reading-notice[hidden] {
1165
+ display: none;
1166
+ }
1167
+
1168
+ .explico-reading-notice p {
1169
+ margin: 0;
1170
+ }
1171
+
1172
+ .explico-reading-notice strong {
1173
+ display: block;
1174
+ margin-block-end: 0.2rem;
1175
+ font-size: var(--sl-text-base);
1176
+ }
1177
+
1178
+ .explico-reading-notice__actions {
1179
+ display: grid;
1180
+ grid-template-columns: 1fr 1fr;
1181
+ gap: 0.5rem;
1182
+ }
1183
+
1184
+ .explico-reading-notice__actions button {
1185
+ border: 1px solid var(--sl-color-text-accent);
1186
+ border-radius: 0.4rem;
1187
+ padding: 0.4rem 0.6rem;
1188
+ color: var(--sl-color-text-accent);
1189
+ background: transparent;
1190
+ font: inherit;
1191
+ font-weight: 600;
1192
+ cursor: pointer;
1193
+ }
1194
+
1195
+ .explico-reading-notice__actions button:hover,
1196
+ .explico-reading-notice__actions button:focus-visible {
1197
+ background: var(--sl-color-accent-low);
1198
+ }
1199
+
1200
+ .explico-reading-notice__actions button:focus-visible {
1201
+ outline: 2px solid var(--sl-color-accent-high);
1202
+ outline-offset: 2px;
1203
+ }
1204
+
1205
+ .explico-reading-notice__note {
1206
+ color: var(--sl-color-gray-3);
1207
+ font-size: var(--sl-text-xs);
1208
+ }
1209
+
1210
+ @media not all and (min-width: 50rem) {
1211
+ .explico-reading-notice {
1212
+ inset-inline: 0;
1213
+ inset-block-end: 0;
1214
+ width: auto;
1215
+ border-inline: 0;
1216
+ border-block-end: 0;
1217
+ border-radius: 0.75rem 0.75rem 0 0;
1218
+ padding-block-end: calc(0.9rem + env(safe-area-inset-bottom, 0px));
1219
+ }
1220
+ }
1221
+
1222
+ @media print {
1223
+ .explico-reading-notice {
1224
+ display: none;
1225
+ }
1226
+ }
1227
+
1228
+ /* The panel's foot, under the chapter list: how a lesson's row opens
1229
+ (`sidebar-editions.ts`), then what the marks on screen mean. The panel's
1230
+ scripts fill it; empty, it takes no room. */
1231
+ .explico-sidebar-foot {
1232
+ display: grid;
1233
+ gap: 0.6rem;
1234
+ margin: 1rem 0 0.5rem;
1235
+ border-top: 1px solid var(--sl-color-hairline-light);
1236
+ padding: 0.6rem var(--sl-sidebar-item-padding-inline, 0.5rem) 0;
1237
+ color: var(--sl-color-gray-3);
1238
+ font-size: var(--sl-text-xs);
1239
+ line-height: 1.4;
1240
+ }
1241
+
1242
+ .explico-sidebar-foot:empty {
1243
+ display: none;
1244
+ }
1245
+
1246
+ /* "Lessons open as" Chapter | Slides, a segmented pair of radios, and "List
1247
+ the other edition too", a checkbox. The radios stay native, laid
1248
+ transparent over their segments, so the keyboard, a screen reader and a
1249
+ click all reach the real control. The legend is floated so that it is a
1250
+ flex item beside the segments, not drawn on the fieldset's border. */
1251
+ .explico-sidebar-editions {
1252
+ display: grid;
1253
+ gap: 0.4rem;
1254
+ }
1255
+
1256
+ .explico-sidebar-editions__lead {
1257
+ display: flex;
1258
+ flex-wrap: wrap;
1259
+ align-items: center;
1260
+ gap: 0.3rem 0.5rem;
1261
+ min-inline-size: 0;
1262
+ margin: 0;
1263
+ border: 0;
1264
+ padding: 0;
1265
+ }
1266
+
1267
+ .explico-sidebar-editions__lead > legend {
1268
+ float: left;
1269
+ padding: 0;
1270
+ }
1271
+
1272
+ .explico-sidebar-editions__segments {
1273
+ display: inline-flex;
1274
+ border: 1px solid var(--sl-color-gray-5);
1275
+ border-radius: 0.3rem;
1276
+ overflow: hidden;
1277
+ }
1278
+
1279
+ .explico-sidebar-editions__segment {
1280
+ position: relative;
1281
+ display: inline-flex;
1282
+ }
1283
+
1284
+ .explico-sidebar-editions__segment + .explico-sidebar-editions__segment {
1285
+ border-inline-start: 1px solid var(--sl-color-gray-5);
1286
+ }
1287
+
1288
+ .explico-sidebar-editions__segment > input {
1289
+ position: absolute;
1290
+ inset: 0;
1291
+ width: 100%;
1292
+ height: 100%;
1293
+ margin: 0;
1294
+ opacity: 0;
1295
+ cursor: pointer;
1296
+ }
1297
+
1298
+ .explico-sidebar-editions__segment > span {
1299
+ padding: 0.1rem 0.55rem;
1300
+ color: var(--sl-color-gray-2);
1301
+ }
1302
+
1303
+ .explico-sidebar-editions__segment > input:not(:checked):hover + span {
1304
+ color: var(--sl-color-text-accent);
1305
+ background: var(--sl-color-accent-low);
1306
+ }
1307
+
1308
+ .explico-sidebar-editions__segment > input:checked + span {
1309
+ color: var(--sl-color-text-invert);
1310
+ background: var(--sl-color-text-accent);
1311
+ font-weight: 600;
1312
+ }
1313
+
1314
+ .explico-sidebar-editions__segment > input:focus-visible + span {
1315
+ outline: 2px solid var(--sl-color-accent-high);
1316
+ outline-offset: -2px;
1317
+ }
1318
+
1319
+ .explico-sidebar-editions__other {
1320
+ display: inline-flex;
1321
+ align-items: center;
1322
+ gap: 0.4rem;
1323
+ justify-self: start;
1324
+ cursor: pointer;
1325
+ }
1326
+
1327
+ .explico-sidebar-editions__other > input {
1328
+ margin: 0;
1329
+ accent-color: var(--sl-color-text-accent);
1330
+ cursor: pointer;
1331
+ }
1332
+
1333
+ /* What the marks on screen mean, and the two ways to reset them, last in the
1334
+ panel's foot. The line stays while the reader's record is kept, with no
1335
+ mark on screen too, so a reset can always be undone; what an action did is
1336
+ said in the line's own status, under its buttons. */
1337
+ .explico-page-marks-legend {
1338
+ min-width: 0;
1339
+ }
1340
+
1341
+ .explico-page-marks-legend__row {
1342
+ display: flex;
1343
+ flex-wrap: wrap;
1344
+ align-items: center;
1345
+ gap: 0.25rem 0.85rem;
1346
+ }
1347
+
1348
+ .explico-page-marks-legend__item:not([hidden]) {
1349
+ display: inline-flex;
1350
+ align-items: center;
1351
+ gap: 0.35rem;
1352
+ }
1353
+
1354
+ .explico-page-marks-legend__actions {
1355
+ display: inline-flex;
1356
+ flex-wrap: wrap;
1357
+ gap: 0.25rem;
1358
+ margin-inline-start: auto;
1359
+ }
1360
+
1361
+ .explico-page-marks-legend__action {
1362
+ border: 0;
1363
+ border-radius: 0.25rem;
1364
+ padding: 0.1rem 0.3rem;
1365
+ color: var(--sl-color-text-accent);
1366
+ background: none;
1367
+ font: inherit;
1368
+ cursor: pointer;
1369
+ }
1370
+
1371
+ .explico-page-marks-legend__action:not([aria-disabled='true']):hover,
1372
+ .explico-page-marks-legend__action:focus-visible {
1373
+ background: var(--sl-color-accent-low);
1374
+ }
1375
+
1376
+ /* Out of use (nothing to change), in its place: the same muted grey as the
1377
+ legend's text, so it reads as an option that does nothing now. */
1378
+ .explico-page-marks-legend__action[aria-disabled='true'] {
1379
+ color: var(--sl-color-gray-3);
1380
+ cursor: default;
1381
+ }
1382
+
1383
+ .explico-page-marks-legend__status {
1384
+ margin: 0;
1385
+ }
1386
+
1387
+ .explico-page-marks-legend__status:not(:empty) {
1388
+ margin-block-start: 0.35rem;
1389
+ }
1390
+
1391
+ @media print {
1392
+ .explico-sidebar-foot {
1393
+ display: none;
1394
+ }
1395
+
1396
+ .layout-navigation-content li[data-page-mark]::after {
1397
+ content: none;
1398
+ }
1399
+ }
1400
+
725
1401
  @media (min-width: 50rem) {
726
1402
  :root {
727
1403
  --layout-edge-rail-width: 2.5rem;
@@ -857,18 +1533,30 @@ details.layout-part-has-open > summary > .group-label {
857
1533
  background: var(--sl-color-bg-sidebar);
858
1534
  }
859
1535
 
1536
+ /* A chapter is a sheet with lines of text; a part (below) two plain
1537
+ sheets, and a deck a slide frame with a play mark (`deck.css`). */
860
1538
  .layout-compact-sidebar
861
1539
  details[data-compact]
862
1540
  > ul:not(.top-level)
863
1541
  > li
864
1542
  > a::before {
865
1543
  content: '';
866
- width: 0.65rem;
867
- height: 0.78rem;
868
- border: 1.5px solid currentColor;
869
- border-radius: 0.13rem;
870
- box-shadow: 0.18rem 0.18rem 0 -0.1rem var(--sl-color-bg-sidebar),
871
- 0.18rem 0.18rem 0 0 currentColor;
1544
+ width: 0.74rem;
1545
+ height: 0.94rem;
1546
+ background: currentColor;
1547
+ -webkit-mask: var(--explico-chapter-glyph) center / contain no-repeat;
1548
+ mask: var(--explico-chapter-glyph) center / contain no-repeat;
1549
+ }
1550
+
1551
+ @media (forced-colors: active) {
1552
+ .layout-compact-sidebar
1553
+ details[data-compact]
1554
+ > ul:not(.top-level)
1555
+ > li
1556
+ > a:not(.explico-part-overview)::before {
1557
+ forced-color-adjust: none;
1558
+ background: currentColor;
1559
+ }
872
1560
  }
873
1561
 
874
1562
  .layout-compact-sidebar
@@ -881,6 +1569,21 @@ details.layout-part-has-open > summary > .group-label {
881
1569
  > ul:not(.top-level)
882
1570
  > li
883
1571
  > a:focus-visible {
1572
+ --explico-overview-gap: var(--sl-color-accent-low);
1573
+ border-color: var(--sl-color-accent);
1574
+ color: var(--sl-color-text-accent);
1575
+ background: var(--sl-color-accent-low);
1576
+ }
1577
+
1578
+ /* `»` lights the compact part's Overview tile as a pointer on the tile
1579
+ would (see the expanded row's rule beside `.layout-part-open`). */
1580
+ .layout-compact-sidebar
1581
+ details[data-compact].layout-part-has-open
1582
+ > .layout-part-open:is(:hover, :focus-visible)
1583
+ ~ ul:not(.top-level)
1584
+ > li
1585
+ > a.explico-part-overview:not([aria-current='page']) {
1586
+ --explico-overview-gap: var(--sl-color-accent-low);
884
1587
  border-color: var(--sl-color-accent);
885
1588
  color: var(--sl-color-text-accent);
886
1589
  background: var(--sl-color-accent-low);
@@ -890,7 +1593,7 @@ details.layout-part-has-open > summary > .group-label {
890
1593
  details[data-compact]
891
1594
  > ul:not(.top-level)
892
1595
  > li
893
- > a[aria-current='page'] {
1596
+ > a:is([aria-current='page'], [data-deck-section][aria-current='location']) {
894
1597
  color: var(--sl-color-text-invert);
895
1598
  background: var(--sl-color-text-accent);
896
1599
  }
@@ -900,7 +1603,8 @@ details.layout-part-has-open > summary > .group-label {
900
1603
  > ul:not(.top-level)
901
1604
  > li
902
1605
  > a
903
- > span {
1606
+ > span,
1607
+ .layout-navigation-content li > a.layout-edition-other[data-tooltip-open] > span {
904
1608
  position: absolute;
905
1609
  z-index: 2;
906
1610
  inset-block-start: 50%;
@@ -929,11 +1633,28 @@ details.layout-part-has-open > summary > .group-label {
929
1633
  > ul:not(.top-level)
930
1634
  > li
931
1635
  > a:is(:hover, :focus-visible)
932
- > span {
1636
+ > span,
1637
+ .layout-navigation-content li > a.layout-edition-other[data-tooltip-open] > span {
933
1638
  opacity: 1;
934
1639
  transform: translateY(-50%) translateX(0);
935
1640
  }
936
1641
 
1642
+ /* The row's icon names itself out of sight (above) until its tooltip
1643
+ shows, and as a compact tile it is a tooltip like any other. */
1644
+ .layout-compact-sidebar
1645
+ details[data-compact]
1646
+ > ul:not(.top-level)
1647
+ > li
1648
+ > a.layout-edition-other
1649
+ > span,
1650
+ .layout-navigation-content li > a.layout-edition-other[data-tooltip-open] > span {
1651
+ height: auto;
1652
+ margin: 0;
1653
+ overflow: visible;
1654
+ clip-path: none;
1655
+ white-space: normal;
1656
+ }
1657
+
937
1658
  /* The panel that holds this tooltip is a scroll container
938
1659
  (`.sidebar-pane` is `overflow-y: auto`, which forces `overflow-x` to
939
1660
  match), so an absolutely positioned child cannot leave it: a lesson
@@ -948,7 +1669,8 @@ details.layout-part-has-open > summary > .group-label {
948
1669
  > ul:not(.top-level)
949
1670
  > li
950
1671
  > a[data-tooltip-open]
951
- > span {
1672
+ > span,
1673
+ .layout-navigation-content li > a.layout-edition-other[data-tooltip-open] > span {
952
1674
  position: fixed;
953
1675
  z-index: calc(var(--sl-z-index-menu) + 2);
954
1676
  inset-inline: auto;
@@ -986,7 +1708,16 @@ details.layout-part-has-open > summary > .group-label {
986
1708
  > ul:not(.top-level)
987
1709
  > li
988
1710
  > a.explico-part-overview::before {
1711
+ width: 0.65rem;
1712
+ height: 0.78rem;
1713
+ border: 1.5px solid currentColor;
1714
+ border-radius: 0.13rem;
989
1715
  background: currentColor;
1716
+ -webkit-mask: none;
1717
+ mask: none;
1718
+ box-shadow:
1719
+ 0.18rem 0.18rem 0 -0.1rem var(--explico-overview-gap),
1720
+ 0.18rem 0.18rem 0 0 currentColor;
990
1721
  }
991
1722
 
992
1723
  /* On the part's own page the tile is already accent-filled, so filled
@@ -998,6 +1729,7 @@ details.layout-part-has-open > summary > .group-label {
998
1729
  > ul:not(.top-level)
999
1730
  > li
1000
1731
  > a.explico-part-overview[aria-current='page'] {
1732
+ --explico-overview-gap: var(--sl-color-text-accent);
1001
1733
  color: var(--sl-color-text-invert);
1002
1734
  border-color: var(--sl-color-text-accent);
1003
1735
  }
@@ -1017,10 +1749,209 @@ details.layout-part-has-open > summary > .group-label {
1017
1749
  > ul:not(.top-level)
1018
1750
  > li[data-covered]
1019
1751
  > a:not([aria-current='page']) {
1752
+ --explico-overview-gap: var(--sl-color-accent-low);
1020
1753
  border-color: var(--sl-color-accent-low);
1021
1754
  background: var(--sl-color-accent-low);
1022
1755
  }
1023
1756
 
1757
+ /* A lesson's row in a compact part (`sidebar-editions.ts`): its two
1758
+ links are two tiles in one item, the lead first, joined as a chapter's
1759
+ tile and its deck's are without the script (`deck.css`). The second
1760
+ tile lies over the first's last pixel, its own start border clear, so
1761
+ the line between them is the first tile's border, lit with whichever
1762
+ tile is lit (not on a covered pair, which keeps its tint), and the open
1763
+ page's tile is outlined in accent. The item says it is a pair: no
1764
+ `:has()`. */
1765
+ .layout-compact-sidebar
1766
+ details[data-compact]
1767
+ > ul:not(.top-level)
1768
+ > li[data-editions='pair'] {
1769
+ display: flex;
1770
+ }
1771
+
1772
+ .layout-compact-sidebar
1773
+ details[data-compact]
1774
+ > ul:not(.top-level)
1775
+ > li[data-editions='pair']
1776
+ > a:first-child {
1777
+ border-start-end-radius: 0;
1778
+ border-end-end-radius: 0;
1779
+ }
1780
+
1781
+ .layout-compact-sidebar
1782
+ details[data-compact]
1783
+ > ul:not(.top-level)
1784
+ > li[data-editions='pair']
1785
+ > a.layout-edition-other {
1786
+ inset: auto;
1787
+ margin-block: 0;
1788
+ margin-inline-start: -1px;
1789
+ border-inline-start-color: transparent;
1790
+ border-start-start-radius: 0;
1791
+ border-end-start-radius: 0;
1792
+ background-clip: padding-box;
1793
+ }
1794
+
1795
+ .layout-compact-sidebar
1796
+ details[data-compact]
1797
+ > ul:not(.top-level)
1798
+ > li[data-editions='pair']:not([data-covered])
1799
+ > a.layout-edition-other:is(:hover, :focus-visible) {
1800
+ border-inline-start-color: var(--sl-color-accent);
1801
+ }
1802
+
1803
+ .layout-compact-sidebar
1804
+ details[data-compact]
1805
+ > ul:not(.top-level)
1806
+ > li[data-editions='pair']
1807
+ > a:is([aria-current='page'], [data-deck-section][aria-current='location']) {
1808
+ border-color: var(--sl-color-text-accent);
1809
+ }
1810
+
1811
+ /* A tile keeps its own colour beside an open page's tile; the row's icon
1812
+ turned to the accent fill's ink only where the fill runs under it. */
1813
+ .layout-compact-sidebar
1814
+ details[data-compact]
1815
+ > ul:not(.top-level)
1816
+ > li[data-editions='pair']
1817
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
1818
+ + a.layout-edition-other:not(:hover, :focus-visible) {
1819
+ color: var(--sl-color-gray-3);
1820
+ }
1821
+
1822
+ /* A compact tile has no row end: the reader's mark (`page-marks.ts`) sits
1823
+ on its corner, as a badge on an icon does, ringed in the panel's colour
1824
+ so it reads against the tile's border. The tile keeps its size, and the
1825
+ tooltip names the mark under the title. */
1826
+ .layout-compact-sidebar
1827
+ details[data-compact]
1828
+ > ul:not(.top-level)
1829
+ > li[data-page-mark]::after {
1830
+ z-index: 1;
1831
+ inset-block-start: -0.15rem;
1832
+ inset-inline-end: -0.15rem;
1833
+ width: 0.5rem;
1834
+ height: 0.5rem;
1835
+ background-color: var(--sl-color-bg-sidebar);
1836
+ box-shadow: 0 0 0 2px var(--sl-color-bg-sidebar);
1837
+ transform: none;
1838
+ }
1839
+
1840
+ .layout-compact-sidebar
1841
+ details[data-compact]
1842
+ > ul:not(.top-level)
1843
+ > li[data-page-mark='changed']::after {
1844
+ background-color: var(--sl-color-text-accent);
1845
+ }
1846
+
1847
+ /* In a pair, the row's own mark is on its own tile's corner, where the
1848
+ two tiles meet; the second tile carries its own, as the row's icon
1849
+ does (`.layout-edition-mark`), at a tile's size. */
1850
+ .layout-compact-sidebar
1851
+ details[data-compact]
1852
+ > ul:not(.top-level)
1853
+ > li[data-editions='pair'][data-page-mark]::after {
1854
+ inset-inline-end: calc(1.75rem - 1px - 0.15rem);
1855
+ }
1856
+
1857
+ .layout-compact-sidebar
1858
+ details[data-compact]
1859
+ > ul:not(.top-level)
1860
+ > li
1861
+ > a.layout-edition-other
1862
+ > .layout-edition-mark {
1863
+ width: 0.5rem;
1864
+ height: 0.5rem;
1865
+ }
1866
+
1867
+ /* A tile's mark is on the panel, never on its neighbour's fill. */
1868
+ .layout-compact-sidebar
1869
+ details[data-compact]
1870
+ > ul:not(.top-level)
1871
+ > li[data-editions='pair']
1872
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
1873
+ + a.layout-edition-other[data-page-mark='unopened']
1874
+ > .layout-edition-mark {
1875
+ border-color: var(--sl-color-gray-4);
1876
+ background-color: var(--sl-color-bg-sidebar);
1877
+ box-shadow: 0 0 0 2px var(--sl-color-bg-sidebar);
1878
+ }
1879
+
1880
+ .layout-compact-sidebar
1881
+ details[data-compact]
1882
+ > ul:not(.top-level)
1883
+ > li[data-editions='pair']
1884
+ > :is(a[aria-current='page'], a[data-deck-section][aria-current='location'])
1885
+ + a.layout-edition-other[data-page-mark='changed']
1886
+ > .layout-edition-mark {
1887
+ background-color: var(--sl-color-text-accent);
1888
+ box-shadow: 0 0 0 2px var(--sl-color-bg-sidebar);
1889
+ }
1890
+
1891
+ .layout-compact-sidebar
1892
+ details[data-compact]
1893
+ > ul:not(.top-level)
1894
+ > li[data-page-mark]
1895
+ > a:not(.layout-edition-other)
1896
+ > span::after,
1897
+ .layout-navigation-content li > a.layout-edition-other[data-page-mark] > span::after {
1898
+ display: block;
1899
+ color: var(--sl-color-gray-3);
1900
+ font-weight: 400;
1901
+ }
1902
+
1903
+ /* A link's second line where its name is a tooltip: a part's deck's
1904
+ chapters and slides, a section's slides (`sidebar-editions.ts`). */
1905
+ .layout-compact-sidebar
1906
+ details[data-compact]
1907
+ > ul:not(.top-level)
1908
+ > li
1909
+ > a
1910
+ > span
1911
+ > .layout-edition-detail,
1912
+ .layout-navigation-content li > a.layout-edition-other > span > .layout-edition-detail {
1913
+ display: block;
1914
+ color: var(--sl-color-gray-3);
1915
+ font-size: inherit;
1916
+ font-weight: 400;
1917
+ }
1918
+
1919
+ .layout-compact-sidebar
1920
+ details[data-compact]
1921
+ > ul:not(.top-level)
1922
+ > li[data-page-mark='unopened']
1923
+ > a:not(.layout-edition-other)
1924
+ > span::after,
1925
+ .layout-navigation-content li > a.layout-edition-other[data-page-mark='unopened'] > span::after {
1926
+ content: 'Not opened yet' / '';
1927
+ }
1928
+
1929
+ .layout-compact-sidebar
1930
+ details[data-compact]
1931
+ > ul:not(.top-level)
1932
+ > li[data-page-mark='changed']
1933
+ > a:not(.layout-edition-other)
1934
+ > span::after,
1935
+ .layout-navigation-content li > a.layout-edition-other[data-page-mark='changed'] > span::after {
1936
+ content: 'Changed since you last opened it' / '';
1937
+ }
1938
+
1939
+ /* The panel folded away to its edge: the restore control says that a
1940
+ page changed since the reader opened it. Pages not yet opened do not
1941
+ claim it; on a first visit that would be every page. */
1942
+ .layout-navigation-panel[data-page-marks~='changed']
1943
+ .layout-navigation-toggle[aria-expanded='false']::after {
1944
+ content: '';
1945
+ position: absolute;
1946
+ inset-block-start: -0.2rem;
1947
+ inset-inline-end: -0.2rem;
1948
+ width: 0.45rem;
1949
+ height: 0.45rem;
1950
+ border-radius: 50%;
1951
+ background: var(--sl-color-text-accent);
1952
+ box-shadow: 0 0 0 2px var(--sl-color-bg-nav);
1953
+ }
1954
+
1024
1955
  .layout-navigation-toggle {
1025
1956
  position: fixed;
1026
1957
  z-index: calc(var(--sl-z-index-menu) + 1);
@@ -1202,7 +2133,7 @@ details.layout-part-has-open > summary > .group-label {
1202
2133
  .right-sidebar {
1203
2134
  width: max-content;
1204
2135
  max-width: 80ch;
1205
- background-color: var(--sl-color-bg);
2136
+ background-color: var(--ex-zone-toc);
1206
2137
  /* Anchor to the viewport edge instead of Starlight's default static
1207
2138
  position (wherever `.right-sidebar-container`'s reserved flex column
1208
2139
  happens to land, which drifts left as `.main-pane` grows on a wide