mdeck 3.7.1 → 3.8.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 (43) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +3 -3
  3. package/assets/base.css +9 -5
  4. package/assets/extensions/themes/academic/styles.css +22 -22
  5. package/assets/extensions/themes/glass/styles.css +17 -17
  6. package/assets/extensions/themes/minimal/styles.css +14 -14
  7. package/assets/extensions/themes/neue/styles.css +14 -14
  8. package/assets/extensions/themes/plain/styles.css +17 -17
  9. package/assets/extensions/themes/work/styles.css +26 -26
  10. package/docs/reference/authoring.md +12 -0
  11. package/docs/site/content/drawing.md +1 -1
  12. package/docs/site/content/presenting.md +45 -0
  13. package/examples/python/slides.de.md +493 -0
  14. package/examples/python/{slides.md → slides.en.md} +1 -1
  15. package/examples/python/slides.fa.md +492 -0
  16. package/examples/python/slides.hi.md +492 -0
  17. package/examples/showcase/slides.md +33 -0
  18. package/package.json +1 -1
  19. package/skills/write-slides/SKILL.md +1 -0
  20. package/src/build/config.js +1 -1
  21. package/src/build/slidesPlugin.js +34 -4
  22. package/src/components/callout.css +10 -10
  23. package/src/components/citation.css +2 -2
  24. package/src/components/code-block.css +3 -3
  25. package/src/components/poll.css +6 -6
  26. package/src/components/video-player.css +1 -1
  27. package/src/core/editDeck.js +3 -2
  28. package/src/core/icons.js +1 -0
  29. package/src/core/languages.js +51 -0
  30. package/src/core/parseSlides.js +15 -3
  31. package/src/core/validateDeck.js +5 -0
  32. package/src/editor/components/DeckSettings.jsx +4 -0
  33. package/src/editor/components/MetaFields.jsx +7 -0
  34. package/src/layouts/layoutApi.jsx +7 -1
  35. package/src/live/answer/answer.css +2 -2
  36. package/src/runtime/chrome.jsx +6 -7
  37. package/src/runtime/deck-stage.js +249 -11
  38. package/src/runtime/hotspots.js +98 -0
  39. package/src/runtime/ink/bus.js +12 -1
  40. package/src/runtime/ink/room.js +20 -8
  41. package/src/runtime/main.jsx +152 -22
  42. package/src/runtime/zoom/camera.js +77 -0
  43. /package/examples/python/{slides.drawings.json → slides.en.drawings.json} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.8.0 — 2026-10-11
4
+
5
+ - Hotspots: with `hotspots: auto` in the deck's settings, the presenter view puts a numbered key on each picture, code block, table, formula, video, callout, column and poll of the slide, and **1**–**9** zoom smoothly until that part fills the screen, keeping the slide around a part of another shape in view. The audience window, a paired iPad and phones zoom along; only the presenter view shows the keys, which can also be tapped. The same number, **0**, **Escape**, a tap on the slide or the next point or slide show the whole slide again. `hotspots: marked` keys only parts marked `data-hotspot`; a slide can set its own (`hotspots: false`), and **H** or the presenter view's new button turns hotspots on or off during the talk. Without hotspots, the default, **1**–**9** still go to slides 1–9. The editor has a **Hotspots** choice in the deck's settings and in each slide's details, and the tour deck a slide to try it on.
6
+ - A talk in several languages is one file per language, side by side and named for it: `talk.en.md`, `talk.de.md`, `talk.hi.md`. `mdeck run` finds them and the presenter view gets a **Language** switch (**L** for the next language): the slides, the notes and mdeck's own words change in every window, the audience window, a paired iPad and phones following the talk, at the same slide and step. A file named this way needs no `lang`. A deck in one language shows no switch.
7
+ - A deck in a language written from right to left (`lang: fa`, `ar`, `he` …) runs its slides and notes from right to left in every theme; code, maths and mdeck's controls stay left to right. The Python example comes in German, Hindi and Farsi too.
8
+ - The presenter view calls the light and dark switch **Mode**.
9
+ - The presenter view's next-slide preview keeps the language shown after the last slide or a reload, instead of going back to the file's.
10
+ - The presenter view shows a palette as the theme gallery does: one chip of its background and two accents, in front of its name.
11
+
3
12
  ## 3.7.1 — 2026-10-09
4
13
 
5
14
  - A video file on a slide (`<videoplayer src="…" />`) follows the presenter view, on the laptop or a paired iPad: play, pause and a jump there do the same in the audience window, which plays the sound while the presenter view's copy stays silent. This works without a server too, in a built folder. An audience window that nobody has clicked yet plays silently and offers **Click for sound** (German: **Klicken für Ton**). Online videos from YouTube, Vimeo or SwitchTube still play only where they are started; the iPad guide says so.
package/README.md CHANGED
@@ -160,7 +160,7 @@ mdeck send talk.md # one file to email, with a PDF inside
160
160
  - **Layouts:** title, chapter, big statement, image and text, split, full-bleed image, and plain content slides, with points that appear one at a time.
161
161
  - **Looks:** six built-in themes and six colour palettes, each light or dark, changeable without touching the slides. Install more from the [theme repository](https://gh.tschieber.de/mdeck-themes/) with `mdeck themes install`, or make your own as small `extension.toml` folders beside the deck.
162
162
  - **One launch page:** `mdeck run` opens a page with a live preview, the presenter and audience views, the deck and reader views, the editor, the guides, one-click builds and PDF, the deck's check results, and for decks with a server its health and the presenter code.
163
- - **Presenting:** a presenter view with notes and timer, and an audience window that stays in sync.
163
+ - **Presenting:** a presenter view with notes and timer, and an audience window that stays in sync. With `hotspots: auto`, the number keys zoom smoothly into a slide's pictures, code and tables, and the audience window zooms along.
164
164
  - **Drawing on slides:** pen with pressure, highlighter and a laser pointer, with a mouse, a finger or an iPad pencil (`D`). Drawings are saved in `<deck>.drawings.json` beside the deck and appear in every view, build and PDF. An iPad can present on its own, or pair with the laptop through a QR code on the launch page while the laptop's audience window follows it.
165
165
  - **Audience questions:** `<poll room="lunch" options="A|B|C" />` shows live results and a QR code; people vote on their phones. `<scale>`, `<wordcloud>` and `<question>` ask for a rating, words or open answers, and `<qrcode join />` shows the join code once for all of them. Rooms run inside `mdeck run --network` or on a small server (`mdeck server`).
166
166
  - **Sharing:** a reader view with an outline, a phone-friendly Read mode and a PDF download; speaker notes are stripped from shared builds, and interactive slides appear in their finished state.
@@ -188,8 +188,8 @@ complete folder.
188
188
 
189
189
  | Example | Theme | What it demonstrates |
190
190
  |---|---|---|
191
- | [Tour](examples/showcase/slides.md) | Glass | Start here: each slide shows the Markdown beside what it becomes, from headings to layouts, live code, notes, drawing, a poll and sharing |
192
- | [Python](examples/python/slides.md) | Academic | A real lesson: live code to try out, points revealed step by step, notes on every slide, a poll to check understanding |
191
+ | [Tour](examples/showcase/slides.md) | Glass | Start here: each slide shows the Markdown beside what it becomes, from headings to layouts, live code, notes, drawing, zooming into a part, a poll and sharing |
192
+ | [Python](examples/python/slides.en.md) | Academic | A real lesson: live code to try out, points revealed step by step, notes on every slide, a poll to check understanding; in English, [German](examples/python/slides.de.md), [Hindi](examples/python/slides.hi.md) and [Farsi](examples/python/slides.fa.md), switched in the presenter view |
193
193
  | [Poll](examples/poll/slides.md) | Neue | A join slide, then a poll, a scale, a word cloud and open questions; start it with `mdeck run slides.md --network` |
194
194
  | [Custom layouts](examples/custom-layouts/slides.md) | Neue | A deck-local comparison design and named regions |
195
195
 
package/assets/base.css CHANGED
@@ -160,7 +160,7 @@ deck-stage[data-ink-hidden] .slide-ink { display: none; }
160
160
  padding-top: 20px;
161
161
  margin-top: auto;
162
162
  }
163
- .slide-footnotes ol { margin: 0; padding-left: 1.5em; display: flex; flex-direction: column; gap: 4px; }
163
+ .slide-footnotes ol { margin: 0; padding-inline-start: 1.5em; display: flex; flex-direction: column; gap: 4px; }
164
164
  .slide-footnotes li { line-height: 1.4; }
165
165
  .slide-footnotes p { margin: 0; }
166
166
  .slide-footnotes .footnote-backref { display: none; }
@@ -171,8 +171,8 @@ deck-stage[data-ink-hidden] .slide-ink { display: none; }
171
171
  :where(.slide) a { color: var(--accent); text-underline-offset: 0.15em; text-decoration-thickness: 0.06em; }
172
172
  :where(.slide) blockquote {
173
173
  margin: 0 0 var(--gap-item);
174
- padding-left: 0.9em;
175
- border-left: 4px solid var(--accent);
174
+ padding-inline-start: 0.9em;
175
+ border-inline-start: 4px solid var(--accent);
176
176
  color: var(--ink-soft);
177
177
  }
178
178
  :where(.slide) blockquote > p:last-child { margin-bottom: 0; }
@@ -182,10 +182,14 @@ deck-stage[data-ink-hidden] .slide-ink { display: none; }
182
182
 
183
183
  /* ── Code blocks ─────────────────────────────────────────────────────────── */
184
184
  .code-block { white-space: pre-wrap; overflow-x: hidden; }
185
+ /* Code and maths read from left to right, also on a right-to-left slide. */
186
+ .slide[dir="rtl"] :is(pre, code, kbd, samp, .katex, .code-block-wrapper) { direction: ltr; unicode-bidi: isolate; }
187
+ /* A bullet that points along the line points the other way. */
188
+ .slide[dir="rtl"] .slide-body ul > li::before { scale: -1 1; }
185
189
 
186
190
  /* ── Pictures written in the text ───────────────────────────────────────── */
187
191
  /* A paragraph of nothing but pictures (marked in markedSetup.js) fits into
188
- the room the slide has left: a large picture shrinks, keeping its
192
+ the room the slide has inset-inline-start: a large picture shrinks, keeping its
189
193
  proportions, and never runs off the slide; a small one keeps its size.
190
194
  Several sit side by side. Themes may set them differently (a grid, cropped
191
195
  to fill); a picture in a sentence is left alone. */
@@ -215,7 +219,7 @@ deck-stage[data-ink-hidden] .slide-ink { display: none; }
215
219
  }
216
220
  .slide-body th,
217
221
  .slide-body td {
218
- text-align: left;
222
+ text-align: start;
219
223
  padding: 12px 16px;
220
224
  border-bottom: 1px solid var(--rule);
221
225
  }
@@ -41,7 +41,7 @@
41
41
  .slide-logo {
42
42
  position: absolute;
43
43
  top: calc(var(--pad-y) - 20px);
44
- right: var(--pad-x);
44
+ inset-inline-end: var(--pad-x);
45
45
  height: 72px;
46
46
  width: auto;
47
47
  max-width: 320px;
@@ -183,12 +183,12 @@ strong { color: var(--ink); font-weight: 700; }
183
183
  .slide-body ul > li,
184
184
  .slide-body ol > li {
185
185
  line-height: 1.45;
186
- padding-left: 44px;
186
+ padding-inline-start: 44px;
187
187
  }
188
188
  .slide-body ul > li::before {
189
189
  content: '';
190
190
  position: absolute;
191
- left: 4px;
191
+ inset-inline-start: 4px;
192
192
  top: 0.5em;
193
193
  width: 0.42em;
194
194
  height: 0.5em;
@@ -198,7 +198,7 @@ strong { color: var(--ink); font-weight: 700; }
198
198
  .slide-body ol > li::before {
199
199
  content: counter(slide-ol) '.';
200
200
  position: absolute;
201
- left: 0;
201
+ inset-inline-start: 0;
202
202
  top: 0;
203
203
  font-weight: 700;
204
204
  color: var(--accent);
@@ -259,11 +259,11 @@ strong { color: var(--ink); font-weight: 700; }
259
259
  grid-template-columns: 1.2fr 1fr;
260
260
  column-gap: 96px;
261
261
  align-items: center;
262
- text-align: left;
262
+ text-align: start;
263
263
  }
264
264
  .slide--title.has-image .title-text { align-items: flex-start; }
265
265
  .slide--title.has-image .display { font-size: calc(var(--fs-display) * 0.82); }
266
- .slide--title.has-image .display::after { margin-left: 0; }
266
+ .slide--title.has-image .display::after { margin-inline-start: 0; }
267
267
  .slide--title.has-image .title-image { width: 100%; height: 100%; max-height: 720px; object-fit: contain; }
268
268
  .slide--title.has-image .slide-footer { justify-content: flex-start; }
269
269
 
@@ -291,8 +291,8 @@ strong { color: var(--ink); font-weight: 700; }
291
291
  line-height: 0.9;
292
292
  letter-spacing: -0.04em;
293
293
  color: var(--accent);
294
- padding-right: 56px;
295
- border-right: 4px solid var(--accent);
294
+ padding-inline-end: 56px;
295
+ border-inline-end: 4px solid var(--accent);
296
296
  font-variant-numeric: lining-nums;
297
297
  user-select: none;
298
298
  }
@@ -349,9 +349,9 @@ strong { color: var(--ink); font-weight: 700; }
349
349
  }
350
350
  .slide--focus .slide-body > * {
351
351
  background: var(--accent-soft);
352
- border-left: 8px solid var(--accent);
353
- padding-left: 64px;
354
- padding-right: 80px;
352
+ border-inline-start: 8px solid var(--accent);
353
+ padding-inline-start: 64px;
354
+ padding-inline-end: 80px;
355
355
  }
356
356
  .slide--focus .slide-body > :first-child { padding-top: 48px; }
357
357
  .slide--focus .slide-body > :last-child { padding-bottom: 48px; }
@@ -384,7 +384,7 @@ strong { color: var(--ink); font-weight: 700; }
384
384
  font-size: var(--fs-small);
385
385
  font-weight: 600;
386
386
  color: var(--muted);
387
- text-align: right;
387
+ text-align: end;
388
388
  padding-top: 28px;
389
389
  }
390
390
 
@@ -452,7 +452,7 @@ strong { color: var(--ink); font-weight: 700; }
452
452
  --block: var(--muted);
453
453
  background: color-mix(in oklab, var(--block) 7%, var(--bg));
454
454
  border: 0;
455
- border-left: 6px solid var(--block);
455
+ border-inline-start: 6px solid var(--block);
456
456
  border-radius: 0 4px 4px 0;
457
457
  padding: 0;
458
458
  margin: var(--gap-item) 0;
@@ -488,7 +488,7 @@ strong { color: var(--ink); font-weight: 700; }
488
488
  /* Examples and remarks: no fill, the label in small capitals */
489
489
  .slide-body :is(.callout-example, .callout-remark) {
490
490
  background: none;
491
- border-left-width: 3px;
491
+ border-inline-start-width: 3px;
492
492
  }
493
493
  .slide-body :is(.callout-example, .callout-remark) .callout-title {
494
494
  background: none;
@@ -509,10 +509,10 @@ strong { color: var(--ink); font-weight: 700; }
509
509
  }
510
510
  .slide-body .callout.callout-proof > * { padding: 0; }
511
511
  .slide-body .callout.callout-proof .callout-title {
512
- float: left;
512
+ float: inline-start;
513
513
  background: none;
514
514
  padding: 0;
515
- margin-right: 0.35em;
515
+ margin-inline-end: 0.35em;
516
516
  font-family: var(--font-body);
517
517
  font-size: var(--fs-body);
518
518
  font-style: italic;
@@ -522,11 +522,11 @@ strong { color: var(--ink); font-weight: 700; }
522
522
  }
523
523
  .slide-body .callout.callout-proof .callout-title::after { content: '.'; }
524
524
  .slide-body .callout.callout-proof > .callout-title + * { margin-top: 0; }
525
- .slide-body .callout.callout-proof p { padding-left: 0; color: var(--ink-soft); }
525
+ .slide-body .callout.callout-proof p { padding-inline-start: 0; color: var(--ink-soft); }
526
526
  .slide-body .callout.callout-proof > :last-child { margin-bottom: 0; }
527
527
  .slide-body .callout.callout-proof > :last-child::after {
528
528
  content: '\220E';
529
- margin-left: 0.6em;
529
+ margin-inline-start: 0.6em;
530
530
  color: var(--ink);
531
531
  }
532
532
 
@@ -545,7 +545,7 @@ strong { color: var(--ink); font-weight: 700; }
545
545
  }
546
546
  .slide-body th,
547
547
  .slide-body td {
548
- padding: 10px 28px 10px 0;
548
+ padding-block: 10px; padding-inline: 0 28px;
549
549
  border: 0;
550
550
  }
551
551
  .slide-body th {
@@ -570,7 +570,7 @@ strong { color: var(--ink); font-weight: 700; }
570
570
  content: '';
571
571
  position: absolute;
572
572
  top: 0;
573
- left: 0;
573
+ inset-inline-start: 0;
574
574
  width: 280px;
575
575
  height: 1px;
576
576
  background: var(--ink-soft);
@@ -587,7 +587,7 @@ strong { color: var(--ink); font-weight: 700; }
587
587
  content: '';
588
588
  position: absolute;
589
589
  top: 0;
590
- left: 0;
590
+ inset-inline-start: 0;
591
591
  width: 280px;
592
592
  height: 1px;
593
593
  background: var(--ink-soft);
@@ -602,7 +602,7 @@ strong { color: var(--ink); font-weight: 700; }
602
602
  --code-size: 24px;
603
603
  background: var(--code-bg);
604
604
  border-radius: 4px;
605
- border-left: 4px solid var(--hairline);
605
+ border-inline-start: 4px solid var(--hairline);
606
606
  padding: 24px 32px;
607
607
  margin: 0;
608
608
  overflow: hidden;
@@ -152,7 +152,7 @@
152
152
  .slide-logo {
153
153
  position: absolute;
154
154
  top: var(--pad-y);
155
- right: var(--pad-x);
155
+ inset-inline-end: var(--pad-x);
156
156
  height: 80px;
157
157
  width: auto;
158
158
  max-width: 320px;
@@ -221,7 +221,7 @@ em { font-style: normal; font-weight: 600; color: var(--em); }
221
221
  background-clip: text;
222
222
  -webkit-text-fill-color: transparent;
223
223
  color: var(--accent);
224
- padding-right: 0.04em;
224
+ padding-inline-end: 0.04em;
225
225
  }
226
226
  strong { font-weight: 650; color: var(--ink); }
227
227
 
@@ -284,28 +284,28 @@ strong { font-weight: 650; color: var(--ink); }
284
284
  inset 0 0 0 1px color-mix(in oklab, var(--tint) 42%, transparent),
285
285
  0 3px 8px -3px color-mix(in oklab, var(--lo) 45%, transparent);
286
286
  }
287
- .slide-body ul > li { line-height: 1.38; padding-left: 48px; }
287
+ .slide-body ul > li { line-height: 1.38; padding-inline-start: 48px; }
288
288
  .slide-body ul > li::before {
289
289
  content: '';
290
290
  position: absolute;
291
- left: 0;
291
+ inset-inline-start: 0;
292
292
  top: calc(0.69em - 11px);
293
293
  width: 22px;
294
294
  height: 22px;
295
295
  }
296
296
  /* A point inside a point: a smaller bead in the second accent. */
297
- .slide-body li ul > li { padding-left: 38px; }
297
+ .slide-body li ul > li { padding-inline-start: 38px; }
298
298
  .slide-body li ul > li::before {
299
299
  --tint: var(--accent-2);
300
300
  width: 14px;
301
301
  height: 14px;
302
302
  top: calc(0.69em - 7px);
303
303
  }
304
- .slide-body ol > li { line-height: 1.38; padding-left: 66px; }
304
+ .slide-body ol > li { line-height: 1.38; padding-inline-start: 66px; }
305
305
  .slide-body ol > li::before {
306
306
  content: counter(slide-ol);
307
307
  position: absolute;
308
- left: 0;
308
+ inset-inline-start: 0;
309
309
  top: calc(0.69em - 20px);
310
310
  width: 44px;
311
311
  height: 44px;
@@ -351,7 +351,7 @@ strong { font-weight: 650; color: var(--ink); }
351
351
  grid-template-columns: 1.05fr 1fr;
352
352
  column-gap: 72px;
353
353
  align-items: center;
354
- text-align: left;
354
+ text-align: start;
355
355
  padding: 13px;
356
356
  }
357
357
  .slide--title.has-image .title-text {
@@ -395,7 +395,7 @@ strong { font-weight: 650; color: var(--ink); }
395
395
  content: '';
396
396
  position: absolute;
397
397
  z-index: -1;
398
- left: calc(var(--disc) * 0.3);
398
+ inset-inline-start: calc(var(--disc) * 0.3);
399
399
  top: calc(50% - var(--disc) * 0.95);
400
400
  width: calc(var(--disc) * 1.3);
401
401
  aspect-ratio: 1;
@@ -457,7 +457,7 @@ strong { font-weight: 650; color: var(--ink); }
457
457
  }
458
458
  .slide--chapter.has-image .chapter-content { --disc: 210px; align-self: center; }
459
459
  .slide--chapter.has-image .chapter-content:has(> .chapter-num) { display: flex; flex-direction: column; align-items: flex-start; }
460
- .slide--chapter.has-image .chapter-content:has(> .chapter-num)::before { top: calc(var(--disc) * -0.45); left: calc(var(--disc) * 0.3); }
460
+ .slide--chapter.has-image .chapter-content:has(> .chapter-num)::before { top: calc(var(--disc) * -0.45); inset-inline-start: calc(var(--disc) * 0.3); }
461
461
  .slide--chapter.has-image .chapter-num { align-self: flex-start; margin-bottom: 44px; }
462
462
  .slide--chapter.has-image .chapter-title { font-size: calc(var(--fs-title) * 0.78); }
463
463
  .slide--chapter.has-image .chapter-image {
@@ -482,7 +482,7 @@ strong { font-weight: 650; color: var(--ink); }
482
482
  display: inline-flex;
483
483
  align-items: center;
484
484
  gap: 12px;
485
- padding: 11px 28px 11px 22px;
485
+ padding-block: 11px; padding-inline: 22px 28px;
486
486
  border-radius: 999px;
487
487
  font-family: var(--font-body);
488
488
  font-size: var(--fs-eyebrow);
@@ -639,7 +639,7 @@ deck-stage[data-deck-static] .slide { animation: none; }
639
639
  background: currentColor;
640
640
  box-shadow: 0 0 10px currentColor;
641
641
  }
642
- .slide-body .callout p { padding-left: 0; margin: 0; color: var(--ink); }
642
+ .slide-body .callout p { padding-inline-start: 0; margin: 0; color: var(--ink); }
643
643
  .slide-body :is(.callout-note, .callout-tip, .callout-important) { --tint: var(--accent); }
644
644
  .slide-body :is(.callout-warning, .callout-caution) { --tint: var(--accent-3); }
645
645
  .slide-body .callout-definition { --tint: var(--accent-2); }
@@ -676,8 +676,8 @@ deck-stage[data-deck-static] .slide { animation: none; }
676
676
  border-bottom: 1.5px solid color-mix(in oklab, var(--ink) 40%, transparent);
677
677
  background: color-mix(in oklab, var(--hi) 7%, transparent);
678
678
  }
679
- .slide-body th:first-child { border-top-left-radius: 16px; }
680
- .slide-body th:last-child { border-top-right-radius: 16px; }
679
+ .slide-body th:first-child { border-start-start-radius: 16px; }
680
+ .slide-body th:last-child { border-start-end-radius: 16px; }
681
681
  .slide-body td { border-bottom: 1px solid var(--hairline); }
682
682
  .slide-body tr:last-child td { border-bottom: 0; }
683
683
 
@@ -685,14 +685,14 @@ deck-stage[data-deck-static] .slide { animation: none; }
685
685
  .slide-body blockquote {
686
686
  position: relative;
687
687
  border: 0;
688
- padding: 4px 0 4px 40px;
688
+ padding-block: 4px; padding-inline: 40px 0;
689
689
  margin: 0 0 var(--gap-item);
690
690
  color: var(--ink);
691
691
  }
692
692
  .slide-body blockquote::before {
693
693
  content: '';
694
694
  position: absolute;
695
- left: 0;
695
+ inset-inline-start: 0;
696
696
  top: 0;
697
697
  bottom: 0;
698
698
  width: 6px;
@@ -721,7 +721,7 @@ deck-stage[data-deck-static] .slide { animation: none; }
721
721
  .slide .poll-track, .slide .scale-track { border-radius: 999px; background: color-mix(in oklab, var(--hi) 8%, transparent); box-shadow: inset 0 0 0 1px var(--edge); }
722
722
  .slide .poll-fill { border-radius: 999px; background: var(--shine); box-shadow: 0 0 18px color-mix(in oklab, var(--accent) 40%, transparent); }
723
723
  .slide .scale-fill { border-radius: 14px 14px 0 0; background: linear-gradient(to top, var(--accent), var(--accent-2)); }
724
- .slide .question-cards li { border-radius: 22px; border-left: 0; background: var(--glass-sheen), var(--glass-fill); box-shadow: var(--glass-rim); }
724
+ .slide .question-cards li { border-radius: 22px; border-inline-start: 0; background: var(--glass-sheen), var(--glass-fill); box-shadow: var(--glass-rim); }
725
725
  .slide .poll-join { border-radius: 28px; }
726
726
 
727
727
  /* ─────────────────────────────────────────────
@@ -18,7 +18,7 @@
18
18
  .slide-logo {
19
19
  position: absolute;
20
20
  top: var(--pad-y);
21
- right: var(--pad-x);
21
+ inset-inline-end: var(--pad-x);
22
22
  height: 96px;
23
23
  width: auto;
24
24
  max-width: 420px;
@@ -215,21 +215,21 @@ strong { color: var(--ink); font-weight: 600; }
215
215
  /* ─────────────────────────────────────────────
216
216
  LISTS — a short dash, plain numbers
217
217
  ───────────────────────────────────────────── */
218
- .slide-body ul > li { line-height: 1.4; padding-left: 40px; position: relative; }
218
+ .slide-body ul > li { line-height: 1.4; padding-inline-start: 40px; position: relative; }
219
219
  .slide-body ul > li::before {
220
220
  content: '';
221
221
  position: absolute;
222
- left: 0;
222
+ inset-inline-start: 0;
223
223
  top: 0.72em;
224
224
  width: 16px;
225
225
  height: 2px;
226
226
  background: var(--muted);
227
227
  }
228
- .slide-body ol > li { padding-left: 52px; position: relative; }
228
+ .slide-body ol > li { padding-inline-start: 52px; position: relative; }
229
229
  .slide-body ol > li::before {
230
230
  content: counter(slide-ol) '.';
231
231
  position: absolute;
232
- left: 0;
232
+ inset-inline-start: 0;
233
233
  color: var(--muted);
234
234
  font-variant-numeric: tabular-nums;
235
235
  }
@@ -291,19 +291,19 @@ strong { color: var(--ink); font-weight: 600; }
291
291
  ───────────────────────────────────────────── */
292
292
  .slide-body .callout {
293
293
  background: none;
294
- border-left: 3px solid var(--rule);
294
+ border-inline-start: 3px solid var(--rule);
295
295
  border-radius: 0;
296
- padding: 4px 0 4px 32px;
296
+ padding-block: 4px; padding-inline: 32px 0;
297
297
  margin: 32px 0 0;
298
298
  max-width: 1200px;
299
299
  }
300
- .slide-body :is(.callout-note, .callout-tip, .callout-important) { border-left-color: var(--accent); }
301
- .slide-body :is(.callout-warning, .callout-caution) { border-left-color: var(--accent-3); }
300
+ .slide-body :is(.callout-note, .callout-tip, .callout-important) { border-inline-start-color: var(--accent); }
301
+ .slide-body :is(.callout-warning, .callout-caution) { border-inline-start-color: var(--accent-3); }
302
302
  .slide-body .callout-title { margin-bottom: 8px; }
303
- .slide-body .callout p { padding-left: 0; color: var(--ink); font-size: var(--fs-body); }
303
+ .slide-body .callout p { padding-inline-start: 0; color: var(--ink); font-size: var(--fs-body); }
304
304
  /* Lecture blocks: theorems in the accent, definitions in the second */
305
- .slide-body :is(.callout-theorem, .callout-lemma, .callout-corollary) { border-left-color: var(--accent); }
306
- .slide-body .callout-definition { border-left-color: var(--accent-2); }
305
+ .slide-body :is(.callout-theorem, .callout-lemma, .callout-corollary) { border-inline-start-color: var(--accent); }
306
+ .slide-body .callout-definition { border-inline-start-color: var(--accent-2); }
307
307
 
308
308
  /* ─────────────────────────────────────────────
309
309
  CODE — on the surface, no frame
@@ -344,8 +344,8 @@ strong { color: var(--ink); font-weight: 600; }
344
344
  ───────────────────────────────────────────── */
345
345
  .slide-body blockquote {
346
346
  margin: 0 0 var(--gap-item);
347
- padding: 2px 0 2px 28px;
347
+ padding-block: 2px; padding-inline: 28px 0;
348
348
  border: 0;
349
- border-left: 3px solid var(--muted);
349
+ border-inline-start: 3px solid var(--muted);
350
350
  color: var(--ink-soft);
351
351
  }
@@ -26,7 +26,7 @@
26
26
  .slide-logo {
27
27
  position: absolute;
28
28
  top: var(--pad-y);
29
- right: var(--pad-x);
29
+ inset-inline-end: var(--pad-x);
30
30
  height: 128px;
31
31
  width: auto;
32
32
  max-width: 480px;
@@ -35,7 +35,7 @@
35
35
  transform: translateY(calc(var(--fs-eyebrow) * 0.5 - 50%));
36
36
  /* The rule across the top stops before the logo instead of crossing it. */
37
37
  background: var(--bg);
38
- padding-left: 32px;
38
+ padding-inline-start: 32px;
39
39
  }
40
40
 
41
41
  .slide-footer {
@@ -167,7 +167,7 @@ strong { color: var(--ink); font-weight: 600; }
167
167
  }
168
168
  .chapter-num {
169
169
  position: absolute;
170
- right: var(--pad-x);
170
+ inset-inline-end: var(--pad-x);
171
171
  bottom: calc(var(--pad-y) + 120px);
172
172
  font-family: var(--font-display);
173
173
  font-size: 600px;
@@ -222,7 +222,7 @@ strong { color: var(--ink); font-weight: 600; }
222
222
  justify-content: flex-end;
223
223
  align-items: flex-start;
224
224
  }
225
- .slide--chapter.has-image .chapter-num { right: auto; left: calc(var(--pad-x) - 40px); }
225
+ .slide--chapter.has-image .chapter-num { inset-inline-end: auto; inset-inline-start: calc(var(--pad-x) - 40px); }
226
226
  .slide--chapter.has-image .chapter-image {
227
227
  width: 100%;
228
228
  height: 100%;
@@ -256,7 +256,7 @@ strong { color: var(--ink); font-weight: 600; }
256
256
  .slide--focus .slide-body {
257
257
  justify-content: center;
258
258
  align-items: flex-start;
259
- text-align: left;
259
+ text-align: start;
260
260
  }
261
261
  .focus-eyebrow {
262
262
  font-family: var(--font-body);
@@ -279,7 +279,7 @@ strong { color: var(--ink); font-weight: 600; }
279
279
  max-width: 1560px;
280
280
  margin: 0;
281
281
  text-wrap: balance;
282
- text-align: left;
282
+ text-align: start;
283
283
  }
284
284
  .focus-content {
285
285
  display: flex;
@@ -339,13 +339,13 @@ strong { color: var(--ink); font-weight: 600; }
339
339
  .slide-body ul > li {
340
340
  font-weight: 400;
341
341
  line-height: 1.32;
342
- padding-left: 44px;
342
+ padding-inline-start: 44px;
343
343
  position: relative;
344
344
  }
345
345
  .slide-body ul > li::before {
346
346
  content: '';
347
347
  position: absolute;
348
- left: 0;
348
+ inset-inline-start: 0;
349
349
  top: 0.42em;
350
350
  width: 14px;
351
351
  height: 14px;
@@ -353,13 +353,13 @@ strong { color: var(--ink); font-weight: 600; }
353
353
  }
354
354
  .slide-body ol > li {
355
355
  counter-increment: slide-ol;
356
- padding-left: 64px;
356
+ padding-inline-start: 64px;
357
357
  position: relative;
358
358
  }
359
359
  .slide-body ol > li::before {
360
360
  content: counter(slide-ol, decimal-leading-zero);
361
361
  position: absolute;
362
- left: 0;
362
+ inset-inline-start: 0;
363
363
  top: 0.05em;
364
364
  font-family: var(--font-display);
365
365
  font-size: var(--fs-body);
@@ -428,7 +428,7 @@ strong { color: var(--ink); font-weight: 600; }
428
428
  ───────────────────────────────────────────── */
429
429
  .slide-body .callout {
430
430
  background: none;
431
- border-left: 0;
431
+ border-inline-start: 0;
432
432
  border-top: 6px solid var(--rule);
433
433
  padding: 20px 0 0;
434
434
  margin: 40px 0 0;
@@ -438,7 +438,7 @@ strong { color: var(--ink); font-weight: 600; }
438
438
  .slide-body .callout-tip .callout-title { color: var(--accent); }
439
439
  .slide-body :is(.callout-warning, .callout-caution) { border-top-color: var(--accent-3); }
440
440
  .slide-body .callout-title { letter-spacing: 0.12em; margin-bottom: 10px; }
441
- .slide-body .callout p { padding-left: 0; color: var(--ink); font-size: var(--fs-body); }
441
+ .slide-body .callout p { padding-inline-start: 0; color: var(--ink); font-size: var(--fs-body); }
442
442
  /* Lecture blocks: theorems under a rule in the accent, definitions in the second */
443
443
  .slide-body :is(.callout-theorem, .callout-lemma, .callout-corollary) { border-top-color: var(--accent); }
444
444
  .slide-body .callout-definition { border-top-color: var(--accent-2); }
@@ -491,9 +491,9 @@ strong { color: var(--ink); font-weight: 600; }
491
491
  ───────────────────────────────────────────── */
492
492
  .slide-body blockquote {
493
493
  margin: 0 0 var(--gap-item);
494
- padding: 2px 0 2px 32px;
494
+ padding-block: 2px; padding-inline: 32px 0;
495
495
  border: 0;
496
- border-left: 6px solid var(--accent);
496
+ border-inline-start: 6px solid var(--accent);
497
497
  max-width: 1200px;
498
498
  color: var(--ink);
499
499
  }