rshow 0.0.5 → 0.0.7

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 (41) hide show
  1. package/dist/main.js +15258 -631
  2. package/package.json +2 -1
  3. package/skills/rshow/SKILL.md +7 -0
  4. package/skills/rshow/reference/mockups.md +1 -0
  5. package/skills/rshow/reference/reports.md +5 -1
  6. package/skills/rshow-slides/SKILL.md +9 -0
  7. package/skills/rshow-slides/reference/layouts.md +15 -0
  8. package/themes/default/deck.css +325 -1
  9. package/themes/default/deck.js +255 -5
  10. package/themes/default/example/index.html +19 -2
  11. package/themes/default/example/report.html +17 -10
  12. package/themes/default/fonts/katex/KaTeX_AMS-Regular.woff2 +0 -0
  13. package/themes/default/fonts/katex/KaTeX_Caligraphic-Bold.woff2 +0 -0
  14. package/themes/default/fonts/katex/KaTeX_Caligraphic-Regular.woff2 +0 -0
  15. package/themes/default/fonts/katex/KaTeX_Fraktur-Bold.woff2 +0 -0
  16. package/themes/default/fonts/katex/KaTeX_Fraktur-Regular.woff2 +0 -0
  17. package/themes/default/fonts/katex/KaTeX_Main-Bold.woff2 +0 -0
  18. package/themes/default/fonts/katex/KaTeX_Main-BoldItalic.woff2 +0 -0
  19. package/themes/default/fonts/katex/KaTeX_Main-Italic.woff2 +0 -0
  20. package/themes/default/fonts/katex/KaTeX_Main-Regular.woff2 +0 -0
  21. package/themes/default/fonts/katex/KaTeX_Math-BoldItalic.woff2 +0 -0
  22. package/themes/default/fonts/katex/KaTeX_Math-Italic.woff2 +0 -0
  23. package/themes/default/fonts/katex/KaTeX_SansSerif-Bold.woff2 +0 -0
  24. package/themes/default/fonts/katex/KaTeX_SansSerif-Italic.woff2 +0 -0
  25. package/themes/default/fonts/katex/KaTeX_SansSerif-Regular.woff2 +0 -0
  26. package/themes/default/fonts/katex/KaTeX_Script-Regular.woff2 +0 -0
  27. package/themes/default/fonts/katex/KaTeX_Size1-Regular.woff2 +0 -0
  28. package/themes/default/fonts/katex/KaTeX_Size2-Regular.woff2 +0 -0
  29. package/themes/default/fonts/katex/KaTeX_Size3-Regular.woff2 +0 -0
  30. package/themes/default/fonts/katex/KaTeX_Size4-Regular.woff2 +0 -0
  31. package/themes/default/fonts/katex/KaTeX_Typewriter-Regular.woff2 +0 -0
  32. package/themes/default/fonts/katex/LICENSE +21 -0
  33. package/themes/default/math.css +46 -0
  34. package/themes/default/math.js +58 -0
  35. package/themes/default/mockup.css +105 -2
  36. package/themes/default/mockup.js +342 -18
  37. package/themes/default/report.css +15 -6
  38. package/themes/default/terminal.css +8 -0
  39. package/themes/default/terminal.js +70 -13
  40. package/themes/default/theme.json +7 -0
  41. package/worker/index.js +15 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rshow",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Publish static artifacts to rshow",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rslib.github.io/rshow",
@@ -44,6 +44,7 @@
44
44
  "devDependencies": {
45
45
  "@types/node": "^26.6.6",
46
46
  "esbuild": "0.28.2",
47
+ "katex": "0.19.1",
47
48
  "rshow-shared": "*",
48
49
  "typescript": "^5.9.3"
49
50
  }
@@ -62,6 +62,11 @@ Copy this checklist into the reply and tick it as you go.
62
62
  Never write `latest`.
63
63
  - A report links `report.css` and `report.js` in place of `page.css`, and `mode.js` still goes in the head.
64
64
  Read [reports](reference/reports.md) before you write one.
65
+ - Math is LaTeX in the text of an element with the class `math`, and the page links `math.css` and `math.js` for it.
66
+ Math needs theme version 8 or newer, so a page on an older version moves up with `rshow config <dir>`.
67
+ A `div.math` is display math and any other element is inline.
68
+ A `$` in the prose is a price and is never read as math, so `$5` stays text.
69
+ Read [reports](reference/reports.md) for the markup an equation takes.
65
70
  - The page reads at 360px wide.
66
71
  Tables go inside `<div class="table">`.
67
72
  - Nothing secret in a page, because anyone who holds the link can read the HTML source.
@@ -145,6 +150,8 @@ The short list above is a hard rule.
145
150
  - Never publish a folder that holds `.env`, a key, a credential or customer data.
146
151
  - Never publish a source tree, `node_modules` or a `dist` folder that still holds a draft.
147
152
  - Never write the token into a page, a script, a log line, a commit or a chat message.
153
+ - Never fake math with Unicode subscripts, Greek letters in mono or an HTML `<sub>`.
154
+ Write the LaTeX in an element with the class `math` and link `math.css` and `math.js`.
148
155
  - Never create a second artifact with a `-v2` slug.
149
156
  Publish the same slug again.
150
157
  - Never delete an artifact or drop a share without a yes from the person.
@@ -110,6 +110,7 @@ Never present invented data as if somebody measured it.
110
110
 
111
111
  - `rshow check <dir>` exits 0, then `rshow preview <dir>`.
112
112
  - Look at the canvas, the focus view and Play mode, in both modes, at desktop width and at 360px.
113
+ - Press `?` on the page for the keys: `w` `a` `s` `d` or the arrows pan, `[` `]` step between screens, `Enter` opens one, `1` to `9` pick a state, so tell the person about that list.
113
114
  - Switch the skin in the toolbar and check the drawing still reads.
114
115
  - Print puts one artboard on a page with no tool chrome, which is what a review meeting wants on paper.
115
116
  - `rshow publish <dir> --slug <slug> --label "<what changed>"`, then read `rshow-implement` before anybody writes code from it.
@@ -109,7 +109,11 @@ Numbering is generated, so never type a number into a heading.
109
109
 
110
110
  `report.js` puts `Figure 1.` or `Table 1.` in front of the caption and counts in document order, so give every one an `id`.
111
111
  Draw the figure as inline `<svg>` with the colours from tokens, and give it a `viewBox` so it scales.
112
- An equation is `<div class="equation" id="eq-bytes">` with the formula inside, and `report.js` adds `(1)` at the end of the line.
112
+ An equation is `<div class="equation" id="eq-bytes">` with a `<div class="math">` of LaTeX inside it, and `report.js` adds `(1)` at the end of the line.
113
+ The report links `math.css` in the head and `math.js` before `report.js`, and `rshow check` reports bad LaTeX as an error.
114
+ Inline math is a `<span class="math">` inside the sentence, and a wide equation scrolls inside its own box on a phone.
115
+ Write `<` as `&lt;` and `&` as `&amp;` inside the LaTeX, and `&amp;` where lines align in a LaTeX alignment.
116
+ A `$...$` in the prose is not math: it is text, so a price such as `$5` stays a price.
113
117
  Mark example data as example data in the caption, and never present a number you did not measure.
114
118
 
115
119
  ## Cross-references
@@ -33,6 +33,7 @@ A topic on its own is not a slide.
33
33
  ## 2. Skeleton
34
34
 
35
35
  Replace `<name>@<n>` with the `theme` value that `rshow config <dir>` prints, which the server resolves to the current version. Use `default@3` only when `rshow config` warns that it cannot resolve the theme.
36
+ Math needs theme version 8 or newer, so a page on an older version moves up with `rshow config <dir>`.
36
37
 
37
38
  ```html
38
39
  <!doctype html>
@@ -44,6 +45,9 @@ Replace `<name>@<n>` with the `theme` value that `rshow config <dir>` prints, wh
44
45
  <link rel="stylesheet" href="/_themes/default@3/fonts.css">
45
46
  <link rel="stylesheet" href="/_themes/default@3/tokens.css">
46
47
  <link rel="stylesheet" href="/_themes/default@3/deck.css">
48
+ <!-- a deck that writes math links these two, and math.js goes before deck.js -->
49
+ <link rel="stylesheet" href="/_themes/default@3/math.css">
50
+ <script defer src="/_themes/default@3/math.js"></script>
47
51
  </head>
48
52
  <body>
49
53
  <main class="deck">
@@ -71,6 +75,7 @@ Replace `<name>@<n>` with the `theme` value that `rshow config <dir>` prints, wh
71
75
  ```
72
76
 
73
77
  The three stylesheet links and the script carry the same `<n>` on purpose, because a mixed version renders somewhere between two designs.
78
+ A fallback to `default@3` keeps the page readable but has no math, so a deck on that version links neither `math.css` nor `math.js`, and the `math.js` warning of `rshow check` is the sign to move up.
74
79
  The deck needs no `mode.js`, because `deck.js` reads the same key and `t` does the same work.
75
80
  Override a token in one `:root` block after the theme links when the deck needs its own accent, with no limit on the declarations.
76
81
  An inline `<style>` block after the theme links may also carry a layout of the deck's own, as section 3 says.
@@ -85,6 +90,7 @@ Every slide is a `<section class="slide ...">`, and the second class is one of t
85
90
  One series is drawn in the accent blue and two or more take `--chart-1`, `--chart-2` and so on in order.
86
91
  - `table` for a clean data table and `code` for one command.
87
92
  - `two-col` for two blocks of text, `quote` for one sentence and `big-number` for one number.
93
+ - A slide with an equation is a `bullets` slide with one `<div class="math">` of LaTeX under the title, and the deck links `math.css` and `math.js` for it.
88
94
 
89
95
  A sparse slide is centred a little above the middle of the canvas, so the air sits under the block.
90
96
  A bullets slide puts its points under the title at 28px with a 1.4 line, five at most.
@@ -102,6 +108,7 @@ Vary the rhythm: do not run more than three text slides (`two-col` or `bullets`)
102
108
  - Every slide gets one `<aside class="notes">`, including the title slide, because a slide without one shows nothing in the notes window.
103
109
  - Keep a note under 60 words.
104
110
  It is what you say, not what the room reads.
111
+ - A note holds no math: an equation inside an `aside.notes` stays as its LaTeX, because the notes window loads no math stylesheet.
105
112
  - Press `n` for the notes window, which also names the next slide.
106
113
  - Press `p` for the presenter view: the current slide, the next slide, the notes and an elapsed timer, kept in step with the deck.
107
114
  - Put `class="step"` on any element inside a slide to reveal it one press later, because `deck.js` selects every `.step` in the slide.
@@ -112,6 +119,8 @@ Vary the rhythm: do not run more than three text slides (`two-col` or `bullets`)
112
119
  Press `Ctrl` and `P` for a print sheet when someone wants a pdf.
113
120
  - Press `t` to cycle the mode: system, light, dark, with the mode shown in the counter for a moment.
114
121
  The choice is remembered for every rshow document and print is always light.
122
+ - On a phone held upright the deck reads as a stack of slides, each one reflowed to the width of the screen at phone sizes with a rule and an `n / total` label between slides, and a `Present` button goes back to one slide at a time.
123
+ `Esc` comes back to reading, and the arrows, space and a `#n` link work in both.
115
124
 
116
125
  ## 5. Check, preview, publish
117
126
 
@@ -14,6 +14,7 @@
14
14
  - two-col
15
15
  - quote
16
16
  - big-number
17
+ - math (an equation on a bullets slide)
17
18
  - your own layout
18
19
 
19
20
  One markup example per layout, all inside `<main class="deck">`.
@@ -252,6 +253,20 @@ The unit belongs in the statement and the source goes under it.
252
253
 
253
254
  A number you cannot measure is `[PLACEHOLDER]` until it is real, and a number that stands for an example says so in the source line.
254
255
 
256
+ ## math
257
+
258
+ An equation takes a `bullets` slide: a takeaway title and one `div.math`.
259
+ The LaTeX is the text of the element, and the deck links `math.css` and `math.js` for it.
260
+ A note holds words, not math.
261
+
262
+ ```html
263
+ <section class="slide bullets">
264
+ <h2>A republish sends only the bytes that changed</h2>
265
+ <div class="math">\mathrm{sent}(n) = \sum_{f \in \mathrm{new}(n)} |f|</div>
266
+ <aside class="notes"><p>The sum drops every file the host already holds.</p></aside>
267
+ </section>
268
+ ```
269
+
255
270
  ## your own layout
256
271
 
257
272
  A layout of your own takes a short class name and sits second on the slide, in the same slot as the twelve.
@@ -517,6 +517,323 @@ aside.notes {
517
517
  pointer-events: none;
518
518
  }
519
519
 
520
+ /* --------------------------------------------------------------- reading */
521
+
522
+ /* A phone held upright cannot show a 16:9 slide: 390px of width leaves a 219px
523
+ strip. So the deck stops presenting and reads. Every slide becomes a block
524
+ down the page, the width of the screen, one after another, with no scale in
525
+ it: a 1280px canvas shrunk to 390px sets the body text near 9px, which is a
526
+ picture of a slide and not a slide. The type takes sizes a phone reads, each
527
+ figure takes the width it is given, a wide table or a block of code scrolls
528
+ sideways inside itself, and every grid stacks to one column. The notes stay
529
+ hidden, every step is out, and a hairline rule with an "n / total" label in
530
+ the margin marks where one slide ends and the next begins.
531
+ deck.js turns this on for a viewport that is portrait and narrower than 700px,
532
+ and off everywhere else: a landscape phone and a desktop keep one slide at a
533
+ time. The button that goes back to presenting is deck.js's, and Esc comes back
534
+ here. It is a screen mode, so it sits in @media screen: a sheet of paper keeps
535
+ one slide per page, laid out on the canvas it was drawn for. */
536
+
537
+ @media screen {
538
+ html.is-reading,
539
+ body.is-reading {
540
+ height: auto;
541
+ overflow: visible;
542
+ background: var(--bg);
543
+ /* Reading sizes. The type scale has no 17px step and the canvas headings are
544
+ drawn for 1280px, so a phone slide names the size of its own body text and
545
+ of the one line a quote or a statement sets. Every other size below is a
546
+ token: 32px, 24px, 20px, 18px, 14px. */
547
+ --deck-read-body: 17px;
548
+ --deck-read-line: 22px;
549
+ }
550
+
551
+ /* The deck is the page now: no canvas, no transform, no clip. The bottom pad
552
+ clears the Present button, so the last line of the last slide stays under
553
+ the reader's thumb and not inside it. */
554
+ main.deck.is-reading {
555
+ position: static;
556
+ width: auto;
557
+ height: auto;
558
+ margin: 0;
559
+ padding: 0 0 80px;
560
+ overflow: visible;
561
+ transform: none !important;
562
+ background: var(--bg);
563
+ counter-reset: deck-slide;
564
+ }
565
+
566
+ /* One slide, one block: the width of the screen, a 16px gutter either side,
567
+ air above and below, and a rule where the previous slide ended. */
568
+ main.deck.is-reading > .slide,
569
+ main.deck.is-reading.is-ready > .slide {
570
+ position: relative;
571
+ inset: auto;
572
+ display: block;
573
+ width: auto;
574
+ height: auto;
575
+ min-height: 0;
576
+ margin: 0;
577
+ padding: var(--space-06) var(--space-05);
578
+ overflow: visible;
579
+ opacity: 1;
580
+ visibility: visible;
581
+ transform: none;
582
+ border-top: 1px solid var(--border-subtle);
583
+ counter-increment: deck-slide;
584
+ }
585
+
586
+ main.deck.is-reading > .slide:first-child {
587
+ border-top: 0;
588
+ }
589
+
590
+ /* Where this slide sits in the stack. It is a label, so sans, sentence case
591
+ and the muted colour of every other label: mono and caps are for code. */
592
+ main.deck.is-reading > .slide::before {
593
+ content: counter(deck-slide) " / " var(--deck-total, "");
594
+ display: block;
595
+ margin: 0 0 var(--space-05);
596
+ font-family: var(--font-sans);
597
+ font-size: var(--text-2xs);
598
+ font-weight: 400;
599
+ line-height: 1.33;
600
+ letter-spacing: 0;
601
+ text-transform: none;
602
+ color: var(--muted);
603
+ font-variant-numeric: tabular-nums;
604
+ }
605
+
606
+ /* ----------------------------------------------------- reading type --- */
607
+
608
+ /* The display steps belong to a 1280px slide: 76px of heading in 358px of
609
+ width is three words a line. In reading mode a heading is a heading. */
610
+ main.deck.is-reading .slide h1,
611
+ main.deck.is-reading .slide h2,
612
+ main.deck.is-reading .slide h3 {
613
+ margin: 0 0 var(--space-04);
614
+ max-width: none;
615
+ font-weight: 400;
616
+ line-height: var(--lh-heading);
617
+ letter-spacing: 0;
618
+ }
619
+
620
+ main.deck.is-reading .slide h1 {
621
+ font-size: var(--text-xl);
622
+ }
623
+
624
+ main.deck.is-reading .slide h2 {
625
+ font-size: var(--text-md);
626
+ }
627
+
628
+ main.deck.is-reading .slide h3 {
629
+ font-size: var(--text-base);
630
+ font-weight: 600;
631
+ }
632
+
633
+ /* Running text: 17px on a 1.45 leading reads on a phone without a pinch, and
634
+ the measure is the screen, so nothing caps it short of the gutter. */
635
+ main.deck.is-reading .slide p,
636
+ main.deck.is-reading .slide li,
637
+ main.deck.is-reading .slide li > p,
638
+ main.deck.is-reading .slide .col p,
639
+ main.deck.is-reading .slide .col li {
640
+ max-width: none;
641
+ font-size: var(--deck-read-body);
642
+ line-height: var(--lh-body);
643
+ }
644
+
645
+ main.deck.is-reading .slide ul,
646
+ main.deck.is-reading .slide ol {
647
+ padding-left: var(--space-06);
648
+ }
649
+
650
+ main.deck.is-reading .slide li {
651
+ margin-bottom: var(--space-03);
652
+ }
653
+
654
+ main.deck.is-reading .slide li:last-child {
655
+ margin-bottom: 0;
656
+ }
657
+
658
+ main.deck.is-reading .slide.title .subtitle {
659
+ margin-top: var(--space-04);
660
+ max-width: none;
661
+ font-size: var(--text-sm);
662
+ line-height: 1.4;
663
+ }
664
+
665
+ /* The line under a title, a figure or a table: a caption, so small and muted,
666
+ and never wider than the slide. */
667
+ main.deck.is-reading .slide .muted,
668
+ main.deck.is-reading .slide figcaption,
669
+ main.deck.is-reading .slide cite,
670
+ main.deck.is-reading .slide caption,
671
+ main.deck.is-reading .slide .byline,
672
+ main.deck.is-reading .slide .source,
673
+ main.deck.is-reading .slide li > p {
674
+ max-width: none;
675
+ font-size: var(--text-2xs);
676
+ line-height: 1.45;
677
+ }
678
+
679
+ main.deck.is-reading .slide.section h2 {
680
+ margin-bottom: 0;
681
+ font-size: var(--text-md);
682
+ font-weight: 400;
683
+ }
684
+
685
+ main.deck.is-reading .slide.statement p,
686
+ main.deck.is-reading .slide.quote blockquote {
687
+ max-width: none;
688
+ font-size: var(--deck-read-line);
689
+ font-weight: 400;
690
+ line-height: 1.4;
691
+ }
692
+
693
+ main.deck.is-reading .slide.big-number .value {
694
+ font-size: var(--text-2xl);
695
+ line-height: var(--lh-flat);
696
+ }
697
+
698
+ main.deck.is-reading .slide.big-number .caption {
699
+ max-width: none;
700
+ font-size: var(--text-sm);
701
+ line-height: 1.4;
702
+ }
703
+
704
+ /* A statement or a divider carries one short line, so it keeps a little
705
+ height and sits its text in the middle of it instead of at the top. */
706
+ main.deck.is-reading > .slide.statement,
707
+ main.deck.is-reading > .slide.section {
708
+ display: flex;
709
+ flex-direction: column;
710
+ justify-content: center;
711
+ min-height: 40vh;
712
+ }
713
+
714
+ /* ------------------------------------------------ reading containers -- */
715
+
716
+ /* Anything that holds a picture takes the width it is given, keeps its own
717
+ shape, and never reaches past the gutter. */
718
+ main.deck.is-reading .slide figure {
719
+ display: block;
720
+ margin: 0;
721
+ min-height: 0;
722
+ }
723
+
724
+ main.deck.is-reading .slide img,
725
+ main.deck.is-reading .slide svg,
726
+ main.deck.is-reading .slide video,
727
+ main.deck.is-reading .slide canvas {
728
+ display: block;
729
+ max-width: 100%;
730
+ height: auto;
731
+ }
732
+
733
+ /* A table keeps its columns and a code block keeps its lines: each one
734
+ scrolls sideways inside itself rather than widening the page. */
735
+ main.deck.is-reading .slide table {
736
+ display: block;
737
+ width: 100%;
738
+ max-width: 100%;
739
+ overflow-x: auto;
740
+ font-size: 15px;
741
+ line-height: 1.4;
742
+ }
743
+
744
+ main.deck.is-reading .slide th,
745
+ main.deck.is-reading .slide td {
746
+ padding: var(--space-03) var(--space-04);
747
+ }
748
+
749
+ main.deck.is-reading .slide pre {
750
+ max-width: 100%;
751
+ max-height: none;
752
+ padding: var(--space-05);
753
+ overflow-x: auto;
754
+ overflow-y: hidden;
755
+ font-size: 14px;
756
+ line-height: var(--lh-code);
757
+ white-space: pre;
758
+ word-break: normal;
759
+ tab-size: 2;
760
+ }
761
+
762
+ /* Two columns and two figures side by side are a landscape idea. On a phone
763
+ every grid is one column, in the order the deck wrote it. */
764
+ main.deck.is-reading > .slide.two-col,
765
+ main.deck.is-reading > .slide.three-col,
766
+ main.deck.is-reading > .slide .pair,
767
+ main.deck.is-reading > .slide .col,
768
+ main.deck.is-reading > .slide .cols,
769
+ main.deck.is-reading > .slide .grid,
770
+ main.deck.is-reading > .slide .gallery {
771
+ display: block;
772
+ grid-template-columns: none;
773
+ gap: 0;
774
+ min-height: 0;
775
+ }
776
+
777
+ main.deck.is-reading .slide.two-col > h2 {
778
+ grid-column: auto;
779
+ margin-bottom: var(--space-05);
780
+ }
781
+
782
+ main.deck.is-reading .slide .pair > figure + figure,
783
+ main.deck.is-reading .slide .col + .col {
784
+ margin-top: var(--space-06);
785
+ }
786
+
787
+ /* --------------------------------------------------- reading chrome --- */
788
+
789
+ /* A reader scrolls. A keypress it cannot give, so nothing waits for one, and
790
+ the notes and the counter are a presenter's furniture, not a reader's. */
791
+ main.deck.is-reading .step {
792
+ opacity: 1;
793
+ }
794
+
795
+ main.deck.is-reading aside.notes,
796
+ main.deck.is-reading .deck-hud {
797
+ display: none;
798
+ }
799
+ }
800
+
801
+ /* One slide at a time, for a room or for a phone turned back to presenting. */
802
+ .deck-present {
803
+ position: fixed;
804
+ z-index: 20;
805
+ right: max(16px, env(safe-area-inset-right, 16px));
806
+ bottom: max(16px, env(safe-area-inset-bottom, 16px));
807
+ min-width: 44px;
808
+ min-height: 44px;
809
+ padding: 0 14px;
810
+ font-family: var(--font-sans);
811
+ font-size: var(--text-2xs);
812
+ line-height: 1;
813
+ letter-spacing: 0;
814
+ color: var(--fg);
815
+ background: var(--bg);
816
+ border: 1px solid var(--border-subtle);
817
+ border-radius: var(--radius);
818
+ cursor: pointer;
819
+ -webkit-appearance: none;
820
+ appearance: none;
821
+ }
822
+
823
+ .deck-present[hidden] {
824
+ display: none;
825
+ }
826
+
827
+ /* A phone in present mode keeps the canvas on the window rather than in the
828
+ document: a 1280px box in the page widens a phone's layout viewport and
829
+ pushes the slide off the screen. */
830
+ @media (max-width: 699px) {
831
+ main.deck {
832
+ position: fixed;
833
+ inset: 0;
834
+ }
835
+ }
836
+
520
837
  @media (prefers-reduced-motion: reduce) {
521
838
  .step {
522
839
  transition: none;
@@ -574,9 +891,16 @@ aside.notes {
574
891
  }
575
892
 
576
893
  .deck-hud,
577
- aside.notes {
894
+ aside.notes,
895
+ .deck-present {
578
896
  display: none !important;
579
897
  }
898
+
899
+ /* Reading mode is a screen mode, so a page printed from a phone is the deck
900
+ on its canvas again: one slide, one sheet. Nothing here has to undo it. */
901
+ main.deck.is-reading {
902
+ overflow: visible;
903
+ }
580
904
  }
581
905
 
582
906
  /* Exact 16:9 sheet for one slide per page. */