explico 0.8.0 → 0.11.1

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 (230) hide show
  1. package/CHANGELOG.md +1257 -1
  2. package/README.md +60 -15
  3. package/dist/compiler/astro.d.ts +6 -1
  4. package/dist/compiler/cli.d.ts +46 -2
  5. package/dist/compiler/cli.js +70 -4
  6. package/dist/compiler/collections.d.ts +35 -2
  7. package/dist/compiler/collections.js +68 -5
  8. package/dist/compiler/course-config.d.ts +3 -194
  9. package/dist/compiler/course-config.js +78 -5
  10. package/dist/compiler/exports/standalone-html.d.ts +6 -1
  11. package/dist/compiler/knowledge-version.js +1 -1
  12. package/dist/compiler/lesson-derivation.d.ts +27 -10
  13. package/dist/compiler/lesson-derivation.js +23 -8
  14. package/dist/compiler/logging.d.ts +4 -1
  15. package/dist/compiler/logging.js +4 -1
  16. package/dist/compiler/manifest.d.ts +204 -31
  17. package/dist/compiler/manifest.js +270 -55
  18. package/dist/compiler/resolution-report.d.ts +6 -1
  19. package/dist/course-config-Dsnri9Tk.d.ts +464 -0
  20. package/dist/reference/base-accents.d.mts +26 -0
  21. package/dist/reference/base-accents.mjs +31 -0
  22. package/dist/reference/base-roman-labels.d.mts +2 -2
  23. package/dist/reference/base-roman-labels.mjs +2 -2
  24. package/dist/reference/consistency.d.ts +14 -2
  25. package/dist/reference/consistency.js +108 -4
  26. package/dist/reference/delimiter-size.d.ts +3 -2
  27. package/dist/reference/diagrams-validate.d.ts +7 -2
  28. package/dist/reference/diagrams-validate.js +9 -1
  29. package/dist/reference/equations-validate.d.ts +8 -5
  30. package/dist/reference/equations-validate.js +1 -0
  31. package/dist/reference/equations.d.mts +60 -31
  32. package/dist/reference/equations.mjs +83 -43
  33. package/dist/reference/examples-validate.d.ts +31 -0
  34. package/dist/reference/examples-validate.js +48 -0
  35. package/dist/reference/figures-validate.d.ts +1 -1
  36. package/dist/reference/figures-validate.js +4 -1
  37. package/dist/reference/folds-validate.d.ts +33 -0
  38. package/dist/reference/folds-validate.js +32 -0
  39. package/dist/reference/gate-abbreviations.d.ts +3 -1
  40. package/dist/reference/gate-abbreviations.js +1 -0
  41. package/dist/reference/gate-course-rules.d.ts +32 -0
  42. package/dist/reference/gate-course-rules.js +85 -0
  43. package/dist/reference/gate-heading-length.d.ts +5 -2
  44. package/dist/reference/gate-heading-length.js +45 -21
  45. package/dist/reference/gate-heading-structure.d.ts +41 -0
  46. package/dist/reference/gate-heading-structure.js +113 -0
  47. package/dist/reference/gate-math-punctuation.d.ts +71 -0
  48. package/dist/reference/gate-math-punctuation.js +251 -0
  49. package/dist/reference/gate-math.d.ts +22 -6
  50. package/dist/reference/gate-math.js +42 -8
  51. package/dist/reference/gate-part-pages.d.ts +50 -0
  52. package/dist/reference/gate-part-pages.js +118 -0
  53. package/dist/reference/gate-prose-notation.d.ts +21 -11
  54. package/dist/reference/gate-prose-notation.js +25 -7
  55. package/dist/reference/katex-delimiters.mjs +20 -7
  56. package/dist/reference/keyed-float-validate.d.ts +27 -10
  57. package/dist/reference/keyed-float-validate.js +15 -1
  58. package/dist/reference/keyed-jsx-floats.d.mts +11 -5
  59. package/dist/reference/keyed-jsx-floats.mjs +73 -20
  60. package/dist/reference/knowledge-checks-validate.d.ts +1 -1
  61. package/dist/reference/knowledge-checks.d.mts +3 -1
  62. package/dist/reference/knowledge-checks.mjs +9 -4
  63. package/dist/reference/lab-math-scope.d.ts +1 -0
  64. package/dist/reference/lab-math-slot.d.ts +34 -0
  65. package/dist/reference/lab-math-slot.js +6 -0
  66. package/dist/reference/math-glyphs.d.mts +80 -4
  67. package/dist/reference/math-glyphs.mjs +572 -37
  68. package/dist/reference/page-notation.d.ts +6 -1
  69. package/dist/reference/raw-floats-validate.js +1 -1
  70. package/dist/reference/raw-floats.mjs +1 -1
  71. package/dist/reference/rehype-heading-anchors.d.mts +14 -0
  72. package/dist/reference/rehype-heading-anchors.mjs +116 -17
  73. package/dist/reference/rehype-table-header-labels.d.mts +6 -1
  74. package/dist/reference/rehype-table-header-labels.mjs +21 -3
  75. package/dist/reference/remark-asides.d.mts +3 -0
  76. package/dist/reference/remark-asides.mjs +180 -0
  77. package/dist/reference/remark-memo.d.mts +3 -1
  78. package/dist/reference/remark-memo.mjs +42 -11
  79. package/dist/reference/remark-notation.d.mts +60 -10
  80. package/dist/reference/remark-notation.mjs +387 -36
  81. package/dist/reference/render-lab-math.d.ts +4 -26
  82. package/dist/reference/render-lab-math.js +4 -4
  83. package/dist/reference/sections-validate.d.ts +27 -0
  84. package/dist/reference/sections-validate.js +41 -0
  85. package/dist/reference/sections.d.mts +97 -0
  86. package/dist/reference/sections.mjs +306 -0
  87. package/dist/reference/tables-validate.d.ts +1 -1
  88. package/dist/reference/types.d.ts +17 -1
  89. package/dist/reference/unit-words.d.ts +37 -0
  90. package/dist/reference/unit-words.js +170 -0
  91. package/dist/rules/catalog.d.ts +176 -0
  92. package/dist/rules/catalog.js +983 -0
  93. package/dist/rules/course-rules.d.ts +115 -0
  94. package/dist/rules/course-rules.js +292 -0
  95. package/dist/rules/course-rules.schema.json +138 -0
  96. package/dist/rules/in-effect.d.ts +53 -0
  97. package/dist/rules/in-effect.js +142 -0
  98. package/dist/rules/rules.schema.json +1072 -0
  99. package/dist/rules/settings.d.ts +3 -0
  100. package/dist/rules/settings.js +290 -0
  101. package/dist/rules/waivers.d.ts +53 -0
  102. package/dist/rules/waivers.js +132 -0
  103. package/dist/session/PreferenceStore.d.ts +5 -0
  104. package/dist/session/PreferenceStore.js +9 -0
  105. package/docs/VERSIONING.md +5 -3
  106. package/docs/authoring/README.md +232 -40
  107. package/docs/authoring/agents.md +55 -9
  108. package/docs/authoring/components.md +178 -22
  109. package/docs/authoring/migrating.md +1152 -2
  110. package/docs/authoring/notation.md +576 -322
  111. package/docs/authoring/prose.md +551 -0
  112. package/docs/authoring/retired.md +35 -0
  113. package/docs/authoring/structure-rules.md +422 -40
  114. package/docs/authoring/structure.md +445 -62
  115. package/docs/authoring/versioning.md +20 -28
  116. package/docs/authoring/visualizations.md +142 -20
  117. package/package.json +2 -2
  118. package/src/compiler/cli.ts +116 -6
  119. package/src/compiler/collections.ts +111 -7
  120. package/src/compiler/course-config.ts +273 -34
  121. package/src/compiler/knowledge-version.ts +1 -1
  122. package/src/compiler/lesson-derivation.ts +54 -15
  123. package/src/compiler/logging.ts +8 -2
  124. package/src/compiler/manifest.ts +573 -104
  125. package/src/components/BlockHeading.astro +113 -0
  126. package/src/components/CourseContents.astro +221 -0
  127. package/src/components/CurriculumMap.astro +5 -6
  128. package/src/components/FloatIndex.astro +200 -0
  129. package/src/components/HoverPanel.astro +431 -79
  130. package/src/components/PartBridge.astro +27 -0
  131. package/src/components/PartOverview.astro +401 -0
  132. package/src/components/PartScope.astro +27 -0
  133. package/src/components/abbreviation/AbbreviationLayer.astro +49 -51
  134. package/src/components/assessments/AssessmentRunner.tsx +8 -5
  135. package/src/components/assessments/AssessmentSet.astro +23 -26
  136. package/src/components/block-heading.ts +146 -0
  137. package/src/components/card-arrow.ts +243 -0
  138. package/src/components/card-drag.ts +631 -0
  139. package/src/components/card-jump.ts +45 -0
  140. package/src/components/card-manager.ts +1589 -0
  141. package/src/components/card-memory.ts +177 -0
  142. package/src/components/card-placement.ts +504 -0
  143. package/src/components/card-side.ts +336 -0
  144. package/src/components/card-travel.ts +197 -0
  145. package/src/components/citation/CitationLayer.astro +77 -76
  146. package/src/components/diagram/Diagram.astro +161 -316
  147. package/src/components/disclosure/course-disclosure.ts +24 -0
  148. package/src/components/disclosure/hover-preview.ts +122 -42
  149. package/src/components/disclosure/persisted-disclosure.ts +3 -3
  150. package/src/components/disclosure/print-as-shown.ts +252 -0
  151. package/src/components/examples/CompactExample.astro +3 -1
  152. package/src/components/examples/CompactExamples.astro +101 -94
  153. package/src/components/figure/Figure.astro +174 -274
  154. package/src/components/figure/FloatCaption.astro +87 -0
  155. package/src/components/figure/figure-state.ts +58 -0
  156. package/src/components/figure/figure-tools.ts +87 -0
  157. package/src/components/float-name.ts +101 -0
  158. package/src/components/fold/Fold.astro +125 -0
  159. package/src/components/fold/fold-id.ts +40 -0
  160. package/src/components/memo/Memo.astro +162 -231
  161. package/src/components/memo/ShortNote.astro +6 -6
  162. package/src/components/notation/NotationFormula.astro +5 -1
  163. package/src/components/notation/NotationGlossary.astro +3 -4
  164. package/src/components/notation/NotationLayer.astro +169 -162
  165. package/src/components/notation/NotationMath.astro +10 -1
  166. package/src/components/reference/FloatRefLayer.astro +485 -423
  167. package/src/components/starlight/AboutPanel.astro +5 -4
  168. package/src/components/starlight/CollapsibleSections.astro +207 -93
  169. package/src/components/starlight/DiagramEnhancer.astro +15 -138
  170. package/src/components/starlight/HeadingAnchorEnhancer.astro +193 -1
  171. package/src/components/starlight/KeyedFloatEnhancer.astro +100 -9
  172. package/src/components/starlight/LayoutHeader.astro +298 -19
  173. package/src/components/starlight/LayoutPageSidebar.astro +99 -12
  174. package/src/components/starlight/LayoutPageTitle.astro +120 -0
  175. package/src/components/starlight/LayoutSidebar.astro +229 -11
  176. package/src/components/starlight/LessonExportActions.astro +53 -72
  177. package/src/components/starlight/LessonFooter.astro +26 -4
  178. package/src/components/starlight/section-parts.ts +15 -2
  179. package/src/components/starlight/section-summary.ts +181 -0
  180. package/src/components/table/Table.astro +95 -76
  181. package/src/components/table/TableOverflowExpander.astro +65 -28
  182. package/src/content-config.ts +40 -4
  183. package/src/reference/base-accents.mjs +31 -0
  184. package/src/reference/base-roman-labels.mjs +2 -2
  185. package/src/reference/consistency.ts +176 -5
  186. package/src/reference/delimiter-size.ts +3 -2
  187. package/src/reference/diagrams-validate.ts +17 -1
  188. package/src/reference/equations-validate.ts +10 -5
  189. package/src/reference/equations.mjs +83 -43
  190. package/src/reference/examples-validate.ts +97 -0
  191. package/src/reference/figures-validate.ts +6 -1
  192. package/src/reference/folds-validate.ts +65 -0
  193. package/src/reference/gate-abbreviations.ts +1 -0
  194. package/src/reference/gate-course-rules.ts +134 -0
  195. package/src/reference/gate-heading-length.ts +66 -35
  196. package/src/reference/gate-heading-structure.ts +193 -0
  197. package/src/reference/gate-math-punctuation.ts +381 -0
  198. package/src/reference/gate-math.ts +69 -10
  199. package/src/reference/gate-part-pages.ts +217 -0
  200. package/src/reference/gate-prose-notation.ts +59 -12
  201. package/src/reference/katex-delimiters.mjs +20 -7
  202. package/src/reference/keyed-float-validate.ts +45 -11
  203. package/src/reference/keyed-jsx-floats.mjs +73 -20
  204. package/src/reference/knowledge-checks-validate.ts +1 -1
  205. package/src/reference/knowledge-checks.mjs +9 -4
  206. package/src/reference/lab-math-slot.ts +36 -0
  207. package/src/reference/math-glyphs.mjs +572 -37
  208. package/src/reference/raw-floats-validate.ts +1 -1
  209. package/src/reference/raw-floats.mjs +1 -1
  210. package/src/reference/rehype-heading-anchors.mjs +116 -17
  211. package/src/reference/rehype-table-header-labels.mjs +21 -3
  212. package/src/reference/remark-asides.mjs +180 -0
  213. package/src/reference/remark-memo.mjs +42 -11
  214. package/src/reference/remark-notation.mjs +387 -36
  215. package/src/reference/render-lab-math.ts +16 -31
  216. package/src/reference/sections-validate.ts +81 -0
  217. package/src/reference/sections.mjs +306 -0
  218. package/src/reference/tables-validate.ts +2 -1
  219. package/src/reference/types.ts +17 -0
  220. package/src/reference/unit-words.ts +233 -0
  221. package/src/rules/catalog.ts +1298 -0
  222. package/src/rules/course-rules.ts +456 -0
  223. package/src/rules/in-effect.ts +235 -0
  224. package/src/rules/settings.ts +448 -0
  225. package/src/rules/waivers.ts +249 -0
  226. package/src/session/PreferenceStore.ts +15 -0
  227. package/src/styles/global.css +1467 -163
  228. package/src/styles/surfaces.css +182 -0
  229. package/src/components/hover-panel.ts +0 -339
  230. package/src/components/popup-stack.ts +0 -345
@@ -1,29 +1,30 @@
1
1
  ---
2
2
  /**
3
- * Shared hover/pin panel shell for the notation and citation layers.
3
+ * The shell every explanation card is cloned from: notation, citation,
4
+ * abbreviation and reference cards alike (rule C6 of
5
+ * `docs/plans/hover-card-consistency.md`).
4
6
  *
5
- * This component contributes only the fixed-position `<aside>` container and
6
- * its base styling. The interaction engine — side selection, the sticky-header
7
- * and article-column clamps, pin, Escape, and outside-close — lives once in
8
- * `./hover-panel.ts` and is wired from each layer's island script. The panel's
9
- * inner fields are slotted by the layer that owns them.
7
+ * It renders a `<template>`, so nothing shows until a layer's script clones
8
+ * it with `cloneCardShell` (`./card-manager.ts`) — once per card, which is
9
+ * what lets a layer show several cards at once. A card is an `<aside>` with
10
+ * a header row — a grip, the layer's `heading` slot, then a Side toggle, a
11
+ * Pin toggle and a × — a note line under it, and the layer's own fields in
12
+ * the default slot. The card manager owns the buttons (`data-card-grip`,
13
+ * `data-card-side`, `data-card-pin`, `data-card-close`), the note
14
+ * (`data-card-note`), the mode (`data-card-mode`: hover, pinned, side or
15
+ * moved), the flash (`is-card-flashing`) and where the card goes
16
+ * (`./card-placement.ts`, `./card-side.ts`, `./card-drag.ts`).
10
17
  *
11
- * Extra attributes (e.g. `data-notation-panel`, `data-citation-panel`) are
12
- * forwarded to the `<aside>` so each layer keeps the hook its tests and pin
13
- * controls already reference.
18
+ * Extra attributes (`data-citation-panel`, `data-float-ref-panel`, …) go on
19
+ * every card, so each layer keeps the hook its styles and tests use.
14
20
  *
15
- * `tabindex="-1"`: never in the tab order, but a valid target for
16
- * `panel.focus()`. A layer that lets the reader click deeper into the panel's
17
- * own content (D15's in-panel navigation) needs somewhere stable to move
18
- * focus to before it replaces whatever the reader just clicked — otherwise
19
- * removing the focused node drops focus to nothing, and the shared
20
- * `focusout` handler in `./hover-panel.ts` reads that as "the reader left"
21
- * and closes the panel it was just asked to update.
21
+ * `tabindex="-1"`: never in the tab order, but focusable, so a click inside
22
+ * a card raises it and focus has somewhere stable to go.
22
23
  */
23
24
  export interface Props {
24
- /** Element id — pin controls point `aria-controls` at it. */
25
+ /** The template's id. Each card cloned from it gets `‹id›-‹n›`. */
25
26
  id: string;
26
- /** Accessible name for the region. */
27
+ /** Accessible name for each card, until the layer gives it a specific one. */
27
28
  label: string;
28
29
  class?: string;
29
30
  }
@@ -31,52 +32,100 @@ export interface Props {
31
32
  const { id, label, class: className, ...rest } = Astro.props;
32
33
  ---
33
34
 
34
- <aside
35
- class:list={['hover-panel', className]}
36
- id={id}
37
- role="region"
38
- aria-label={label}
39
- aria-live="polite"
40
- aria-atomic="true"
41
- hidden
42
- tabindex="-1"
43
- {...rest}
44
- >
45
- <button
46
- class="hover-panel-close"
47
- type="button"
48
- data-hover-panel-close
49
- aria-label="Close"
35
+ <template id={id} data-card-template>
36
+ <aside
37
+ class:list={['hover-panel', className]}
38
+ role="region"
39
+ aria-label={label}
40
+ tabindex="-1"
41
+ {...rest}
50
42
  >
51
- <span aria-hidden="true">&times;</span>
52
- </button>
53
- <div class="hover-panel-scroll">
54
- <slot />
55
- </div>
56
- </aside>
43
+ <div class="hover-panel-header">
44
+ <button
45
+ class="hover-panel-grip"
46
+ type="button"
47
+ data-card-grip
48
+ aria-label="Move card"
49
+ title="Drag to move this card. Arrow keys move it; Home puts it back."
50
+ >
51
+ <svg viewBox="0 0 10 16" width="10" height="16" aria-hidden="true">
52
+ <circle cx="3" cy="4" r="1.15"></circle>
53
+ <circle cx="7" cy="4" r="1.15"></circle>
54
+ <circle cx="3" cy="8" r="1.15"></circle>
55
+ <circle cx="7" cy="8" r="1.15"></circle>
56
+ <circle cx="3" cy="12" r="1.15"></circle>
57
+ <circle cx="7" cy="12" r="1.15"></circle>
58
+ </svg>
59
+ </button>
60
+ <div class="hover-panel-heading"><slot name="heading" /></div>
61
+ <div class="hover-panel-tools">
62
+ <button
63
+ class="hover-panel-side"
64
+ type="button"
65
+ data-card-side
66
+ aria-pressed="false"
67
+ aria-label="Side"
68
+ title="Keep this card beside the article"
69
+ >
70
+ <svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
71
+ <rect x="1.75" y="2.75" width="12.5" height="10.5" rx="1.5"></rect>
72
+ <path class="hover-panel-side-column" d="M10.25 2.75v10.5"></path>
73
+ <path class="hover-panel-side-fill" d="M10.25 3.5h3.25v9h-3.25z"></path>
74
+ </svg>
75
+ </button>
76
+ <button
77
+ class="hover-panel-pin"
78
+ type="button"
79
+ data-card-pin
80
+ aria-pressed="false"
81
+ aria-label="Pin"
82
+ title="Keep this card open"
83
+ >
84
+ <svg viewBox="0 0 16 16" width="15" height="15" aria-hidden="true">
85
+ <path
86
+ class="hover-panel-pin-head"
87
+ d="M6 1.75h4v4.25l2.25 2.75h-8.5L6 6z"
88
+ ></path>
89
+ <path d="M8 8.75V14.5"></path>
90
+ </svg>
91
+ </button>
92
+ <button
93
+ class="hover-panel-close"
94
+ type="button"
95
+ data-hover-panel-close
96
+ data-card-close
97
+ aria-label="Close"
98
+ >
99
+ <span aria-hidden="true">&times;</span>
100
+ </button>
101
+ </div>
102
+ </div>
103
+ <p class="hover-panel-note" data-card-note role="status" hidden></p>
104
+ <div class="hover-panel-scroll">
105
+ <slot />
106
+ </div>
107
+ </aside>
108
+ </template>
57
109
 
58
110
  <style>
59
111
  @layer starlight.components {
60
112
  .hover-panel {
61
- position: fixed;
62
- z-index: 100;
63
- /* The panel is an <aside> in the content flow; a stray cascade margin
64
- would offset a position:fixed box from its computed `top`, so the
65
- JS placement (which clears display equations) must start from zero. */
113
+ /* In the card layer, whose origin is the document's: `left`/`top` are
114
+ page coordinates, so the card scrolls with the page (P1). */
115
+ position: absolute;
66
116
  margin: 0;
67
- width: min(23rem, calc(100vw - 1.5rem));
117
+ width: min(var(--explico-card-width, 23rem), calc(100vw - 1.5rem));
68
118
  display: flex;
69
119
  flex-direction: column;
70
- /* The scrolling lives on `.hover-panel-scroll` below, not here — the
71
- close button is an absolutely-positioned sibling of that scroller,
72
- so it stays put when the content scrolls instead of scrolling away
73
- with it (which is what happens to an absolutely-positioned child of
74
- the scroll container itself). `hidden` also keeps the rounded
75
- corners clean around the inner scroller. */
120
+ /* The scrolling lives on `.hover-panel-scroll` below, so the header
121
+ row stays put while a long card scrolls; `hidden` also keeps the
122
+ rounded corners clean around that scroller. */
76
123
  overflow: hidden;
77
- border: 1px solid var(--sl-color-gray-5);
78
- border-top: 0.25rem solid var(--sl-color-accent);
79
- border-radius: 0.65rem;
124
+ /* No accent top rule: the system has none (`surfaces.css`). A floating
125
+ card keeps its overlay shadow — that is what lifts it off the page —
126
+ which is not the accent tier's in-flow `raised` depth. */
127
+ border: var(--ex-edge-border);
128
+ border-radius: var(--ex-radius-meta);
80
129
  color: var(--sl-color-text);
81
130
  background: var(--sl-color-bg);
82
131
  box-shadow: var(--sl-shadow-lg);
@@ -85,41 +134,135 @@ const { id, label, class: className, ...rest } = Astro.props;
85
134
 
86
135
  /* `.hover-panel { display: flex }` above has the same specificity as the
87
136
  UA stylesheet's `[hidden] { display: none }` and comes later in the
88
- cascade, so it would otherwise win and defeat the `hidden` attribute
89
- that every layer's JS relies on to actually hide the panel. */
137
+ cascade, so it would otherwise win and defeat the `hidden` attribute. */
90
138
  .hover-panel[hidden] {
91
139
  display: none;
92
140
  }
93
141
 
94
- /* The equation/table/figure preview card (`FloatRefLayer.astro`) is the
95
- one panel whose content size varies wildly — a short reference vs. a
96
- wide equation — so it grows to fit instead of staying pinned at the
97
- default width. `--float-ref-max-width` is computed in JS from the live
98
- layout (the room between the left sidebar and the viewport edge); the
99
- notation and citation panels never set it and keep the fixed default. */
142
+ /* C6: a kept card shows it, on its border as well as its Pin or Side
143
+ button. */
144
+ .hover-panel:is([data-card-mode='pinned'], [data-card-mode='side'], [data-card-mode='moved']) {
145
+ border-color: var(--sl-color-accent);
146
+ box-shadow:
147
+ var(--sl-shadow-lg),
148
+ 0 0 0 1px var(--sl-color-accent);
149
+ }
150
+
151
+ /* C8: pointing at another occurrence of a kept card's item. */
152
+ .hover-panel.is-card-flashing {
153
+ outline: 3px solid transparent;
154
+ outline-offset: 2px;
155
+ animation: explico-card-flash var(--explico-card-flash, 500ms) ease-out;
156
+ }
157
+
158
+ @keyframes explico-card-flash {
159
+ from {
160
+ outline-color: var(--sl-color-accent);
161
+ }
162
+ to {
163
+ outline-color: transparent;
164
+ }
165
+ }
166
+
167
+ @media (prefers-reduced-motion: reduce) {
168
+ .hover-panel.is-card-flashing {
169
+ animation: none;
170
+ outline-color: var(--sl-color-accent);
171
+ }
172
+ }
173
+
174
+ /* P5: a reference card fits its content, a short reference or a wide
175
+ equation, up to the cap; wider content scrolls inside it. */
100
176
  .hover-panel[data-float-ref-panel] {
101
177
  width: fit-content;
102
- min-width: min(23rem, var(--float-ref-max-width, 100vw));
103
- max-width: var(--float-ref-max-width, min(23rem, calc(100vw - 1.5rem)));
178
+ min-width: min(var(--explico-card-width, 23rem), calc(100vw - 1.5rem));
179
+ max-width: min(
180
+ var(--explico-card-reference-max-width, 80ch),
181
+ calc(100vw - 1.5rem)
182
+ );
104
183
  }
105
184
 
106
- .hover-panel-scroll {
107
- overflow: auto;
108
- /* Without these, this flex item's default `auto` minimum size is its
109
- *content's* size, not the panel's — content wider or taller than the
110
- panel would inflate the panel itself outward instead of scrolling
111
- inside it (the same flexbox trap `.float-ref-panel-content` guards
112
- against with its own `min-width: 0`). */
185
+ /* S1, S8: a docked card takes the side column's width, whatever its
186
+ layer: a wide reference wraps or scrolls inside rather than reaching
187
+ onto the rail. The manager caps its height. */
188
+ .hover-panel[data-card-mode='side'] {
189
+ width: var(--explico-card-side-width, var(--explico-card-width, 23rem));
113
190
  min-width: 0;
114
- min-height: 0;
115
- padding: 1rem;
116
- padding-inline-end: 2.4rem;
191
+ max-width: none;
117
192
  }
118
193
 
119
- .hover-panel-close {
194
+ /* S6: a docked card keeps × and its Side toggle; Side brings it back. A
195
+ moved card is kept too: Home, or a drop near its old spot, brings it
196
+ back (D5, D6). */
197
+ .hover-panel:is([data-card-mode='side'], [data-card-mode='moved']) .hover-panel-pin {
198
+ display: none;
199
+ }
200
+
201
+ .hover-panel-header {
202
+ position: relative;
203
+ display: flex;
204
+ align-items: flex-start;
205
+ gap: 0.5rem;
206
+ /* Logical, so the grip's margin is at the start in either direction. */
207
+ padding-block: 0.5rem 0;
208
+ padding-inline: 1.75rem 0.5rem;
209
+ }
210
+
211
+ /* D1: the grip, in the header's start margin. The only drag handle: the
212
+ rest of the card stays selectable, and only the grip turns off touch
213
+ panning. */
214
+ .hover-panel-grip {
120
215
  position: absolute;
121
- top: 0.5rem;
122
- right: 0.5rem;
216
+ inset-block-start: 0.5rem;
217
+ inset-inline-start: 0.35rem;
218
+ width: 1.1rem;
219
+ height: 1.6rem;
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: center;
223
+ padding: 0;
224
+ border: 0;
225
+ border-radius: 0.35rem;
226
+ color: var(--sl-color-gray-3);
227
+ background: transparent;
228
+ cursor: grab;
229
+ touch-action: none;
230
+ user-select: none;
231
+ -webkit-user-select: none;
232
+ }
233
+
234
+ .hover-panel-grip svg {
235
+ fill: currentColor;
236
+ }
237
+
238
+ .hover-panel-grip:hover,
239
+ .hover-panel[data-card-dragged] .hover-panel-grip {
240
+ color: var(--sl-color-text);
241
+ background: var(--sl-color-gray-6);
242
+ }
243
+
244
+ .hover-panel[data-card-dragged] {
245
+ box-shadow:
246
+ var(--sl-shadow-lg),
247
+ 0 0 0 1px var(--sl-color-accent);
248
+ }
249
+
250
+ .hover-panel-heading {
251
+ flex: 1;
252
+ min-width: 0;
253
+ padding-block-start: 0.2rem;
254
+ }
255
+
256
+ .hover-panel-tools {
257
+ flex: none;
258
+ display: flex;
259
+ align-items: center;
260
+ gap: 0.15rem;
261
+ }
262
+
263
+ .hover-panel-side,
264
+ .hover-panel-pin,
265
+ .hover-panel-close {
123
266
  width: 1.6rem;
124
267
  height: 1.6rem;
125
268
  display: flex;
@@ -130,21 +273,230 @@ const { id, label, class: className, ...rest } = Astro.props;
130
273
  border-radius: 0.35rem;
131
274
  color: var(--sl-color-gray-3);
132
275
  background: transparent;
276
+ cursor: pointer;
277
+ }
278
+
279
+ .hover-panel-close {
133
280
  font-size: 1.15rem;
134
281
  line-height: 1;
135
- cursor: pointer;
136
282
  }
137
283
 
284
+ .hover-panel-side:hover,
285
+ .hover-panel-pin:hover,
138
286
  .hover-panel-close:hover {
139
287
  color: var(--sl-color-text);
140
288
  background: var(--sl-color-gray-6);
141
289
  }
142
290
 
291
+ .hover-panel-side svg,
292
+ .hover-panel-pin svg {
293
+ fill: none;
294
+ stroke: currentColor;
295
+ stroke-width: 1.4;
296
+ stroke-linecap: round;
297
+ stroke-linejoin: round;
298
+ }
299
+
300
+ .hover-panel-side[aria-pressed='true'],
301
+ .hover-panel-pin[aria-pressed='true'] {
302
+ color: var(--sl-color-text-accent);
303
+ background: var(--sl-color-accent-low);
304
+ }
305
+
306
+ .hover-panel-pin[aria-pressed='true'] .hover-panel-pin-head {
307
+ fill: currentColor;
308
+ }
309
+
310
+ .hover-panel-side-fill {
311
+ stroke: none;
312
+ }
313
+
314
+ .hover-panel-side[aria-pressed='true'] .hover-panel-side-fill {
315
+ fill: currentColor;
316
+ }
317
+
318
+ /* S7: below 72rem there is never a side column, so no Side button. The
319
+ side column is laid out left to right only. */
320
+ @media not all and (min-width: 72rem) {
321
+ .hover-panel-side {
322
+ display: none;
323
+ }
324
+ }
325
+
326
+ :global([dir='rtl']) .hover-panel-side {
327
+ display: none;
328
+ }
329
+
330
+ /* S7: "Collapse a side panel to make room", under the header row. */
331
+ .hover-panel-note {
332
+ margin: 0.35rem 1rem 0;
333
+ padding: 0.25rem 0.5rem;
334
+ border-radius: 0.35rem;
335
+ font-size: var(--sl-text-xs);
336
+ color: var(--sl-color-text);
337
+ background: var(--sl-color-gray-6);
338
+ }
339
+
340
+ .hover-panel-note[hidden] {
341
+ display: none;
342
+ }
343
+
344
+ .hover-panel-scroll {
345
+ overflow: auto;
346
+ /* Without these, this flex item's default `auto` minimum size is its
347
+ *content's* size, not the panel's — content wider or taller than the
348
+ panel would inflate the panel itself outward instead of scrolling
349
+ inside it (the same flexbox trap `.float-ref-panel-content` guards
350
+ against with its own `min-width: 0`). */
351
+ min-width: 0;
352
+ min-height: 0;
353
+ padding: 0.35rem 1rem 1rem;
354
+ }
355
+
143
356
  /* Slotted fields carry the owning layer's scope, not this component's, so
144
357
  the descendant match must be global. */
145
358
  .hover-panel :global(:focus-visible) {
146
359
  outline: 3px solid var(--sl-color-accent);
147
360
  outline-offset: 2px;
148
361
  }
362
+
363
+ @media (forced-colors: active) {
364
+ .hover-panel:is([data-card-mode='pinned'], [data-card-mode='side'], [data-card-mode='moved']) {
365
+ border-color: Highlight;
366
+ }
367
+ }
368
+ }
369
+
370
+ /* D1: while a card is dragged, nothing on the page is selected and the
371
+ pointer shows the grab everywhere. */
372
+ :global(html[data-card-dragging]),
373
+ :global(html[data-card-dragging] *) {
374
+ cursor: grabbing !important;
375
+ user-select: none !important;
376
+ -webkit-user-select: none !important;
377
+ }
378
+
379
+ /* D3: the docking area's tint from a drag's first movement; once the card
380
+ snaps, a dashed line on the article's edge, the dashed outline of where
381
+ it lands, and a label (`../card-drag.ts`). Fixed to the window at the
382
+ bottom of the card layer: over the article, under every card. */
383
+ :global(.explico-card-dock) {
384
+ position: fixed;
385
+ inset: 0;
386
+ z-index: 0;
387
+ pointer-events: none;
388
+ }
389
+
390
+ :global(.explico-card-dock [hidden]) {
391
+ display: none;
392
+ }
393
+
394
+ :global(.explico-card-dock-area) {
395
+ position: fixed;
396
+ bottom: 0;
397
+ background: color-mix(in srgb, var(--sl-color-accent) 6%, transparent);
398
+ }
399
+
400
+ :global(.explico-card-dock-edge) {
401
+ position: fixed;
402
+ bottom: 0;
403
+ width: 0;
404
+ border-inline-start: 2px dashed var(--sl-color-accent);
405
+ transform: translateX(-1px);
406
+ }
407
+
408
+ :global(.explico-card-dock-outline) {
409
+ position: fixed;
410
+ box-sizing: border-box;
411
+ border: 2px dashed var(--sl-color-accent);
412
+ border-radius: var(--ex-radius-meta);
413
+ background: color-mix(in srgb, var(--sl-color-accent) 10%, transparent);
414
+ }
415
+
416
+ :global(.explico-card-dock-label) {
417
+ position: fixed;
418
+ transform: translateX(-50%);
419
+ padding: 0.2rem 0.75rem;
420
+ border: 1px solid var(--sl-color-accent);
421
+ border-radius: 999px;
422
+ font-size: var(--sl-text-xs);
423
+ line-height: 1.4;
424
+ white-space: nowrap;
425
+ color: var(--sl-color-text-accent);
426
+ background: var(--sl-color-bg);
427
+ box-shadow: var(--sl-shadow-sm);
428
+ }
429
+
430
+ @media (forced-colors: active) {
431
+ :global(.explico-card-dock-area),
432
+ :global(.explico-card-dock-outline) {
433
+ background: transparent;
434
+ }
435
+
436
+ :global(.explico-card-dock-edge),
437
+ :global(.explico-card-dock-outline),
438
+ :global(.explico-card-dock-label) {
439
+ border-color: Highlight;
440
+ }
441
+ }
442
+
443
+ @media print {
444
+ :global(.explico-card-dock) {
445
+ display: none;
446
+ }
447
+ }
448
+
449
+ /* S5: the arrow from a kept card to an occurrence of its item
450
+ (`../card-arrow.ts`), at the bottom of the card layer. */
451
+ :global(.explico-card-arrow) {
452
+ transition: opacity var(--explico-card-motion, 100ms) ease-out;
453
+ }
454
+
455
+ :global(.explico-card-arrow.is-fading) {
456
+ opacity: 0;
457
+ }
458
+
459
+ :global(.explico-card-arrow-line) {
460
+ fill: none;
461
+ stroke: var(--sl-color-accent);
462
+ stroke-width: 1.75;
463
+ stroke-linecap: round;
464
+ }
465
+
466
+ :global(.explico-card-arrow-head) {
467
+ fill: var(--sl-color-accent);
468
+ }
469
+
470
+ @media (prefers-reduced-motion: reduce) {
471
+ :global(.explico-card-arrow) {
472
+ transition: none;
473
+ }
474
+ }
475
+
476
+ @media (forced-colors: active) {
477
+ :global(.explico-card-arrow-line) {
478
+ stroke: Highlight;
479
+ }
480
+
481
+ :global(.explico-card-arrow-head) {
482
+ fill: Highlight;
483
+ }
484
+ }
485
+
486
+ @media print {
487
+ :global(.explico-card-arrow) {
488
+ display: none;
489
+ }
490
+ }
491
+
492
+ /* The open mobile menu covers the page; the cards above it would float
493
+ over the menu. */
494
+ :global(body[data-mobile-menu-expanded] .explico-card-layer) {
495
+ display: none;
496
+ }
497
+
498
+ /* Escape can hand focus back to the article (C10); it needs no ring. */
499
+ :global(main[data-card-focus-return]:focus) {
500
+ outline: none;
149
501
  }
150
502
  </style>
@@ -0,0 +1,27 @@
1
+ ---
2
+ /**
3
+ * The paragraph on a part's overview page that says how the earlier parts
4
+ * lead into this one — which results it reuses, and what they now make
5
+ * possible. Rule S2 requires one on every part after the first, placed before
6
+ * `<PartScope>`; `gate-part-pages.ts` checks that it holds one paragraph within
7
+ * the course's `partPages.bridge` word range.
8
+ *
9
+ * Usage, in `content/docs/<part>/index.mdx`:
10
+ *
11
+ * ```mdx
12
+ * import PartBridge from 'explico/components/PartBridge.astro';
13
+ *
14
+ * <PartBridge>
15
+ *
16
+ * Part 1 gave the position of a point and, for a constant acceleration, its
17
+ * velocity and position at any later time. …
18
+ *
19
+ * </PartBridge>
20
+ * ```
21
+ *
22
+ * Keep a blank line inside each tag, so the paragraph is parsed as Markdown
23
+ * and its math and `[[key]]` references render.
24
+ */
25
+ ---
26
+
27
+ <div class="part-intro part-bridge" data-part-intro="bridge"><slot /></div>