explico 0.13.1 → 0.15.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 (256) hide show
  1. package/CHANGELOG.md +990 -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 +100 -0
  6. package/dist/compiler/cli-main.js +433 -0
  7. package/dist/compiler/cli-reference.d.ts +50 -0
  8. package/dist/compiler/cli-reference.js +213 -0
  9. package/dist/compiler/cli-verbs.d.ts +45 -0
  10. package/dist/compiler/cli-verbs.js +224 -0
  11. package/dist/compiler/cli-verify.d.ts +51 -0
  12. package/dist/compiler/cli-verify.js +151 -0
  13. package/dist/compiler/cli.d.ts +408 -24
  14. package/dist/compiler/cli.js +1328 -8
  15. package/dist/compiler/collections.d.ts +88 -1
  16. package/dist/compiler/collections.js +170 -25
  17. package/dist/compiler/content-release.d.ts +49 -0
  18. package/dist/compiler/content-release.js +63 -0
  19. package/dist/compiler/content-schemas.d.ts +2 -2
  20. package/dist/compiler/course-config.d.ts +1 -1
  21. package/dist/compiler/course-config.js +105 -1
  22. package/dist/compiler/decks.d.ts +161 -0
  23. package/dist/compiler/decks.js +235 -0
  24. package/dist/compiler/exports/combined-html.d.ts +5 -1
  25. package/dist/compiler/exports/deck-fit.d.ts +55 -0
  26. package/dist/compiler/exports/deck-fit.js +90 -0
  27. package/dist/compiler/exports/export-chapters.d.ts +37 -6
  28. package/dist/compiler/exports/export-chapters.js +64 -5
  29. package/dist/compiler/exports/export-pages.d.ts +30 -3
  30. package/dist/compiler/exports/export-pages.js +24 -1
  31. package/dist/compiler/exports/latex/beamerthemeexplico.sty +124 -0
  32. package/dist/compiler/exports/latex/cache.d.ts +78 -0
  33. package/dist/compiler/exports/latex/cache.js +129 -0
  34. package/dist/compiler/exports/latex/capture.d.ts +10 -1
  35. package/dist/compiler/exports/latex/capture.js +3 -1
  36. package/dist/compiler/exports/latex/compile.d.ts +13 -2
  37. package/dist/compiler/exports/latex/compile.js +12 -1
  38. package/dist/compiler/exports/latex/deck.d.ts +92 -0
  39. package/dist/compiler/exports/latex/deck.js +349 -0
  40. package/dist/compiler/exports/latex/document.d.ts +51 -6
  41. package/dist/compiler/exports/latex/document.js +71 -12
  42. package/dist/compiler/exports/latex/explico-common.sty +198 -0
  43. package/dist/compiler/exports/latex/explico.cls +13 -183
  44. package/dist/compiler/exports/latex/serialize.d.ts +60 -4
  45. package/dist/compiler/exports/latex/serialize.js +4 -2
  46. package/dist/compiler/exports/latex-export.d.ts +24 -2
  47. package/dist/compiler/exports/latex-export.js +107 -26
  48. package/dist/compiler/exports/markdown/serialize.d.ts +24 -4
  49. package/dist/compiler/exports/markdown/serialize.js +85 -8
  50. package/dist/compiler/exports/markdown-export.d.ts +6 -1
  51. package/dist/compiler/exports/markdown-export.js +50 -11
  52. package/dist/compiler/exports/standalone-html.d.ts +10 -5
  53. package/dist/compiler/exports/standalone-html.js +3 -3
  54. package/dist/compiler/exports/static-tree.d.ts +38 -1
  55. package/dist/compiler/exports/static-tree.js +120 -4
  56. package/dist/compiler/knowledge-version.d.ts +26 -2
  57. package/dist/compiler/knowledge-version.js +27 -17
  58. package/dist/compiler/lesson-derivation.d.ts +143 -6
  59. package/dist/compiler/lesson-derivation.js +145 -13
  60. package/dist/compiler/manifest.d.ts +133 -4
  61. package/dist/compiler/manifest.js +364 -58
  62. package/dist/compiler/page-versions.d.ts +184 -0
  63. package/dist/compiler/page-versions.js +217 -0
  64. package/dist/compiler/render-diagnostics.d.ts +5 -1
  65. package/dist/compiler/resolution-report.d.ts +24 -6
  66. package/dist/compiler/resolution-report.js +22 -4
  67. package/dist/compiler/validate-content.d.ts +7 -0
  68. package/dist/compiler/validate-content.js +160 -0
  69. package/dist/{course-config-rRtME5UV.d.ts → course-config-BLtIdkei.d.ts} +164 -1
  70. package/dist/curriculum/competency-graph.d.ts +54 -0
  71. package/dist/curriculum/competency-graph.js +41 -0
  72. package/dist/reference/base-library.d.mts +8 -0
  73. package/dist/reference/base-library.mjs +19 -0
  74. package/dist/reference/consistency.d.ts +8 -4
  75. package/dist/reference/consistency.js +82 -26
  76. package/dist/reference/deck-remark.d.mts +123 -0
  77. package/dist/reference/deck-remark.mjs +600 -0
  78. package/dist/reference/deck-source.d.ts +107 -0
  79. package/dist/reference/deck-source.js +140 -0
  80. package/dist/reference/decks-validate.d.ts +133 -0
  81. package/dist/reference/decks-validate.js +359 -0
  82. package/dist/reference/derived-entries.d.ts +5 -1
  83. package/dist/reference/diagram-fit.d.ts +6 -2
  84. package/dist/reference/diagram-fit.js +5 -1
  85. package/dist/reference/figure-symbols.d.ts +23 -6
  86. package/dist/reference/figure-symbols.js +51 -15
  87. package/dist/reference/float-name.d.ts +43 -0
  88. package/dist/reference/float-name.js +58 -0
  89. package/dist/reference/folds-validate.d.ts +1 -1
  90. package/dist/reference/gate-abbreviations.d.ts +1 -1
  91. package/dist/reference/gate-indices.js +5 -4
  92. package/dist/reference/gate-math.d.ts +29 -2
  93. package/dist/reference/gate-math.js +99 -18
  94. package/dist/reference/gate-part-pages.d.ts +1 -1
  95. package/dist/reference/lab-katex-validate.d.ts +10 -6
  96. package/dist/reference/lab-katex-validate.js +17 -9
  97. package/dist/reference/lab-math-scope.js +29 -4
  98. package/dist/reference/math-glyphs.d.mts +25 -0
  99. package/dist/reference/math-glyphs.mjs +189 -25
  100. package/dist/reference/page-notation.d.ts +22 -3
  101. package/dist/reference/page-notation.js +32 -10
  102. package/dist/reference/references.d.ts +14 -1
  103. package/dist/reference/references.js +13 -0
  104. package/dist/reference/registry-scope.d.mts +33 -0
  105. package/dist/reference/registry-scope.mjs +34 -0
  106. package/dist/reference/registry.js +29 -10
  107. package/dist/reference/rehype-deck.d.mts +6 -0
  108. package/dist/reference/rehype-deck.mjs +286 -0
  109. package/dist/reference/rehype-heading-anchors.d.mts +20 -0
  110. package/dist/reference/rehype-heading-anchors.mjs +48 -6
  111. package/dist/reference/remark-notation.mjs +249 -40
  112. package/dist/reference/source-lines.d.mts +12 -0
  113. package/dist/reference/source-lines.mjs +65 -0
  114. package/dist/reference/types.d.ts +28 -0
  115. package/dist/rules/catalog.d.ts +21 -4
  116. package/dist/rules/catalog.js +237 -2
  117. package/dist/rules/course-rules.d.ts +5 -1
  118. package/dist/rules/course-rules.js +17 -3
  119. package/dist/rules/course-rules.schema.json +12 -0
  120. package/dist/rules/in-effect.d.ts +13 -3
  121. package/dist/rules/in-effect.js +34 -10
  122. package/dist/rules/rules.schema.json +280 -1
  123. package/dist/rules/settings.d.ts +1 -1
  124. package/dist/session/PreferenceStore.d.ts +6 -0
  125. package/dist/session/PreferenceStore.js +18 -1
  126. package/dist/session/deck-memory.d.ts +116 -0
  127. package/dist/session/deck-memory.js +143 -0
  128. package/dist/session/reading-memory.d.ts +96 -0
  129. package/dist/session/reading-memory.js +133 -0
  130. package/docs/VERSIONING.md +21 -18
  131. package/docs/authoring/README.md +31 -9
  132. package/docs/authoring/agents.md +72 -18
  133. package/docs/authoring/cli-reference.json +2172 -0
  134. package/docs/authoring/cli.md +887 -0
  135. package/docs/authoring/components.md +15 -0
  136. package/docs/authoring/deck.md +612 -0
  137. package/docs/authoring/migrating.md +1195 -16
  138. package/docs/authoring/notation.md +49 -6
  139. package/docs/authoring/structure.md +80 -1
  140. package/docs/authoring/versioning.md +56 -3
  141. package/docs/authoring/visualizations.md +7 -2
  142. package/docs/course-agent/AGENTS.md +40 -0
  143. package/docs/course-agent/agents/rules-reviewer.md +33 -0
  144. package/docs/course-agent/skills/draft-lesson/SKILL.md +38 -0
  145. package/docs/course-agent/skills/migrate-course/SKILL.md +32 -0
  146. package/docs/course-agent/skills/release-content/SKILL.md +26 -0
  147. package/docs/diagram-scaling.md +148 -0
  148. package/docs/privacy.md +59 -0
  149. package/package.json +8 -2
  150. package/src/compiler/astro.ts +60 -21
  151. package/src/compiler/cli-main.ts +557 -0
  152. package/src/compiler/cli-reference.ts +285 -0
  153. package/src/compiler/cli-verbs.ts +270 -0
  154. package/src/compiler/cli-verify.ts +241 -0
  155. package/src/compiler/cli.ts +2119 -170
  156. package/src/compiler/collections.ts +284 -25
  157. package/src/compiler/content-release.ts +91 -0
  158. package/src/compiler/course-config.ts +267 -0
  159. package/src/compiler/decks.ts +455 -0
  160. package/src/compiler/exports/deck-fit.ts +127 -0
  161. package/src/compiler/exports/export-chapters.ts +105 -6
  162. package/src/compiler/exports/export-pages.ts +46 -2
  163. package/src/compiler/exports/latex/beamerthemeexplico.sty +124 -0
  164. package/src/compiler/exports/latex/cache.ts +183 -0
  165. package/src/compiler/exports/latex/capture.ts +5 -2
  166. package/src/compiler/exports/latex/compile.ts +18 -0
  167. package/src/compiler/exports/latex/deck.ts +419 -0
  168. package/src/compiler/exports/latex/document.ts +117 -21
  169. package/src/compiler/exports/latex/explico-common.sty +198 -0
  170. package/src/compiler/exports/latex/explico.cls +13 -183
  171. package/src/compiler/exports/latex/serialize.ts +25 -21
  172. package/src/compiler/exports/latex/texlive-packages.txt +6 -2
  173. package/src/compiler/exports/latex-export.ts +187 -45
  174. package/src/compiler/exports/markdown/serialize.ts +118 -9
  175. package/src/compiler/exports/markdown-export.ts +56 -11
  176. package/src/compiler/exports/standalone-html.ts +8 -7
  177. package/src/compiler/exports/static-tree.ts +175 -3
  178. package/src/compiler/knowledge-version.ts +56 -21
  179. package/src/compiler/lesson-derivation.ts +282 -16
  180. package/src/compiler/manifest.ts +568 -63
  181. package/src/compiler/page-versions.ts +401 -0
  182. package/src/compiler/resolution-report.ts +38 -7
  183. package/src/compiler/validate-content.ts +215 -0
  184. package/src/components/CourseContents.astro +124 -6
  185. package/src/components/CurriculumMap.astro +49 -1
  186. package/src/components/FloatIndex.astro +1 -1
  187. package/src/components/PartOverview.astro +51 -5
  188. package/src/components/assessments/AssessmentSet.astro +41 -15
  189. package/src/components/block-heading.ts +15 -6
  190. package/src/components/card-carry.ts +7 -4
  191. package/src/components/card-manager.ts +14 -2
  192. package/src/components/card-memory.ts +13 -9
  193. package/src/components/deck/DeckEnhancer.astro +13 -0
  194. package/src/components/deck/deck-context.ts +104 -0
  195. package/src/components/deck/deck-controller.ts +1287 -0
  196. package/src/components/deck/deck-map.ts +91 -0
  197. package/src/components/deck-lane.ts +163 -0
  198. package/src/components/diagram/Diagram.astro +131 -86
  199. package/src/components/disclosure/persisted-disclosure.ts +9 -1
  200. package/src/components/figure/Figure.astro +7 -2
  201. package/src/components/figure/FloatCaption.astro +5 -3
  202. package/src/components/fold/Fold.astro +2 -2
  203. package/src/components/notation/NotationFormula.astro +81 -11
  204. package/src/components/notation/NotationGlossary.astro +132 -1
  205. package/src/components/notation/NotationLayer.astro +15 -7
  206. package/src/components/starlight/AboutPanel.astro +186 -3
  207. package/src/components/starlight/CollapsibleSections.astro +24 -3
  208. package/src/components/starlight/DiagramEnhancer.astro +5 -1
  209. package/src/components/starlight/HeadingAnchorEnhancer.astro +1 -1
  210. package/src/components/starlight/LayoutHeader.astro +17 -0
  211. package/src/components/starlight/LayoutPageTitle.astro +110 -0
  212. package/src/components/starlight/LayoutSidebar.astro +807 -21
  213. package/src/components/starlight/LayoutSocialIcons.astro +62 -6
  214. package/src/components/starlight/LessonExportActions.astro +27 -9
  215. package/src/components/starlight/LessonFooter.astro +59 -0
  216. package/src/components/starlight/ReadingMemoryNotice.astro +114 -0
  217. package/src/components/starlight/TextSizeControl.astro +24 -13
  218. package/src/components/starlight/page-marks.ts +139 -0
  219. package/src/components/starlight/section-summary.ts +1 -1
  220. package/src/components/starlight/sidebar-editions.ts +245 -0
  221. package/src/components/table/Table.astro +15 -7
  222. package/src/content-config.ts +87 -1
  223. package/src/curriculum/competency-graph.ts +95 -0
  224. package/src/reference/base-library.mjs +19 -0
  225. package/src/reference/consistency.ts +137 -39
  226. package/src/reference/deck-remark.mjs +600 -0
  227. package/src/reference/deck-source.ts +273 -0
  228. package/src/reference/decks-validate.ts +604 -0
  229. package/src/reference/diagram-fit.ts +18 -4
  230. package/src/reference/diagram-layout.ts +3 -1
  231. package/src/reference/figure-symbols.ts +108 -31
  232. package/src/reference/folds-validate.ts +1 -1
  233. package/src/reference/gate-indices.ts +5 -3
  234. package/src/reference/gate-math.ts +169 -25
  235. package/src/reference/lab-katex-validate.ts +30 -15
  236. package/src/reference/lab-math-scope.ts +34 -3
  237. package/src/reference/math-glyphs.mjs +189 -25
  238. package/src/reference/page-notation.ts +69 -15
  239. package/src/reference/references.ts +28 -0
  240. package/src/reference/registry-scope.mjs +34 -0
  241. package/src/reference/registry.ts +41 -11
  242. package/src/reference/rehype-deck.mjs +286 -0
  243. package/src/reference/rehype-heading-anchors.mjs +48 -6
  244. package/src/reference/remark-notation.mjs +249 -40
  245. package/src/reference/source-lines.mjs +65 -0
  246. package/src/reference/types.ts +28 -0
  247. package/src/rules/catalog.ts +274 -4
  248. package/src/rules/course-rules.ts +21 -1
  249. package/src/rules/in-effect.ts +58 -11
  250. package/src/session/PreferenceStore.ts +23 -0
  251. package/src/session/deck-memory.ts +263 -0
  252. package/src/session/reading-memory.ts +243 -0
  253. package/src/styles/deck.css +1150 -0
  254. package/src/styles/global.css +958 -27
  255. package/src/styles/zones.css +277 -0
  256. /package/src/{components → reference}/float-name.ts +0 -0
@@ -0,0 +1,1150 @@
1
+ /* Decks (docs/authoring/deck.md): a lesson's slide edition.
2
+
3
+ The page is a column of frames — the study page a reader scrolls, every
4
+ frame at its last step with its notes under it — and Present mode shows one
5
+ frame at a time on the whole screen (`components/deck/deck-controller.ts`).
6
+
7
+ A frame's canvas is laid out at the course's canvas size, 450 px tall and
8
+ as wide as the page's reading column (800, 720 or 600 px for 16:9, 16:10,
9
+ 4:3), so a figure, a table or a lab lays out on it at the size it was made
10
+ for. Its type scale is fixed to it, and it is scaled to its stage with a
11
+ transform, as a diagram is (docs/diagram-scaling.md): it lays out the same
12
+ at every width, so what fits when the build measures it fits on a phone and
13
+ on a projector. Until the controller has measured the stage, the frame
14
+ shows its content in the page's own flow. */
15
+
16
+ /* A slide's edge on the deck's page (`appearance.slides` in the course
17
+ settings, `course-config.ts`; `LayoutHeader.astro` writes the choice on
18
+ `[data-explico-slides]`):
19
+
20
+ lifted an edge and a drop shadow, and in the dark theme a sheet a step
21
+ lighter than the page. The default; it needs no attribute.
22
+ edge the edge and the shadow, on the page's own colour.
23
+ sorter the deck on a tinted well, each slide a sheet on it.
24
+
25
+ A shadow hardly shows on a near-black page, so the dark edge is a real
26
+ hairline: Starlight's `hairline-shade` there is the page's own colour, and
27
+ a dark slide had no visible edge. Present mode, print and a figure
28
+ captured for the exports draw no edge, shadow, lift or well (below). */
29
+ :root {
30
+ --deck-stage-edge: hsl(224 10% 24%);
31
+ --deck-stage-shadow: 0 2px 4px hsla(0 0% 0% / 0.45), 0 10px 28px hsla(0 0% 0% / 0.6);
32
+ --deck-stage-lift: 5%;
33
+ --deck-well: transparent;
34
+ }
35
+ :root[data-theme='light'] {
36
+ --deck-stage-edge: hsl(224 14% 88%);
37
+ --deck-stage-shadow: 0 2px 4px hsla(224 30% 20% / 0.08), 0 8px 18px hsla(224 30% 20% / 0.1),
38
+ 0 22px 44px hsla(224 30% 20% / 0.1);
39
+ --deck-stage-lift: 0%;
40
+ }
41
+ :root:has([data-explico-slides='edge']) {
42
+ --deck-stage-edge: hsl(224 10% 26%);
43
+ --deck-stage-shadow: 0 1px 2px hsla(0 0% 0% / 0.5), 0 6px 20px hsla(0 0% 0% / 0.55);
44
+ --deck-stage-lift: 0%;
45
+ --deck-well: transparent;
46
+ }
47
+ :root[data-theme='light']:has([data-explico-slides='edge']) {
48
+ --deck-stage-edge: hsl(224 14% 86%);
49
+ --deck-stage-shadow: 0 1px 2px hsla(224 30% 20% / 0.08), 0 4px 10px hsla(224 30% 20% / 0.08),
50
+ 0 14px 30px hsla(224 30% 20% / 0.08);
51
+ --deck-stage-lift: 0%;
52
+ --deck-well: transparent;
53
+ }
54
+ :root:has([data-explico-slides='sorter']) {
55
+ --deck-stage-edge: hsl(224 10% 22%);
56
+ --deck-stage-shadow: 0 2px 4px hsla(0 0% 0% / 0.5), 0 8px 22px hsla(0 0% 0% / 0.55);
57
+ --deck-stage-lift: 3%;
58
+ --deck-well: color-mix(in oklab, var(--sl-color-bg), black 30%);
59
+ }
60
+ :root[data-theme='light']:has([data-explico-slides='sorter']) {
61
+ --deck-stage-edge: hsl(224 14% 86%);
62
+ --deck-stage-shadow: 0 1px 2px hsla(224 30% 20% / 0.08), 0 4px 12px hsla(224 30% 20% / 0.1);
63
+ --deck-stage-lift: 0%;
64
+ --deck-well: hsl(224 22% 94.5%);
65
+ }
66
+
67
+ .deck {
68
+ --deck-scale: 1;
69
+ --deck-ink: var(--sl-color-white);
70
+ --deck-muted: var(--sl-color-gray-3);
71
+ --deck-accent: var(--sl-color-text-accent);
72
+ --deck-rule: var(--sl-color-hairline);
73
+ --deck-paper: var(--sl-color-bg);
74
+ display: flex;
75
+ flex-direction: column;
76
+ gap: 2.25rem;
77
+ margin-block: 1.5rem 2rem;
78
+ }
79
+
80
+ .deck-frame {
81
+ margin: 0;
82
+ }
83
+
84
+ .deck-stage {
85
+ position: relative;
86
+ /* Under the frame's line, its own gap: not the prose's. */
87
+ margin-block-start: 0;
88
+ border: 1px solid var(--deck-stage-edge);
89
+ border-radius: 0.5rem;
90
+ background: var(--deck-paper);
91
+ box-shadow: var(--deck-stage-shadow);
92
+ }
93
+
94
+ /* The lifted sheet: what the slide draws on its own background (a table's
95
+ header, a lab's panel) takes the sheet's colour, not the page's. */
96
+ @media screen {
97
+ :root:not(.deck-presenting) .deck:not([data-deck-static]) {
98
+ --deck-paper: color-mix(in oklab, var(--sl-color-bg), var(--sl-color-white) var(--deck-stage-lift));
99
+ }
100
+ :root:not(.deck-presenting) .deck:not([data-deck-static]) .deck-stage {
101
+ --sl-color-bg: var(--deck-paper);
102
+ }
103
+ :root:not(.deck-presenting):has([data-explico-slides='sorter']) .deck[data-deck-ready]:not([data-deck-static]) {
104
+ margin-inline: calc(-1 * var(--sl-content-pad-x));
105
+ padding: 0.75rem var(--sl-content-pad-x) 1.5rem;
106
+ border-radius: 0.75rem;
107
+ background: var(--deck-well);
108
+ }
109
+ :root:has([data-explico-slides='sorter']) .deck-map {
110
+ background: var(--deck-well);
111
+ }
112
+ }
113
+
114
+ .deck[data-deck-ready] .deck-stage {
115
+ aspect-ratio: 16 / 9;
116
+ overflow: hidden;
117
+ }
118
+ .deck[data-deck-ready][data-aspect='16:10'] .deck-stage {
119
+ aspect-ratio: 16 / 10;
120
+ }
121
+ .deck[data-deck-ready][data-aspect='4:3'] .deck-stage {
122
+ aspect-ratio: 4 / 3;
123
+ }
124
+ /* A figure captured for the exports is drawn at its own size: the canvas
125
+ unscaled and unclipped, so a lab on it hydrates and measures as laid out
126
+ (deck-controller.ts, `explico:prepare-static-export`). */
127
+ .deck[data-deck-ready][data-deck-static] .deck-stage {
128
+ aspect-ratio: auto;
129
+ width: var(--deck-canvas-width, 800px);
130
+ height: var(--deck-canvas-height, 450px);
131
+ overflow: visible;
132
+ }
133
+
134
+ .deck-canvas {
135
+ box-sizing: border-box;
136
+ display: flex;
137
+ flex-direction: column;
138
+ padding: 1.25rem 1.5rem;
139
+ color: var(--deck-ink);
140
+ }
141
+
142
+ .deck[data-deck-ready] .deck-canvas {
143
+ position: absolute;
144
+ inset: 0 auto auto 0;
145
+ width: var(--deck-canvas-width, 800px);
146
+ height: var(--deck-canvas-height, 450px);
147
+ padding: 30px 44px 34px;
148
+ transform: scale(var(--deck-scale));
149
+ transform-origin: 0 0;
150
+ overflow: hidden;
151
+ font-size: 20px;
152
+ line-height: 1.38;
153
+ }
154
+ .deck[data-deck-ready][data-deck-static] .deck-canvas {
155
+ transform: none;
156
+ overflow: visible;
157
+ }
158
+
159
+ /* The canvas sets its own type: none of the page's prose rhythm reaches in. */
160
+ .deck-canvas :is(h2, h3, p, ul, ol, li, figure, table, blockquote) {
161
+ margin: 0;
162
+ }
163
+ .deck-canvas .deck-frame__body > * + * {
164
+ margin-block-start: 0.6em;
165
+ }
166
+ .deck-canvas .deck-frame__body :is(ul, ol) {
167
+ padding-inline-start: 1.15em;
168
+ }
169
+ .deck-canvas .deck-frame__body li + li {
170
+ margin-block-start: 0.3em;
171
+ }
172
+
173
+ .deck .deck-canvas .deck-frame__title {
174
+ margin: 0 0 0.55em;
175
+ font-size: 1.45em;
176
+ font-weight: 650;
177
+ line-height: 1.15;
178
+ color: var(--deck-accent);
179
+ letter-spacing: -0.005em;
180
+ }
181
+
182
+ .deck-frame__body {
183
+ flex: 1 1 auto;
184
+ min-height: 0;
185
+ }
186
+ .deck[data-deck-ready] .deck-frame__body {
187
+ overflow: hidden;
188
+ }
189
+
190
+ /* A frame whose content does not fit (rule D2): the build fails on it, and
191
+ while an author drafts, the page says so where it happens. */
192
+ .deck-frame[data-deck-overflow] .deck-stage {
193
+ outline: 2px dashed #d33;
194
+ outline-offset: 2px;
195
+ }
196
+ .deck-frame[data-deck-overflow] .deck-stage::after {
197
+ content: 'Does not fit its frame (rule D2)';
198
+ position: absolute;
199
+ inset-block-start: 0.4rem;
200
+ inset-inline-end: 0.4rem;
201
+ padding: 0.15rem 0.45rem;
202
+ border-radius: 0.25rem;
203
+ background: #d33;
204
+ color: #fff;
205
+ font: 600 0.7rem/1.2 var(--sl-font, system-ui);
206
+ }
207
+
208
+ /* A display equation on a frame: room around it, its number at the edge. */
209
+ .deck-canvas .keyed-equation,
210
+ .deck-canvas .katex-display {
211
+ margin-block: 0.45em;
212
+ }
213
+
214
+ /* The legend line: the symbols the frame introduces, each with its name. */
215
+ .deck-legend {
216
+ display: flex;
217
+ flex-wrap: wrap;
218
+ gap: 0.15em 1.1em;
219
+ margin-block-start: 0.6em;
220
+ padding-block-start: 0.45em;
221
+ border-block-start: 1px solid var(--deck-rule);
222
+ font-size: 0.62em;
223
+ line-height: 1.3;
224
+ color: var(--deck-muted);
225
+ }
226
+ .deck-legend__item {
227
+ white-space: nowrap;
228
+ }
229
+ .deck-legend__item .katex {
230
+ color: var(--deck-ink);
231
+ }
232
+
233
+ .deck-frame__foot {
234
+ display: none;
235
+ }
236
+ .deck[data-deck-ready] .deck-frame__foot {
237
+ position: absolute;
238
+ inset-inline: 44px 16px;
239
+ inset-block-end: 9px;
240
+ display: flex;
241
+ justify-content: space-between;
242
+ gap: 1em;
243
+ font-size: 10px;
244
+ line-height: 1;
245
+ color: var(--deck-muted);
246
+ font-variant-numeric: tabular-nums;
247
+ }
248
+ .deck-frame__number {
249
+ margin-inline-start: auto;
250
+ }
251
+
252
+ /* A section's divider and the generated frames. */
253
+ .deck[data-deck-ready] .deck-frame--section .deck-canvas,
254
+ .deck[data-deck-ready] .deck-frame--title .deck-canvas {
255
+ justify-content: center;
256
+ }
257
+ .deck .deck-frame--section .deck-frame__title {
258
+ font-size: 1.9em;
259
+ padding-block-end: 0.35em;
260
+ border-block-end: 2px solid var(--deck-accent);
261
+ align-self: flex-start;
262
+ }
263
+ .deck-title__title {
264
+ font-size: 2.1em;
265
+ font-weight: 700;
266
+ line-height: 1.1;
267
+ color: var(--deck-accent);
268
+ }
269
+ .deck-title__course {
270
+ margin-block-start: 0.8em;
271
+ font-size: 1em;
272
+ }
273
+ .deck-title__authors,
274
+ .deck-title__version {
275
+ margin-block-start: 0.3em;
276
+ font-size: 0.7em;
277
+ color: var(--deck-muted);
278
+ }
279
+ .deck-frame--references .deck-frame__body {
280
+ font-size: 0.66em;
281
+ }
282
+
283
+ /* Steps: in Present mode a later step waits for its key press; the study page
284
+ and print show every step. */
285
+ .deck-step {
286
+ transition: opacity 180ms ease-out;
287
+ }
288
+ .deck-step.is-future {
289
+ visibility: hidden;
290
+ opacity: 0;
291
+ }
292
+ li.deck-step {
293
+ display: list-item;
294
+ }
295
+
296
+ /* A spotlit symbol: every place it shows on the frame. */
297
+ .deck-canvas .deck-spotlight {
298
+ border-radius: 0.15em;
299
+ background: color-mix(in srgb, var(--deck-accent) 22%, transparent);
300
+ box-shadow: 0 0 0 0.12em color-mix(in srgb, var(--deck-accent) 22%, transparent);
301
+ transition: background-color 200ms ease-out, box-shadow 200ms ease-out;
302
+ }
303
+
304
+ /* The speaker's notes, under the frame on the study page. */
305
+ .deck-notes {
306
+ margin-block-start: 0.65rem;
307
+ padding: 0.65rem 0.9rem;
308
+ border-inline-start: 3px solid var(--sl-color-accent);
309
+ background: var(--sl-color-gray-7, var(--sl-color-gray-6));
310
+ font-size: var(--sl-text-sm);
311
+ line-height: 1.55;
312
+ }
313
+ .deck-notes::before {
314
+ content: 'Speaker notes';
315
+ display: block;
316
+ margin-block-end: 0.25rem;
317
+ font-size: var(--sl-text-xs);
318
+ letter-spacing: 0.06em;
319
+ text-transform: uppercase;
320
+ color: var(--sl-color-gray-3);
321
+ }
322
+ .deck-notes > :first-child {
323
+ margin-block-start: 0;
324
+ }
325
+ .deck[data-notes='presenter'] .deck-notes,
326
+ .deck[data-notes='off'] .deck-notes {
327
+ display: none;
328
+ }
329
+
330
+ /* The deck's header actions (`LayoutPageTitle.astro`). */
331
+ .deck-actions {
332
+ display: flex;
333
+ flex-wrap: wrap;
334
+ align-items: center;
335
+ gap: 0.5rem 0.9rem;
336
+ margin-block-start: 0.85rem;
337
+ font-size: var(--sl-text-sm);
338
+ }
339
+ .deck-actions__present {
340
+ display: inline-flex;
341
+ align-items: center;
342
+ gap: 0.4rem;
343
+ padding: 0.35rem 0.85rem;
344
+ border: 1px solid var(--sl-color-accent);
345
+ border-radius: 999px;
346
+ background: var(--sl-color-accent);
347
+ color: var(--sl-color-black);
348
+ font: inherit;
349
+ font-weight: 600;
350
+ cursor: pointer;
351
+ }
352
+ .deck-actions__present:hover,
353
+ .deck-actions__present:focus-visible {
354
+ background: var(--sl-color-accent-high);
355
+ border-color: var(--sl-color-accent-high);
356
+ }
357
+ /* "Continue at slide N" / "Present again" (`deck-controller.ts`): it presents
358
+ too, so it is Present's shape, in outline, the second choice beside it. */
359
+ .deck-actions__resume {
360
+ display: inline-flex;
361
+ align-items: center;
362
+ padding: 0.35rem 0.85rem;
363
+ border: 1px solid var(--sl-color-accent);
364
+ border-radius: 999px;
365
+ background: transparent;
366
+ color: var(--sl-color-text-accent);
367
+ font: inherit;
368
+ font-weight: 600;
369
+ cursor: pointer;
370
+ }
371
+ .deck-actions__resume:hover,
372
+ .deck-actions__resume:focus-visible {
373
+ background: var(--sl-color-accent-low);
374
+ }
375
+ .deck-actions__count {
376
+ color: var(--sl-color-gray-3);
377
+ }
378
+ /* "Read the chapter", "Open the part", "Slides for this chapter" and "…for
379
+ this part": links in the title's line, as its "What changed" is. */
380
+ .deck-actions a {
381
+ color: var(--sl-color-text-accent);
382
+ }
383
+
384
+ /* The reader's marks (`deck-memory.ts`, set by `deck-controller.ts`): the
385
+ sidebar's two (`global.css`), a ring for a frame Present mode has not shown
386
+ yet and an accent dot for one that changed since it did. The line under
387
+ the actions counts them and holds the two resets; each frame's line and the
388
+ slide map show them frame by frame. The screen's alone, as the actions
389
+ are. */
390
+ .deck,
391
+ .deck-actions {
392
+ --page-mark-size: 0.4375rem;
393
+ }
394
+ .deck-actions__mark::before,
395
+ .deck-frame__state::before {
396
+ content: '';
397
+ flex: none;
398
+ box-sizing: border-box;
399
+ width: var(--page-mark-size);
400
+ height: var(--page-mark-size);
401
+ border-radius: 50%;
402
+ }
403
+ .deck-actions__mark[data-frame-mark='unseen']::before {
404
+ border: 1.5px solid var(--sl-color-gray-4);
405
+ }
406
+ .deck-actions__mark[data-frame-mark='changed']::before {
407
+ background: var(--sl-color-text-accent);
408
+ }
409
+
410
+ .deck-actions__marks {
411
+ display: flex;
412
+ flex-basis: 100%;
413
+ flex-wrap: wrap;
414
+ align-items: center;
415
+ gap: 0.25rem 0.85rem;
416
+ color: var(--sl-color-gray-2);
417
+ font-size: var(--sl-text-xs);
418
+ }
419
+ .deck-actions__mark:not([hidden]) {
420
+ display: inline-flex;
421
+ align-items: center;
422
+ gap: 0.35rem;
423
+ }
424
+ .deck-actions__mark-buttons {
425
+ display: inline-flex;
426
+ flex-wrap: wrap;
427
+ gap: 0.25rem;
428
+ }
429
+ .deck-actions__mark-button {
430
+ padding: 0.1rem 0.3rem;
431
+ border: 0;
432
+ border-radius: 0.25rem;
433
+ background: none;
434
+ color: var(--sl-color-text-accent);
435
+ font: inherit;
436
+ cursor: pointer;
437
+ }
438
+ .deck-actions__mark-button:not([aria-disabled='true']):hover,
439
+ .deck-actions__mark-button:focus-visible {
440
+ background: var(--sl-color-accent-low);
441
+ }
442
+ /* Out of use (nothing to change), in its place, as the sidebar's. */
443
+ .deck-actions__mark-button[aria-disabled='true'] {
444
+ color: var(--sl-color-gray-3);
445
+ cursor: default;
446
+ }
447
+ .deck-actions__marks-status {
448
+ flex-basis: 100%;
449
+ margin: 0;
450
+ }
451
+
452
+ /* Each frame's line (`installLines`): "Slide 5", the frame's state, and the
453
+ button that presents from it, above the frame and outside its canvas, so
454
+ it never covers the frame and keeps the page's size at any scale. Never in
455
+ Present mode, an export's figure capture or print. */
456
+ .deck-frame__line {
457
+ display: flex;
458
+ flex-wrap: wrap;
459
+ align-items: center;
460
+ gap: 0.35rem 0.75rem;
461
+ min-height: 2.1rem;
462
+ margin-block-end: 0.4rem;
463
+ font-size: var(--sl-text-sm);
464
+ line-height: 1.3;
465
+ color: var(--sl-color-gray-3);
466
+ }
467
+ .deck-frame__name {
468
+ font-weight: 600;
469
+ font-variant-numeric: tabular-nums;
470
+ color: var(--sl-color-gray-2);
471
+ }
472
+ .deck-frame__state:not([hidden]) {
473
+ display: inline-flex;
474
+ align-items: center;
475
+ gap: 0.35rem;
476
+ }
477
+ /* Shown, quietly, with a check; not shown yet and changed since in the
478
+ accent, with the sidebar's ring and dot. */
479
+ .deck-frame__state[data-frame-state='shown']::before {
480
+ width: 0.75rem;
481
+ height: 0.75rem;
482
+ border-radius: 0;
483
+ background: currentColor;
484
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12.5l5 5L20 6.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
485
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 12.5l5 5L20 6.5' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
486
+ }
487
+ .deck-frame__state:is([data-frame-state='unseen'], [data-frame-state='changed']) {
488
+ color: var(--sl-color-text-accent);
489
+ font-weight: 600;
490
+ }
491
+ .deck-frame__state[data-frame-state='unseen']::before {
492
+ border: 1.5px solid currentColor;
493
+ }
494
+ .deck-frame__state[data-frame-state='changed']::before {
495
+ background: currentColor;
496
+ }
497
+
498
+ /* The line's button, at its end: "Continue here", filled as Present is, on
499
+ the frame to continue at, always shown; "Present from here", outlined, on
500
+ every other, shown while the pointer is on the frame or focus is in it
501
+ (it is in the tab order, so a keyboard reaches it), the frame ringed in
502
+ the accent then. Where there is no hover it is always shown, as its glyph
503
+ alone. */
504
+ .deck-frame__present {
505
+ margin-inline-start: auto;
506
+ display: inline-flex;
507
+ align-items: center;
508
+ gap: 0.4rem;
509
+ padding: 0.28rem 0.85rem;
510
+ border: 1px solid var(--sl-color-accent);
511
+ border-radius: 999px;
512
+ background: var(--sl-color-bg);
513
+ color: var(--sl-color-text-accent);
514
+ font: inherit;
515
+ font-weight: 600;
516
+ cursor: pointer;
517
+ opacity: 0;
518
+ }
519
+ /* Focus that a keyboard moved: not the frame Present mode left focused
520
+ after a click. */
521
+ .deck-frame:is(:hover, :focus-visible, :has(:focus-visible)) .deck-frame__present,
522
+ .deck-frame__present:focus-visible,
523
+ .deck-frame[data-deck-continue] .deck-frame__present {
524
+ opacity: 1;
525
+ }
526
+ .deck-frame__present:hover,
527
+ .deck-frame__present:focus-visible {
528
+ background: var(--sl-color-accent-low);
529
+ }
530
+ .deck-frame[data-deck-continue] .deck-frame__present {
531
+ background: var(--sl-color-accent);
532
+ color: var(--sl-color-black);
533
+ }
534
+ .deck-frame[data-deck-continue] .deck-frame__present:hover,
535
+ .deck-frame[data-deck-continue] .deck-frame__present:focus-visible {
536
+ border-color: var(--sl-color-accent-high);
537
+ background: var(--sl-color-accent-high);
538
+ }
539
+ :root:not(.deck-presenting) .deck[data-deck-lines] .deck-frame:is(:hover, :focus-visible, :has(:focus-visible)) .deck-stage {
540
+ box-shadow: 0 0 0 2px var(--sl-color-accent), var(--deck-stage-shadow);
541
+ }
542
+ /* A frame focused itself (Present mode leaves focus on the frame it ended
543
+ at) shows it by that ring, not by an outline round its line and notes. */
544
+ :root:not(.deck-presenting) .deck[data-deck-lines] .deck-frame:focus-visible {
545
+ outline: none;
546
+ }
547
+ @media (hover: none) {
548
+ .deck-frame__present {
549
+ opacity: 1;
550
+ }
551
+ .deck-frame:not([data-deck-continue]) .deck-frame__present {
552
+ padding: 0.4rem;
553
+ }
554
+ .deck-frame:not([data-deck-continue]) .deck-frame__present-label {
555
+ position: absolute;
556
+ width: 1px;
557
+ height: 1px;
558
+ overflow: hidden;
559
+ clip-path: inset(50%);
560
+ white-space: nowrap;
561
+ }
562
+ /* No hover: the ring is focus's alone. */
563
+ :root:not(.deck-presenting) .deck[data-deck-lines] .deck-frame:hover:not(:focus-visible, :has(:focus-visible)) .deck-stage {
564
+ box-shadow: var(--deck-stage-shadow);
565
+ }
566
+ }
567
+
568
+ /* The slide map (`installMap`): every frame as a numbered square, filled once
569
+ shown, outlined before, dotted when changed since; the frame to continue
570
+ at ringed, the one in view underlined. It sits at the deck's top and
571
+ stays under the header while the deck scrolls, a card over the frames
572
+ then. A frame a link to it lands on keeps its line clear of it. */
573
+ .deck[data-deck-map] .deck-frame {
574
+ scroll-margin-block-start: calc(var(--deck-map-height, 0px) + 0.75rem);
575
+ }
576
+ .deck-map {
577
+ position: sticky;
578
+ inset-block-start: calc(var(--sl-nav-height) + var(--sl-mobile-toc-height, 0rem));
579
+ z-index: 3;
580
+ align-self: flex-start;
581
+ box-sizing: border-box;
582
+ display: flex;
583
+ align-items: center;
584
+ gap: 0.6rem;
585
+ max-width: 100%;
586
+ margin-block-end: -0.75rem;
587
+ padding: 0.4rem 0.5rem;
588
+ margin-inline-start: -0.5rem;
589
+ border-radius: 0.6rem;
590
+ background: var(--sl-color-bg);
591
+ font-size: var(--sl-text-sm);
592
+ line-height: 1;
593
+ }
594
+ .deck-map[data-stuck] {
595
+ box-shadow: var(--sl-shadow-md);
596
+ }
597
+ .deck-map__label {
598
+ flex: none;
599
+ color: var(--sl-color-gray-3);
600
+ }
601
+ /* A phone's line is short: the squares take the label's room, and the
602
+ label names the map to a screen reader alone. */
603
+ @media (max-width: 30rem) {
604
+ .deck-map__label {
605
+ position: absolute;
606
+ width: 1px;
607
+ height: 1px;
608
+ overflow: hidden;
609
+ clip-path: inset(50%);
610
+ white-space: nowrap;
611
+ }
612
+ }
613
+ .deck-map__list {
614
+ display: flex;
615
+ flex-wrap: nowrap;
616
+ gap: 0.25rem;
617
+ min-width: 0;
618
+ margin: 0;
619
+ padding: 0;
620
+ list-style: none;
621
+ }
622
+ .deck-map__list[data-wrap] {
623
+ flex-wrap: wrap;
624
+ }
625
+ .deck-map__list > li {
626
+ display: flex;
627
+ margin: 0;
628
+ padding: 0;
629
+ }
630
+ .deck-map__slide {
631
+ position: relative;
632
+ box-sizing: border-box;
633
+ display: grid;
634
+ place-items: center;
635
+ min-width: 1.75rem;
636
+ height: 1.75rem;
637
+ padding-inline: 0.3rem;
638
+ border: 1px solid var(--sl-color-gray-5);
639
+ border-radius: 0.4rem;
640
+ color: var(--sl-color-gray-2);
641
+ font-weight: 600;
642
+ font-variant-numeric: tabular-nums;
643
+ text-decoration: none;
644
+ }
645
+ .deck-map__slide:hover,
646
+ .deck-map__slide:focus-visible {
647
+ border-color: var(--sl-color-accent);
648
+ color: var(--sl-color-text-accent);
649
+ }
650
+ .deck-map__slide:is([data-frame-state='shown'], [data-frame-state='changed']) {
651
+ border-color: transparent;
652
+ background: var(--sl-color-accent-low);
653
+ color: var(--sl-color-text-accent);
654
+ }
655
+ .deck-map__slide[data-frame-state='changed']::after {
656
+ content: '';
657
+ position: absolute;
658
+ inset-block-start: 0.2rem;
659
+ inset-inline-end: 0.2rem;
660
+ width: 0.35rem;
661
+ height: 0.35rem;
662
+ border-radius: 50%;
663
+ background: var(--sl-color-text-accent);
664
+ }
665
+ .deck-map__slide[data-deck-continue] {
666
+ border: 2px solid var(--sl-color-accent);
667
+ color: var(--sl-color-text-accent);
668
+ }
669
+ .deck-map__slide[aria-current='true']::before {
670
+ content: '';
671
+ position: absolute;
672
+ inset-inline: 0.15rem;
673
+ inset-block-end: -0.3rem;
674
+ height: 0.18rem;
675
+ border-radius: 0.1rem;
676
+ background: var(--sl-color-white);
677
+ }
678
+ .deck-map__gap > a {
679
+ display: grid;
680
+ place-items: center;
681
+ min-width: 1rem;
682
+ height: 1.75rem;
683
+ color: var(--sl-color-gray-3);
684
+ text-decoration: none;
685
+ }
686
+ .deck-map__gap > a:hover,
687
+ .deck-map__gap > a:focus-visible {
688
+ color: var(--sl-color-text-accent);
689
+ }
690
+ :root:is(.deck-presenting, .deck-presenter-window) :is(.deck-frame__line, .deck-map),
691
+ .deck[data-deck-static] :is(.deck-frame__line, .deck-map) {
692
+ display: none;
693
+ }
694
+ /* Forced colours drop shadows and paint backgrounds as the canvas: the
695
+ check, the dot and the bar under the frame in view keep the text's colour,
696
+ a square shown is filled with the system's highlight, and the ring round a
697
+ frame is an outline. */
698
+ @media (forced-colors: active) {
699
+ :is(.deck-frame__state, .deck-actions__mark)[data-frame-state]::before,
700
+ .deck-actions__mark[data-frame-mark='changed']::before,
701
+ .deck-map__slide::before,
702
+ .deck-map__slide::after {
703
+ forced-color-adjust: none;
704
+ background: CanvasText;
705
+ }
706
+ .deck-frame__state[data-frame-state='unseen']::before {
707
+ background: none;
708
+ }
709
+ .deck-map__slide:is([data-frame-state='shown'], [data-frame-state='changed']) {
710
+ forced-color-adjust: none;
711
+ border-color: Highlight;
712
+ background: Highlight;
713
+ color: HighlightText;
714
+ }
715
+ .deck-map__slide[data-frame-state='changed']::after {
716
+ background: HighlightText;
717
+ }
718
+ .deck-map__slide[data-deck-continue] {
719
+ border-color: LinkText;
720
+ }
721
+ :root:not(.deck-presenting) .deck[data-deck-lines] .deck-frame:is(:hover, :focus-visible, :has(:focus-visible)) .deck-stage {
722
+ outline: 2px solid Highlight;
723
+ }
724
+ }
725
+
726
+ /* Present mode: one frame on the whole screen, letterboxed. */
727
+ :root.deck-presenting {
728
+ overflow: hidden;
729
+ }
730
+ :root.deck-presenting :is(.header, .sidebar-pane, .right-sidebar-container, .pagination-links, .explico-site-footer, .lesson-breadcrumb, .explico-reading-notice, .explico-standalone-theme) {
731
+ display: none !important;
732
+ }
733
+ :root.deck-presenting .deck {
734
+ position: fixed;
735
+ inset: 0;
736
+ z-index: calc(var(--sl-z-index-navbar) - 1);
737
+ margin: 0;
738
+ gap: 0;
739
+ display: grid;
740
+ place-items: center;
741
+ background: #000;
742
+ }
743
+ :root.deck-presenting .deck-frame {
744
+ display: none;
745
+ }
746
+ :root.deck-presenting .deck-frame.is-current {
747
+ display: block;
748
+ width: min(100vw, calc(100vh * var(--deck-ratio, 1.7778)));
749
+ }
750
+ :root.deck-presenting .deck-stage {
751
+ border: 0;
752
+ border-radius: 0;
753
+ box-shadow: none;
754
+ }
755
+ :root.deck-presenting .deck-notes {
756
+ display: none;
757
+ }
758
+ /* On one screen, the notes beside the frame (`N`). */
759
+ :root.deck-presenting.deck-notes-open .deck-frame.is-current {
760
+ display: grid;
761
+ grid-template-columns: minmax(0, 1fr) min(30vw, 26rem);
762
+ align-items: center;
763
+ gap: 1.25rem;
764
+ width: 100vw;
765
+ padding-inline: 1.25rem;
766
+ box-sizing: border-box;
767
+ }
768
+ :root.deck-presenting.deck-notes-open .deck-frame.is-current .deck-notes {
769
+ display: block;
770
+ max-height: 90vh;
771
+ overflow: auto;
772
+ color: #eee;
773
+ background: #1a1a1a;
774
+ }
775
+ :root.deck-presenting.deck-blackout .deck-frame.is-current {
776
+ visibility: hidden;
777
+ }
778
+
779
+ /* The controls Present mode shows while the pointer moves. */
780
+ .deck-hud {
781
+ display: none;
782
+ }
783
+ :root.deck-presenting .deck-hud {
784
+ position: fixed;
785
+ inset-inline: 0;
786
+ inset-block-end: 0;
787
+ z-index: calc(var(--sl-z-index-navbar) - 1);
788
+ display: flex;
789
+ justify-content: center;
790
+ gap: 0.5rem;
791
+ padding: 0.6rem;
792
+ opacity: 0;
793
+ transition: opacity 200ms ease-out;
794
+ }
795
+ :root.deck-presenting.deck-hud-visible .deck-hud,
796
+ :root.deck-presenting .deck-hud:focus-within {
797
+ opacity: 1;
798
+ }
799
+ .deck-hud button,
800
+ .deck-hud span {
801
+ padding: 0.3rem 0.7rem;
802
+ border: 1px solid #555;
803
+ border-radius: 0.4rem;
804
+ background: rgb(20 20 20 / 0.85);
805
+ color: #eee;
806
+ font: 600 0.85rem/1.2 var(--sl-font, system-ui);
807
+ font-variant-numeric: tabular-nums;
808
+ }
809
+ .deck-hud button {
810
+ cursor: pointer;
811
+ }
812
+ .deck-hud button:hover,
813
+ .deck-hud button:focus-visible {
814
+ border-color: var(--sl-color-accent);
815
+ }
816
+
817
+ /* The presenter window (`?presenter`): this frame, the next, notes, clock. */
818
+ :root.deck-presenter-window .deck-frame {
819
+ display: none;
820
+ }
821
+ :root.deck-presenter-window .deck {
822
+ position: fixed;
823
+ inset: 0;
824
+ z-index: calc(var(--sl-z-index-navbar) - 1);
825
+ margin: 0;
826
+ display: grid;
827
+ grid-template-columns: 3fr 2fr;
828
+ grid-template-rows: auto 1fr;
829
+ gap: 1rem;
830
+ padding: 1rem;
831
+ background: #111;
832
+ color: #eee;
833
+ }
834
+ :root.deck-presenter-window .deck-frame.is-current {
835
+ display: block;
836
+ grid-column: 1;
837
+ grid-row: 1 / span 2;
838
+ }
839
+ :root.deck-presenter-window .deck-frame.is-next {
840
+ display: block;
841
+ grid-column: 2;
842
+ grid-row: 1;
843
+ opacity: 0.85;
844
+ }
845
+ :root.deck-presenter-window .deck-frame.is-next .deck-notes {
846
+ display: none;
847
+ }
848
+ :root.deck-presenter-window .deck-frame.is-current .deck-notes {
849
+ display: block;
850
+ position: fixed;
851
+ inset-inline-end: 1rem;
852
+ inset-block-end: 3.5rem;
853
+ width: calc(40vw - 2rem);
854
+ max-height: 50vh;
855
+ overflow: auto;
856
+ background: #1a1a1a;
857
+ color: #eee;
858
+ font-size: 1.05rem;
859
+ }
860
+ .deck-clock {
861
+ display: none;
862
+ }
863
+ :root.deck-presenter-window .deck-clock {
864
+ position: fixed;
865
+ inset-inline-end: 1rem;
866
+ inset-block-end: 1rem;
867
+ z-index: calc(var(--sl-z-index-navbar) - 1);
868
+ display: block;
869
+ font: 600 1.3rem/1 var(--sl-font, system-ui);
870
+ font-variant-numeric: tabular-nums;
871
+ color: #eee;
872
+ }
873
+
874
+ @media (prefers-reduced-motion: reduce) {
875
+ .deck-step,
876
+ .deck-canvas .deck-spotlight,
877
+ .deck-hud {
878
+ transition: none;
879
+ }
880
+ }
881
+
882
+ /* Print: one frame a page, every step shown, notes under the frame only when
883
+ the course shows them to readers. */
884
+ @media print {
885
+ /* The Present button and its links are the screen's (the deck's
886
+ standalone HTML keeps them; print never shows them). */
887
+ .deck-actions {
888
+ display: none !important;
889
+ }
890
+ @page deck-16-9 {
891
+ size: 13.333in 7.5in;
892
+ margin: 0;
893
+ }
894
+ @page deck-16-10 {
895
+ size: 12in 7.5in;
896
+ margin: 0;
897
+ }
898
+ @page deck-4-3 {
899
+ size: 10in 7.5in;
900
+ margin: 0;
901
+ }
902
+ .deck {
903
+ display: block;
904
+ }
905
+ .deck-frame {
906
+ page: deck-16-9;
907
+ break-after: page;
908
+ break-inside: avoid;
909
+ }
910
+ .deck[data-aspect='16:10'] .deck-frame {
911
+ page: deck-16-10;
912
+ }
913
+ .deck[data-aspect='4:3'] .deck-frame {
914
+ page: deck-4-3;
915
+ }
916
+ /* The canvas, 450 px tall, on a page 7.5 in (720 px) tall. */
917
+ .deck[data-deck-ready] .deck-stage {
918
+ width: calc(var(--deck-canvas-width, 800px) * 1.6);
919
+ height: 7.5in;
920
+ aspect-ratio: auto;
921
+ border: 0;
922
+ border-radius: 0;
923
+ box-shadow: none;
924
+ }
925
+ .deck[data-deck-ready] .deck-canvas {
926
+ transform: scale(1.6);
927
+ }
928
+ .deck-step.is-future {
929
+ visibility: visible;
930
+ opacity: 1;
931
+ }
932
+ .deck-notes,
933
+ .deck-actions,
934
+ .deck-frame__line,
935
+ .deck-map {
936
+ display: none;
937
+ }
938
+ }
939
+
940
+ /* A deck in the sidebar: a filled 16:9 slide frame with a play mark cut out
941
+ of it, where a chapter is a sheet with lines of text and a part two
942
+ sheets. A chapter's deck is a smaller row under the chapter; a
943
+ slides-first lesson, whose deck is the lesson, is a lesson's row with the
944
+ glyph before its title, as the Overview row has its own. Once the
945
+ sidebar's script makes a lesson one row (`sidebar-editions.ts`), the deck
946
+ is the icon at its chapter row's end (`a.layout-edition-other`), or leads
947
+ the row and has no glyph. The glyph is the link's `::before`, a mask over
948
+ its own colour, so it takes the link's colour in every state and the
949
+ page's colour shows through the mark. The mark points right in either
950
+ reading direction, as a play control does. */
951
+ :root {
952
+ --explico-deck-glyph: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2010'%3E%3Cpath%20fill='black'%20fill-rule='evenodd'%20d='M2%200h12a2%202%200%200%201%202%202v6a2%202%200%200%201-2%202H2a2%202%200%200%201-2-2V2a2%202%200%200%201%202-2ZM6.2%202.3v5.4L11%205Z'/%3E%3C/svg%3E");
953
+ --explico-part-deck-glyph: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2012'%3E%3Cpath%20fill='none'%20stroke='black'%20stroke-width='1.5'%20stroke-linecap='round'%20stroke-linejoin='round'%20d='M3.3%200.75H14.1a1.15%201.15%200%200%201%201.15%201.15V8.4'/%3E%3Cpath%20fill='black'%20fill-rule='evenodd'%20d='M1.6%202.7h9.9a1.6%201.6%200%200%201%201.6%201.6v6a1.6%201.6%200%200%201-1.6%201.6H1.6A1.6%201.6%200%200%201%200%2010.3v-6a1.6%201.6%200%200%201%201.6-1.6ZM5.1%204.75v5.1L9.3%207.3Z'/%3E%3C/svg%3E");
954
+ }
955
+ :is(a.explico-deck-row, a.explico-deck-lesson, a.layout-edition-other[data-edition='slides']) {
956
+ --deck-glyph-start: var(--sl-sidebar-item-padding-inline, 0.5rem);
957
+ }
958
+ .sidebar-content :is(a.explico-deck-row, a.explico-deck-lesson),
959
+ .layout-navigation-content :is(a.explico-deck-row, a.explico-deck-lesson) {
960
+ position: relative;
961
+ display: flex;
962
+ align-items: center;
963
+ gap: 0.45rem;
964
+ }
965
+ .sidebar-content a.explico-deck-row,
966
+ .layout-navigation-content a.explico-deck-row {
967
+ --deck-glyph-start: 1.1rem;
968
+ padding-inline-start: var(--deck-glyph-start);
969
+ font-size: var(--sl-text-sm);
970
+ }
971
+ /* A part's deck is the part's own, as its Overview is: at the list's start,
972
+ its size and inset Starlight's own. The sidebar's script makes the two the
973
+ part's one row (`sidebar-editions.ts`), the deck its own row's lead or the
974
+ icon at Overview's end; without the script it is a row of its own. */
975
+ .sidebar-content a.explico-deck-row.explico-part-deck,
976
+ .layout-navigation-content a.explico-deck-row.explico-part-deck {
977
+ --deck-glyph-start: var(--sl-sidebar-item-padding-inline, 0.5rem);
978
+ padding-inline-start: revert-layer;
979
+ font-size: revert-layer;
980
+ }
981
+ .sidebar-content a.explico-part-deck,
982
+ .layout-navigation-content a.explico-part-deck {
983
+ display: flex;
984
+ align-items: center;
985
+ gap: 0.45rem;
986
+ }
987
+ :is(a.explico-deck-row, a.explico-deck-lesson, a.layout-edition-other[data-edition='slides'])::before {
988
+ content: '';
989
+ flex: none;
990
+ width: 1rem;
991
+ height: 0.625rem;
992
+ background: currentColor;
993
+ -webkit-mask: var(--explico-deck-glyph) center / contain no-repeat;
994
+ mask: var(--explico-deck-glyph) center / contain no-repeat;
995
+ }
996
+ /* A part's deck is two frames: the deck's glyph in front, filled, with an
997
+ outlined frame behind it, as Overview is two sheets. It is the part's in
998
+ every place, so it carries its glyph in every state: its own row, the
999
+ icon at Overview's end, a tile. */
1000
+ a.explico-part-deck[data-edition='slides']::before {
1001
+ content: '';
1002
+ flex: none;
1003
+ width: 1rem;
1004
+ height: 0.75rem;
1005
+ background: currentColor;
1006
+ -webkit-mask: var(--explico-part-deck-glyph) center / contain no-repeat;
1007
+ mask: var(--explico-part-deck-glyph) center / contain no-repeat;
1008
+ }
1009
+ /* Forced colours paint a background as the canvas: the glyph keeps its
1010
+ link's colour, the system's link colour then. */
1011
+ @media (forced-colors: active) {
1012
+ :is(a.explico-deck-row, a.explico-deck-lesson, a.layout-edition-other[data-edition='slides'], a.explico-part-deck)::before {
1013
+ forced-color-adjust: none;
1014
+ background: currentColor;
1015
+ }
1016
+ }
1017
+ @media (min-width: 50rem) {
1018
+ /* A tile, whatever its place in the row: the glyph centred, a little
1019
+ larger. A deck that leads its row has no class of its own, so the tile
1020
+ draws it from `data-edition`. */
1021
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li > a[data-edition='slides'] {
1022
+ padding-inline-start: 0;
1023
+ }
1024
+ /* As specific as a chapter tile's sheet (`global.css`), which it replaces. */
1025
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li > a[data-edition='slides']::before {
1026
+ width: 1.1rem;
1027
+ height: 0.69rem;
1028
+ -webkit-mask: var(--explico-deck-glyph) center / contain no-repeat;
1029
+ mask: var(--explico-deck-glyph) center / contain no-repeat;
1030
+ }
1031
+
1032
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li > a.explico-part-deck[data-edition='slides']::before {
1033
+ width: 1.15rem;
1034
+ height: 0.86rem;
1035
+ -webkit-mask: var(--explico-part-deck-glyph) center / contain no-repeat;
1036
+ mask: var(--explico-part-deck-glyph) center / contain no-repeat;
1037
+ }
1038
+
1039
+ /* A part's deck is the part's own, as its Overview is: its tile takes the
1040
+ accent the Overview tile takes (`global.css`). The sidebar's script
1041
+ joins the two as a lesson's pair (`li[data-editions='pair']`), and both
1042
+ keep the accent beside the open one, where a lesson's tile turns grey.
1043
+ Without the script the deck's tile joins no other. */
1044
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li > a.explico-part-deck {
1045
+ color: var(--sl-color-text-accent);
1046
+ border-color: var(--sl-color-text-accent);
1047
+ }
1048
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li > a.explico-part-deck[aria-current='page'] {
1049
+ color: var(--sl-color-text-invert);
1050
+ }
1051
+ .layout-compact-sidebar
1052
+ details[data-compact]
1053
+ > ul:not(.top-level)
1054
+ > li[data-editions='pair']
1055
+ > a[data-part-edition][aria-current='page']
1056
+ + a.layout-edition-other[data-part-edition]:not(:hover, :focus-visible) {
1057
+ color: var(--sl-color-text-accent);
1058
+ }
1059
+
1060
+ /* A chapter's tile and its deck's tile touch, as one pair. The deck's tile
1061
+ takes back the list's gap and lies over the chapter's last pixel, its own
1062
+ border clear there, so the line between them is the chapter's border, and
1063
+ the corners where they meet are square. That line takes the colour of
1064
+ whichever tile is lit; the open page's tile is outlined in accent, so its
1065
+ fill and the line read as one. Every rule needs `:has()`: a browser
1066
+ without it keeps the two tiles apart, as before. This is the sidebar as
1067
+ the compiler wrote it, one item per edition; the sidebar's script puts a
1068
+ lesson's two links in one item, joined the same way by
1069
+ `li[data-editions='pair']` (`global.css`), and these rules then match
1070
+ nothing. */
1071
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(> a.explico-deck-row:not(.explico-part-deck)) {
1072
+ margin-inline-start: calc(-0.35rem - 1px);
1073
+ }
1074
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(> a.explico-deck-row:not(.explico-part-deck)) > a.explico-deck-row {
1075
+ border-inline-start-color: transparent;
1076
+ border-start-start-radius: 0;
1077
+ border-end-start-radius: 0;
1078
+ background-clip: padding-box;
1079
+ }
1080
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(+ li > a.explico-deck-row:not(.explico-part-deck)) > a {
1081
+ border-start-end-radius: 0;
1082
+ border-end-end-radius: 0;
1083
+ }
1084
+ /* A covered tile keeps its tint under a pointer (`global.css`), so its line does too. */
1085
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(+ li:not([data-covered]) > a.explico-deck-row:not(.explico-part-deck):is(:hover, :focus-visible)) > a {
1086
+ border-inline-end-color: var(--sl-color-accent);
1087
+ }
1088
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(+ li > a.explico-deck-row:not(.explico-part-deck)) > a[aria-current='page'],
1089
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(> a.explico-deck-row:not(.explico-part-deck)) > a.explico-deck-row[aria-current='page'] {
1090
+ border-color: var(--sl-color-text-accent);
1091
+ }
1092
+ .layout-compact-sidebar details[data-compact] > ul:not(.top-level) > li:has(+ li > a.explico-deck-row:not(.explico-part-deck)[aria-current='page']) > a {
1093
+ border-inline-end-color: var(--sl-color-text-accent);
1094
+ }
1095
+ }
1096
+
1097
+ /* A figure on a frame is the frame's picture (rule D7). A lab's tools stand
1098
+ beside its picture rather than folded under its caption, so a lab and its
1099
+ sliders share the frame's width, as a wide screen has room for. */
1100
+ .deck[data-deck-ready] .deck-canvas .keyed-figure {
1101
+ margin: 0;
1102
+ }
1103
+ .deck[data-deck-ready] .deck-canvas .keyed-figure[data-fig-tools] {
1104
+ display: grid;
1105
+ grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
1106
+ grid-template-rows: auto auto;
1107
+ grid-template-areas:
1108
+ 'body tools'
1109
+ 'caption tools';
1110
+ align-items: start;
1111
+ column-gap: 22px;
1112
+ }
1113
+ .deck[data-deck-ready] .deck-canvas .keyed-figure[data-fig-tools] > .keyed-figure__body {
1114
+ grid-area: body;
1115
+ min-width: 0;
1116
+ }
1117
+ .deck[data-deck-ready] .deck-canvas .keyed-figure[data-fig-tools] > figcaption {
1118
+ grid-area: caption;
1119
+ }
1120
+ .deck[data-deck-ready] .deck-canvas .keyed-figure[data-fig-tools] > .keyed-figure__tools-fold {
1121
+ grid-area: tools;
1122
+ min-width: 0;
1123
+ margin: 0;
1124
+ font-size: 0.8em;
1125
+ }
1126
+ .deck-canvas :is(.keyed-figure__tools-summary, .keyed-figure__tools-stub, .keyed-figure__tools-toggle) {
1127
+ display: none !important;
1128
+ }
1129
+ .deck-canvas .keyed-figure__caption,
1130
+ .deck-canvas .keyed-table__caption,
1131
+ .deck-canvas .diagram figcaption {
1132
+ font-size: 0.68em;
1133
+ line-height: 1.35;
1134
+ }
1135
+
1136
+ /* A question frame: the check's label, then its runner. */
1137
+ .deck-canvas .deck-check__label {
1138
+ margin: 0 0 0.4em;
1139
+ font-size: 0.75em;
1140
+ color: var(--deck-muted);
1141
+ }
1142
+ .deck-canvas .deck-check__kind {
1143
+ font-weight: 650;
1144
+ color: var(--deck-accent);
1145
+ }
1146
+
1147
+ /* A step with nothing to show (a driven figure, a spotlight) takes no room. */
1148
+ .deck-canvas .deck-step:empty {
1149
+ display: none;
1150
+ }