@kadal/deck 0.0.0-stage → 0.1.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 (157) hide show
  1. package/LICENSE +661 -0
  2. package/LICENSING.md +40 -0
  3. package/README.md +170 -2
  4. package/dist/_virtual/_rolldown/runtime.js +13 -0
  5. package/dist/audience/index.d.ts +14 -0
  6. package/dist/audience/index.js +680 -0
  7. package/dist/backgrounds/index.d.ts +65 -0
  8. package/dist/backgrounds/index.js +604 -0
  9. package/dist/backgrounds/shared.d.ts +7 -0
  10. package/dist/backgrounds/shared.js +89 -0
  11. package/dist/cli/bin.d.ts +1 -0
  12. package/dist/cli/bin.js +8 -0
  13. package/dist/cli/host.js +111 -0
  14. package/dist/cli/index.d.ts +4 -0
  15. package/dist/cli/index.js +140 -0
  16. package/dist/cli/login.js +56 -0
  17. package/dist/cli/publish.js +159 -0
  18. package/dist/cli/vite.js +39 -0
  19. package/dist/compiler/code-meta.d.ts +33 -0
  20. package/dist/compiler/code-meta.js +81 -0
  21. package/dist/compiler/index.d.ts +8 -0
  22. package/dist/compiler/index.js +8 -0
  23. package/dist/compiler/magic-move.d.ts +26 -0
  24. package/dist/compiler/magic-move.js +33 -0
  25. package/dist/compiler/plain-text.js +7 -0
  26. package/dist/compiler/rehype-code.d.ts +18 -0
  27. package/dist/compiler/rehype-code.js +66 -0
  28. package/dist/compiler/rehype-glossary.d.ts +35 -0
  29. package/dist/compiler/rehype-glossary.js +211 -0
  30. package/dist/compiler/slots.d.ts +3 -0
  31. package/dist/compiler/slots.js +36 -0
  32. package/dist/compiler/split.d.ts +63 -0
  33. package/dist/compiler/split.js +195 -0
  34. package/dist/components/Background.d.ts +15 -0
  35. package/dist/components/Background.js +24 -0
  36. package/dist/components/Click.d.ts +54 -0
  37. package/dist/components/Click.js +129 -0
  38. package/dist/components/Code.d.ts +27 -0
  39. package/dist/components/Code.js +124 -0
  40. package/dist/components/Motion.d.ts +25 -0
  41. package/dist/components/Motion.js +45 -0
  42. package/dist/components/Sketch.d.ts +44 -0
  43. package/dist/components/Sketch.js +141 -0
  44. package/dist/components/Term.d.ts +63 -0
  45. package/dist/components/Term.js +492 -0
  46. package/dist/components/bling.d.ts +75 -0
  47. package/dist/components/bling.js +146 -0
  48. package/dist/components/content.d.ts +232 -0
  49. package/dist/components/content.js +637 -0
  50. package/dist/components/index.d.ts +10 -0
  51. package/dist/components/index.js +88 -0
  52. package/dist/core/clicks.d.ts +45 -0
  53. package/dist/core/clicks.js +75 -0
  54. package/dist/core/hash.d.ts +33 -0
  55. package/dist/core/hash.js +49 -0
  56. package/dist/core/keyboard.d.ts +17 -0
  57. package/dist/core/keyboard.js +198 -0
  58. package/dist/core/layout.d.ts +16 -0
  59. package/dist/core/layout.js +25 -0
  60. package/dist/core/model.d.ts +259 -0
  61. package/dist/core/model.js +377 -0
  62. package/dist/core/navigation.d.ts +74 -0
  63. package/dist/core/navigation.js +244 -0
  64. package/dist/core/poster.js +30 -0
  65. package/dist/core/store.d.ts +20 -0
  66. package/dist/core/store.js +64 -0
  67. package/dist/core/touch.js +27 -0
  68. package/dist/draw/DrawingLayer.js +315 -0
  69. package/dist/draw/strokes.js +188 -0
  70. package/dist/export/index.d.ts +68 -0
  71. package/dist/export/index.js +251 -0
  72. package/dist/export/run.js +81 -0
  73. package/dist/glossary/model.d.ts +81 -0
  74. package/dist/glossary/model.js +156 -0
  75. package/dist/glossary/parse.d.ts +27 -0
  76. package/dist/glossary/parse.js +90 -0
  77. package/dist/index.d.ts +31 -0
  78. package/dist/index.js +30 -0
  79. package/dist/live/LiveProvider.d.ts +20 -0
  80. package/dist/live/LiveProvider.js +450 -0
  81. package/dist/live/analytics.d.ts +15 -0
  82. package/dist/live/analytics.js +103 -0
  83. package/dist/live/client.d.ts +51 -0
  84. package/dist/live/client.js +193 -0
  85. package/dist/live/components.d.ts +64 -0
  86. package/dist/live/components.js +471 -0
  87. package/dist/live/context.d.ts +15 -0
  88. package/dist/live/context.js +28 -0
  89. package/dist/live/index.d.ts +7 -0
  90. package/dist/live/index.js +7 -0
  91. package/dist/live/protocol.d.ts +284 -0
  92. package/dist/live/protocol.js +42 -0
  93. package/dist/live/turnstile.js +49 -0
  94. package/dist/presenter/index.d.ts +20 -0
  95. package/dist/presenter/index.js +1211 -0
  96. package/dist/react/AutoAnimate.js +92 -0
  97. package/dist/react/Backgrounds.d.ts +11 -0
  98. package/dist/react/Backgrounds.js +154 -0
  99. package/dist/react/ConfettiLayer.js +85 -0
  100. package/dist/react/Deck.d.ts +35 -0
  101. package/dist/react/Deck.js +983 -0
  102. package/dist/react/Frame.d.ts +16 -0
  103. package/dist/react/Frame.js +174 -0
  104. package/dist/react/Hints.d.ts +3 -0
  105. package/dist/react/Hints.js +201 -0
  106. package/dist/react/Lightbox.js +54 -0
  107. package/dist/react/Overview.js +93 -0
  108. package/dist/react/PrintView.js +128 -0
  109. package/dist/react/ScrollView.js +128 -0
  110. package/dist/react/SlideFrame.d.ts +51 -0
  111. package/dist/react/SlideFrame.js +323 -0
  112. package/dist/react/Stage.js +151 -0
  113. package/dist/react/ThemeMenu.d.ts +5 -0
  114. package/dist/react/ThemeMenu.js +124 -0
  115. package/dist/react/Zoom.js +23 -0
  116. package/dist/react/chrome.js +339 -0
  117. package/dist/react/context.d.ts +165 -0
  118. package/dist/react/context.js +19 -0
  119. package/dist/react/hooks.d.ts +33 -0
  120. package/dist/react/hooks.js +70 -0
  121. package/dist/react/layouts.d.ts +21 -0
  122. package/dist/react/layouts.js +104 -0
  123. package/dist/react/mdx.d.ts +4 -0
  124. package/dist/react/mdx.js +33 -0
  125. package/dist/react/terms.d.ts +6 -0
  126. package/dist/react/terms.js +66 -0
  127. package/dist/renderers/Island.d.ts +57 -0
  128. package/dist/renderers/Island.js +223 -0
  129. package/dist/renderers/contract.d.ts +173 -0
  130. package/dist/renderers/contract.js +152 -0
  131. package/dist/renderers/index.d.ts +12 -0
  132. package/dist/renderers/index.js +16 -0
  133. package/dist/renderers/react.d.ts +16 -0
  134. package/dist/renderers/react.js +32 -0
  135. package/dist/renderers/web-components.d.ts +4 -0
  136. package/dist/renderers/web-components.js +103 -0
  137. package/dist/sketch/Canvas.js +49 -0
  138. package/dist/sketch/dsl.d.ts +131 -0
  139. package/dist/sketch/dsl.js +281 -0
  140. package/dist/sketch/index.d.ts +4 -0
  141. package/dist/sketch/index.js +3 -0
  142. package/dist/sketch/palette.d.ts +21 -0
  143. package/dist/sketch/palette.js +66 -0
  144. package/dist/sketch/render.d.ts +43 -0
  145. package/dist/sketch/render.js +198 -0
  146. package/dist/themes/base.css +1704 -0
  147. package/dist/themes/bling.css +592 -0
  148. package/dist/themes/glossary.css +317 -0
  149. package/dist/themes/live.css +1557 -0
  150. package/dist/themes/minimal.css +83 -0
  151. package/dist/themes/rla.css +92 -0
  152. package/dist/themes/sketch.css +121 -0
  153. package/dist/themes/stack.css +62 -0
  154. package/dist/vite/index.d.ts +15 -0
  155. package/dist/vite/index.js +320 -0
  156. package/package.json +159 -4
  157. package/tools/verify-island.mjs +150 -0
@@ -0,0 +1,1704 @@
1
+ /* ─────────────────────────────────────────────────────────────────────────────
2
+ @kadal/deck — base stylesheet: the stage, slides, transitions, clicks, code,
3
+ chrome, overview, scroll view, print. Themes set the tokens; this sets the bones.
4
+ ───────────────────────────────────────────────────────────────────────────── */
5
+ @import "katex/dist/katex.min.css";
6
+ @import "shiki-magic-move/style.css";
7
+ @import "./live.css";
8
+ @import "./bling.css";
9
+ @import "./sketch.css";
10
+ @import "./glossary.css";
11
+
12
+ :root {
13
+ --deck-bg: #ffffff;
14
+ --deck-fg: #111111;
15
+ --deck-muted: #6b7280;
16
+ --deck-accent: #2563eb;
17
+ --deck-accent-2: #7c3aed;
18
+ --deck-surface: rgba(0, 0, 0, 0.04);
19
+ --deck-border: rgba(0, 0, 0, 0.12);
20
+ --deck-heading-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
21
+ --deck-body-font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
22
+ --deck-mono-font: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
23
+ --deck-code-bg: #f6f8fa;
24
+ --deck-code-fg: #24292e;
25
+ --deck-code-active: rgba(37, 99, 235, 0.12);
26
+ --deck-radius: 12px;
27
+ --deck-pad: 64px;
28
+ --deck-base-size: 32px;
29
+ --deck-live: #ec4899;
30
+ --deck-transition: 600ms;
31
+ }
32
+ [data-color-scheme="dark"] {
33
+ --deck-bg: #0b0b0d;
34
+ --deck-fg: #f4f4f5;
35
+ --deck-muted: #a1a1aa;
36
+ --deck-surface: rgba(255, 255, 255, 0.06);
37
+ --deck-border: rgba(255, 255, 255, 0.14);
38
+ --deck-code-bg: #16161a;
39
+ --deck-code-fg: #e4e4e7;
40
+ --deck-code-active: rgba(96, 165, 250, 0.16);
41
+ }
42
+
43
+ html,
44
+ body {
45
+ margin: 0;
46
+ height: 100%;
47
+ background: var(--deck-bg);
48
+ color: var(--deck-fg);
49
+ font-family: var(--deck-body-font);
50
+ -webkit-font-smoothing: antialiased;
51
+ overscroll-behavior: none;
52
+ }
53
+ #root,
54
+ .deck-root {
55
+ position: relative;
56
+ width: 100%;
57
+ height: 100%;
58
+ overflow: hidden;
59
+ /* Outside the stage: the bars that centre a 16:9 slide in a window of another shape. */
60
+ --deck-bars: color-mix(in oklab, var(--deck-bg) 30%, #000);
61
+ }
62
+ .deck-root.mode-play {
63
+ background: var(--deck-bars);
64
+ }
65
+ .deck-root.cursor-hidden {
66
+ cursor: none;
67
+ }
68
+ .deck-root.no-select .deck-slide {
69
+ user-select: none;
70
+ }
71
+ /* A PROJECTOR is for looking at, not touching: a second screen, or the one window shared on a
72
+ call. It takes no input (see `Flags.projector`), so it shows no cursor and holds no selection —
73
+ a pointer left sitting on it would otherwise ride along into the share. A desktop shell lays
74
+ its own drag surface over the top; that surface brings its own cursor back. */
75
+ .deck-root.is-projector {
76
+ /* No `cursor: none` here: the idle rule above hides it, so it can come back when the pointer
77
+ moves — a share window has an embedded page and a Reload in it worth pointing at. */
78
+ user-select: none;
79
+ }
80
+ .deck-missing-page {
81
+ padding: 3rem;
82
+ font-family: var(--deck-mono-font);
83
+ }
84
+
85
+ /* ── backgrounds ─────────────────────────────────────────────────────────── */
86
+ .deck-backgrounds {
87
+ /* The stage's box (inline left/top/width/height from the layout): the slide's own ground. */
88
+ position: absolute;
89
+ inset: 0;
90
+ z-index: 0;
91
+ overflow: hidden;
92
+ background: var(--deck-bg);
93
+ }
94
+ .deck-background {
95
+ position: absolute;
96
+ inset: 0;
97
+ transition: opacity var(--deck-transition) ease;
98
+ }
99
+ .deck-background-fill,
100
+ .deck-background-video,
101
+ .deck-background-iframe,
102
+ .deck-background-component {
103
+ position: absolute;
104
+ inset: 0;
105
+ width: 100%;
106
+ height: 100%;
107
+ border: 0;
108
+ }
109
+ .deck-background-video {
110
+ object-fit: cover;
111
+ }
112
+ .deck-backgrounds[data-transition="fade"] .is-leaving {
113
+ opacity: 0;
114
+ }
115
+ .deck-backgrounds[data-transition="none"] .is-leaving {
116
+ display: none;
117
+ }
118
+ .deck-backgrounds[data-transition="slide"] .is-leaving,
119
+ .deck-backgrounds[data-transition="convex"] .is-leaving,
120
+ .deck-backgrounds[data-transition="concave"] .is-leaving,
121
+ .deck-backgrounds[data-transition="zoom"] .is-leaving {
122
+ animation: deck-bg-leave var(--deck-transition) ease forwards;
123
+ }
124
+ .deck-backgrounds[data-transition="slide"] .is-entering,
125
+ .deck-backgrounds[data-transition="convex"] .is-entering,
126
+ .deck-backgrounds[data-transition="concave"] .is-entering,
127
+ .deck-backgrounds[data-transition="zoom"] .is-entering {
128
+ animation: deck-bg-enter var(--deck-transition) ease;
129
+ }
130
+ .deck-backgrounds[data-direction="back"] .is-leaving {
131
+ animation-name: deck-bg-leave-back;
132
+ }
133
+ .deck-backgrounds[data-direction="back"] .is-entering {
134
+ animation-name: deck-bg-enter-back;
135
+ }
136
+ @keyframes deck-bg-enter {
137
+ from {
138
+ transform: translateX(100%);
139
+ }
140
+ }
141
+ @keyframes deck-bg-leave {
142
+ to {
143
+ transform: translateX(-100%);
144
+ }
145
+ }
146
+ @keyframes deck-bg-enter-back {
147
+ from {
148
+ transform: translateX(-100%);
149
+ }
150
+ }
151
+ @keyframes deck-bg-leave-back {
152
+ to {
153
+ transform: translateX(100%);
154
+ }
155
+ }
156
+ .deck-background-missing {
157
+ position: absolute;
158
+ inset: auto 1rem 1rem auto;
159
+ font: 12px var(--deck-mono-font);
160
+ color: #f43f5e;
161
+ }
162
+
163
+ /* ── stage and slides ────────────────────────────────────────────────────── */
164
+ .deck-zoom {
165
+ position: absolute;
166
+ inset: 0;
167
+ z-index: 1;
168
+ }
169
+ .deck-stage {
170
+ position: absolute;
171
+ left: 0;
172
+ top: 0;
173
+ transform-origin: 0 0;
174
+ perspective: 1600px;
175
+ will-change: transform;
176
+ }
177
+ .deck-slide {
178
+ position: absolute;
179
+ inset: 0;
180
+ box-sizing: border-box;
181
+ padding: var(--deck-pad);
182
+ font-size: var(--deck-base-size);
183
+ line-height: 1.4;
184
+ overflow: hidden;
185
+ visibility: hidden;
186
+ pointer-events: none;
187
+ backface-visibility: hidden;
188
+ contain: layout style;
189
+ /* Never transition a slide's own properties: a transition on `visibility` or `transform` would
190
+ outlive the keyframe animation and show the slide that just left, at full opacity, for the
191
+ length of the transition. The keyframes are the only motion a slide gets. */
192
+ transition: none;
193
+ }
194
+ .deck-slide.is-present {
195
+ visibility: visible;
196
+ pointer-events: auto;
197
+ z-index: 2;
198
+ }
199
+ .deck-slide.is-leaving {
200
+ visibility: visible;
201
+ z-index: 1;
202
+ }
203
+ .deck-slide.is-tile,
204
+ .deck-slide.is-scroll,
205
+ .deck-slide.is-print,
206
+ .deck-slide.is-mirror {
207
+ visibility: visible;
208
+ position: absolute;
209
+ }
210
+ .deck-slide.is-scroll {
211
+ pointer-events: auto;
212
+ }
213
+ .deck-slide-loading {
214
+ position: absolute;
215
+ inset: 0;
216
+ }
217
+ .deck-slide-error {
218
+ font: 20px var(--deck-mono-font);
219
+ color: #f43f5e;
220
+ white-space: pre-wrap;
221
+ }
222
+ /* A failed slide is a dead end without these — in the share window there is not even a toolbar. */
223
+ .deck-slide-error-actions {
224
+ display: flex;
225
+ gap: 0.5em;
226
+ margin-top: 1em;
227
+ }
228
+ .deck-slide-error-actions button {
229
+ font: 600 0.5em var(--deck-body-font);
230
+ padding: 0.6em 1.2em;
231
+ border-radius: 999px;
232
+ border: 1px solid var(--deck-border);
233
+ background: var(--deck-surface);
234
+ color: var(--deck-fg);
235
+ cursor: pointer;
236
+ }
237
+ .deck-slide-error-actions button:hover {
238
+ border-color: var(--deck-accent);
239
+ color: var(--deck-accent);
240
+ }
241
+
242
+ /* the layouts */
243
+ .deck-layout {
244
+ position: relative;
245
+ width: 100%;
246
+ height: 100%;
247
+ box-sizing: border-box;
248
+ display: flex;
249
+ flex-direction: column;
250
+ }
251
+ .deck-layout-default {
252
+ justify-content: flex-start;
253
+ }
254
+ .deck-layout-center,
255
+ .deck-layout-cover,
256
+ .deck-layout-intro,
257
+ .deck-layout-section,
258
+ .deck-layout-end,
259
+ .deck-layout-fact,
260
+ .deck-layout-quote,
261
+ .deck-layout-statement {
262
+ justify-content: center;
263
+ }
264
+ .deck-layout-center,
265
+ .deck-layout-fact,
266
+ .deck-layout-statement,
267
+ .deck-layout-end {
268
+ align-items: center;
269
+ text-align: center;
270
+ }
271
+ .deck-layout-fact > :is(h1, h2, p, .deck-counter) {
272
+ font-size: 3em;
273
+ font-weight: 700;
274
+ letter-spacing: -0.02em;
275
+ }
276
+ .deck-layout-quote {
277
+ padding-inline: 8%;
278
+ font-size: 1.4em;
279
+ font-style: italic;
280
+ }
281
+ .deck-layout-full {
282
+ padding: 0;
283
+ }
284
+ .deck-layout-two-cols {
285
+ display: grid;
286
+ grid-template-columns: 1fr 1fr;
287
+ gap: 2em;
288
+ align-items: start;
289
+ align-content: start;
290
+ }
291
+ /* Full-bleed layouts cover the slide's padding box: `inset: 0` already reaches the slide's edges
292
+ (an absolute child ignores the padding), so no negative margin — that overshot by a pad and
293
+ clipped the frame's top and bottom. */
294
+ .deck-layout-image,
295
+ .deck-layout-image-left,
296
+ .deck-layout-image-right,
297
+ .deck-layout-iframe,
298
+ .deck-layout-iframe-left,
299
+ .deck-layout-iframe-right {
300
+ display: grid;
301
+ gap: 0;
302
+ margin: 0;
303
+ width: auto;
304
+ height: auto;
305
+ position: absolute;
306
+ inset: 0;
307
+ }
308
+ .deck-layout-image-left,
309
+ .deck-layout-iframe-left,
310
+ .deck-layout-image-right,
311
+ .deck-layout-iframe-right {
312
+ grid-template-columns: 1fr 1fr;
313
+ }
314
+ .deck-layout-image,
315
+ .deck-layout-iframe {
316
+ grid-template-columns: 1fr;
317
+ }
318
+ .deck-layout-image-pane {
319
+ background-position: center;
320
+ background-repeat: no-repeat;
321
+ min-height: 100%;
322
+ }
323
+ .deck-layout-iframe-pane {
324
+ width: 100%;
325
+ height: 100%;
326
+ border: 0;
327
+ }
328
+ /* An embedded page sits in a framed card with room around it, not flush with the slide's edge. */
329
+ .deck-layout-iframe,
330
+ .deck-layout-iframe-left,
331
+ .deck-layout-iframe-right {
332
+ box-sizing: border-box;
333
+ padding: calc(var(--deck-pad) * 0.5);
334
+ gap: calc(var(--deck-pad) * 0.5);
335
+ }
336
+ .deck-layout-iframe-left .deck-layout-iframe-content,
337
+ .deck-layout-iframe-right .deck-layout-iframe-content {
338
+ padding: calc(var(--deck-pad) * 0.25) calc(var(--deck-pad) * 0.5);
339
+ }
340
+ .deck-frame.deck-layout-iframe-pane {
341
+ border-radius: 16px;
342
+ overflow: hidden;
343
+ border: 1px solid var(--deck-border);
344
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18);
345
+ background: var(--deck-surface);
346
+ }
347
+ .deck-layout-image-content,
348
+ .deck-layout-iframe-content {
349
+ padding: calc(var(--deck-pad) * 0.75) var(--deck-pad);
350
+ display: flex;
351
+ flex-direction: column;
352
+ justify-content: center;
353
+ min-width: 0;
354
+ }
355
+ .deck-layout-iframe-pane,
356
+ .deck-layout-image-pane {
357
+ min-width: 0;
358
+ min-height: 0;
359
+ }
360
+ .deck-layout-image .deck-layout-image-content {
361
+ position: absolute;
362
+ inset: auto 0 0 0;
363
+ background: linear-gradient(transparent, rgba(0, 0, 0, 0.6));
364
+ color: #fff;
365
+ }
366
+
367
+ /* ── slide transitions (the incoming slide animates in, the leaving one out) ── */
368
+ .deck-stage[data-speed="fast"] {
369
+ --deck-transition: 300ms;
370
+ }
371
+ .deck-stage[data-speed="slow"] {
372
+ --deck-transition: 1000ms;
373
+ }
374
+ /* `both`: the incoming slide sits at its first keyframe before the animation starts (no
375
+ one-frame flash at full opacity) and the leaving slide holds its last keyframe until unmounted. */
376
+ .deck-stage:not([data-transition="none"]) .deck-slide.is-present {
377
+ animation: var(--deck-anim-in, none) var(--deck-transition) cubic-bezier(0.26, 0.86, 0.44, 0.985)
378
+ both;
379
+ }
380
+ .deck-stage:not([data-transition="none"]) .deck-slide.is-leaving {
381
+ animation: var(--deck-anim-out, none) var(--deck-transition) cubic-bezier(0.26, 0.86, 0.44, 0.985)
382
+ both;
383
+ }
384
+ .deck-stage[data-transition="fade"] {
385
+ --deck-anim-in: deck-fade-in;
386
+ --deck-anim-out: deck-fade-out;
387
+ }
388
+ .deck-stage[data-transition="slide"][data-direction="forward"],
389
+ .deck-stage[data-transition="slide"][data-direction="none"] {
390
+ --deck-anim-in: deck-slide-in-right;
391
+ --deck-anim-out: deck-slide-out-left;
392
+ }
393
+ .deck-stage[data-transition="slide"][data-direction="back"] {
394
+ --deck-anim-in: deck-slide-in-left;
395
+ --deck-anim-out: deck-slide-out-right;
396
+ }
397
+ .deck-stage[data-transition="slide"][data-direction="down"] {
398
+ --deck-anim-in: deck-slide-in-bottom;
399
+ --deck-anim-out: deck-slide-out-top;
400
+ }
401
+ .deck-stage[data-transition="slide"][data-direction="up"] {
402
+ --deck-anim-in: deck-slide-in-top;
403
+ --deck-anim-out: deck-slide-out-bottom;
404
+ }
405
+ .deck-stage[data-transition="convex"][data-direction="forward"],
406
+ .deck-stage[data-transition="convex"][data-direction="none"] {
407
+ --deck-anim-in: deck-convex-in-right;
408
+ --deck-anim-out: deck-convex-out-left;
409
+ }
410
+ .deck-stage[data-transition="convex"][data-direction="back"] {
411
+ --deck-anim-in: deck-convex-in-left;
412
+ --deck-anim-out: deck-convex-out-right;
413
+ }
414
+ .deck-stage[data-transition="convex"][data-direction="down"],
415
+ .deck-stage[data-transition="convex"][data-direction="up"] {
416
+ --deck-anim-in: deck-fade-in;
417
+ --deck-anim-out: deck-fade-out;
418
+ }
419
+ .deck-stage[data-transition="concave"][data-direction="forward"],
420
+ .deck-stage[data-transition="concave"][data-direction="none"] {
421
+ --deck-anim-in: deck-concave-in-right;
422
+ --deck-anim-out: deck-concave-out-left;
423
+ }
424
+ .deck-stage[data-transition="concave"][data-direction="back"] {
425
+ --deck-anim-in: deck-concave-in-left;
426
+ --deck-anim-out: deck-concave-out-right;
427
+ }
428
+ .deck-stage[data-transition="concave"][data-direction="down"],
429
+ .deck-stage[data-transition="concave"][data-direction="up"] {
430
+ --deck-anim-in: deck-fade-in;
431
+ --deck-anim-out: deck-fade-out;
432
+ }
433
+ .deck-stage[data-transition="zoom"] {
434
+ --deck-anim-in: deck-zoom-in;
435
+ --deck-anim-out: deck-zoom-out;
436
+ }
437
+ .deck-stage[data-transition="zoom"][data-direction="back"] {
438
+ --deck-anim-in: deck-zoom-in-back;
439
+ --deck-anim-out: deck-zoom-out-back;
440
+ }
441
+ .deck-stage[data-transition="view-transition"] {
442
+ --deck-anim-in: none;
443
+ --deck-anim-out: none;
444
+ }
445
+ @keyframes deck-fade-in {
446
+ from {
447
+ opacity: 0;
448
+ }
449
+ }
450
+ @keyframes deck-fade-out {
451
+ to {
452
+ opacity: 0;
453
+ }
454
+ }
455
+ @keyframes deck-slide-in-right {
456
+ from {
457
+ transform: translateX(150%);
458
+ }
459
+ }
460
+ @keyframes deck-slide-out-left {
461
+ to {
462
+ transform: translateX(-150%);
463
+ }
464
+ }
465
+ @keyframes deck-slide-in-left {
466
+ from {
467
+ transform: translateX(-150%);
468
+ }
469
+ }
470
+ @keyframes deck-slide-out-right {
471
+ to {
472
+ transform: translateX(150%);
473
+ }
474
+ }
475
+ @keyframes deck-slide-in-bottom {
476
+ from {
477
+ transform: translateY(150%);
478
+ }
479
+ }
480
+ @keyframes deck-slide-out-top {
481
+ to {
482
+ transform: translateY(-150%);
483
+ }
484
+ }
485
+ @keyframes deck-slide-in-top {
486
+ from {
487
+ transform: translateY(-150%);
488
+ }
489
+ }
490
+ @keyframes deck-slide-out-bottom {
491
+ to {
492
+ transform: translateY(150%);
493
+ }
494
+ }
495
+ @keyframes deck-convex-in-right {
496
+ from {
497
+ transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0);
498
+ }
499
+ }
500
+ @keyframes deck-convex-out-left {
501
+ to {
502
+ transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0);
503
+ }
504
+ }
505
+ @keyframes deck-convex-in-left {
506
+ from {
507
+ transform: translate3d(-100%, 0, 0) rotateY(-90deg) translate3d(-100%, 0, 0);
508
+ }
509
+ }
510
+ @keyframes deck-convex-out-right {
511
+ to {
512
+ transform: translate3d(100%, 0, 0) rotateY(90deg) translate3d(100%, 0, 0);
513
+ }
514
+ }
515
+ @keyframes deck-concave-in-right {
516
+ from {
517
+ transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0);
518
+ }
519
+ }
520
+ @keyframes deck-concave-out-left {
521
+ to {
522
+ transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0);
523
+ }
524
+ }
525
+ @keyframes deck-concave-in-left {
526
+ from {
527
+ transform: translate3d(-100%, 0, 0) rotateY(90deg) translate3d(-100%, 0, 0);
528
+ }
529
+ }
530
+ @keyframes deck-concave-out-right {
531
+ to {
532
+ transform: translate3d(100%, 0, 0) rotateY(-90deg) translate3d(100%, 0, 0);
533
+ }
534
+ }
535
+ @keyframes deck-zoom-in {
536
+ from {
537
+ transform: scale(0.2);
538
+ opacity: 0;
539
+ }
540
+ }
541
+ @keyframes deck-zoom-out {
542
+ to {
543
+ transform: scale(16);
544
+ opacity: 0;
545
+ }
546
+ }
547
+ @keyframes deck-zoom-in-back {
548
+ from {
549
+ transform: scale(16);
550
+ opacity: 0;
551
+ }
552
+ }
553
+ @keyframes deck-zoom-out-back {
554
+ to {
555
+ transform: scale(0.2);
556
+ opacity: 0;
557
+ }
558
+ }
559
+ @media (prefers-reduced-motion: reduce) {
560
+ .deck-stage .deck-slide {
561
+ animation: none !important;
562
+ }
563
+ /* No crossfade at all: the slide that left is hidden at once, and backgrounds swap. */
564
+ .deck-stage .deck-slide.is-leaving {
565
+ visibility: hidden;
566
+ }
567
+ .deck-background {
568
+ transition: none;
569
+ }
570
+ }
571
+
572
+ /* ── clicks (fragments) ──────────────────────────────────────────────────── */
573
+ .deck-click {
574
+ transition:
575
+ opacity 0.4s ease,
576
+ transform 0.4s ease,
577
+ color 0.4s ease,
578
+ filter 0.4s ease;
579
+ }
580
+ .deck-click.is-hidden {
581
+ opacity: 0;
582
+ pointer-events: none;
583
+ }
584
+ .deck-click.effect-fade-up.is-hidden {
585
+ transform: translateY(40px);
586
+ }
587
+ .deck-click.effect-fade-down.is-hidden {
588
+ transform: translateY(-40px);
589
+ }
590
+ .deck-click.effect-fade-left.is-hidden {
591
+ transform: translateX(40px);
592
+ }
593
+ .deck-click.effect-fade-right.is-hidden {
594
+ transform: translateX(-40px);
595
+ }
596
+ .deck-click.effect-fade-out.is-hidden,
597
+ .deck-click.effect-semi-fade-out.is-hidden,
598
+ .deck-click.effect-strike.is-hidden,
599
+ .deck-click.effect-highlight-red.is-hidden,
600
+ .deck-click.effect-highlight-green.is-hidden,
601
+ .deck-click.effect-highlight-blue.is-hidden,
602
+ .deck-click.effect-highlight-current-red.is-hidden,
603
+ .deck-click.effect-highlight-current-green.is-hidden,
604
+ .deck-click.effect-highlight-current-blue.is-hidden,
605
+ .deck-click.effect-grow.is-hidden,
606
+ .deck-click.effect-shrink.is-hidden {
607
+ opacity: 1;
608
+ pointer-events: auto;
609
+ }
610
+ .deck-click.effect-fade-out.is-shown {
611
+ opacity: 0;
612
+ }
613
+ .deck-click.effect-semi-fade-out.is-shown {
614
+ opacity: 0.5;
615
+ }
616
+ .deck-click.effect-grow.is-shown {
617
+ transform: scale(1.2);
618
+ }
619
+ .deck-click.effect-shrink.is-shown {
620
+ transform: scale(0.7);
621
+ }
622
+ .deck-click.effect-strike.is-shown {
623
+ text-decoration: line-through;
624
+ }
625
+ .deck-click.effect-highlight-red.is-shown,
626
+ .deck-click.effect-highlight-current-red.is-current {
627
+ color: #ef4444;
628
+ }
629
+ .deck-click.effect-highlight-green.is-shown,
630
+ .deck-click.effect-highlight-current-green.is-current {
631
+ color: #22c55e;
632
+ }
633
+ .deck-click.effect-highlight-blue.is-shown,
634
+ .deck-click.effect-highlight-current-blue.is-current {
635
+ color: #3b82f6;
636
+ }
637
+ .deck-click.effect-current-visible.is-shown:not(.is-current),
638
+ .deck-click.effect-fade-in-then-out.is-shown:not(.is-current) {
639
+ opacity: 0;
640
+ }
641
+ .deck-click.effect-fade-in-then-semi-out.is-shown:not(.is-current) {
642
+ opacity: 0.5;
643
+ }
644
+ .deck-click.effect-blur.is-hidden {
645
+ opacity: 1;
646
+ filter: blur(6px);
647
+ }
648
+ .deck-click.effect-blur.is-shown {
649
+ filter: none;
650
+ }
651
+ /* In print and the overview, everything is shown: a thumbnail of a slide is of the whole slide.
652
+ `.is-mirror` is deliberately not in this list — the audience's mirror and the presenter's
653
+ next-STEP box are live views of one moment in a slide, and showing them revealed would be
654
+ showing the room the answer before it is given. */
655
+ .is-print .deck-click,
656
+ .is-tile .deck-click {
657
+ opacity: 1 !important;
658
+ transform: none !important;
659
+ filter: none !important;
660
+ }
661
+
662
+ /* ── typography defaults inside slides ───────────────────────────────────── */
663
+ .deck-slide h1,
664
+ .deck-slide h2,
665
+ .deck-slide h3,
666
+ .deck-slide h4 {
667
+ font-family: var(--deck-heading-font);
668
+ line-height: 1.1;
669
+ letter-spacing: -0.02em;
670
+ margin: 0 0 0.5em;
671
+ text-wrap: balance;
672
+ }
673
+ .deck-slide h1 {
674
+ font-size: 2.6em;
675
+ font-weight: 700;
676
+ }
677
+ .deck-slide h2 {
678
+ font-size: 1.9em;
679
+ font-weight: 700;
680
+ }
681
+ .deck-slide h3 {
682
+ font-size: 1.35em;
683
+ font-weight: 600;
684
+ }
685
+ .deck-slide h4 {
686
+ font-size: 1.1em;
687
+ font-weight: 600;
688
+ }
689
+ .deck-slide p {
690
+ margin: 0 0 0.6em;
691
+ }
692
+ .deck-slide ul,
693
+ .deck-slide ol {
694
+ margin: 0 0 0.6em;
695
+ padding-inline-start: 1.2em;
696
+ }
697
+ .deck-slide li {
698
+ margin: 0.15em 0;
699
+ }
700
+ .deck-slide a {
701
+ color: var(--deck-accent);
702
+ text-decoration: underline;
703
+ text-underline-offset: 0.15em;
704
+ }
705
+ .deck-slide blockquote {
706
+ margin: 0.4em 0;
707
+ padding: 0.4em 1em;
708
+ border-inline-start: 4px solid var(--deck-accent);
709
+ color: var(--deck-muted);
710
+ background: var(--deck-surface);
711
+ border-radius: var(--deck-radius);
712
+ }
713
+ .deck-slide table {
714
+ border-collapse: collapse;
715
+ width: 100%;
716
+ font-size: 0.72em;
717
+ line-height: 1.35;
718
+ }
719
+ .deck-slide th,
720
+ .deck-slide td {
721
+ border-bottom: 1px solid var(--deck-border);
722
+ padding: 0.35em 0.6em;
723
+ text-align: start;
724
+ }
725
+ .deck-slide th {
726
+ color: var(--deck-muted);
727
+ font-weight: 600;
728
+ text-transform: uppercase;
729
+ font-size: 0.7em;
730
+ letter-spacing: 0.06em;
731
+ }
732
+ .deck-slide img,
733
+ .deck-slide video,
734
+ .deck-slide iframe {
735
+ max-width: 100%;
736
+ border-radius: var(--deck-radius);
737
+ }
738
+ .deck-slide :not(pre) > code {
739
+ font-family: var(--deck-mono-font);
740
+ font-size: 0.85em;
741
+ background: var(--deck-surface);
742
+ padding: 0.1em 0.35em;
743
+ border-radius: 6px;
744
+ }
745
+ .deck-slide hr {
746
+ border: 0;
747
+ border-top: 1px solid var(--deck-border);
748
+ margin: 1em 0;
749
+ }
750
+ .deck-slide strong {
751
+ font-weight: 700;
752
+ }
753
+
754
+ /* ── code blocks ─────────────────────────────────────────────────────────── */
755
+ .deck-code-block {
756
+ position: relative;
757
+ margin: 0.5em 0;
758
+ border-radius: var(--deck-radius);
759
+ background: var(--deck-code-bg);
760
+ color: var(--deck-code-fg);
761
+ border: 1px solid var(--deck-border);
762
+ overflow: hidden;
763
+ transition: opacity 0.4s ease;
764
+ }
765
+ .deck-code-block.is-hidden {
766
+ opacity: 0;
767
+ }
768
+ .deck-code-title {
769
+ display: flex;
770
+ align-items: center;
771
+ gap: 0.5em;
772
+ padding: 0.35em 1em;
773
+ font: 0.55em var(--deck-mono-font);
774
+ color: var(--deck-muted);
775
+ border-bottom: 1px solid var(--deck-border);
776
+ }
777
+ .deck-code-title-dot {
778
+ width: 0.8em;
779
+ height: 0.8em;
780
+ border-radius: 50%;
781
+ background: var(--deck-accent);
782
+ }
783
+ pre.deck-code {
784
+ margin: 0;
785
+ padding: 0.7em 0;
786
+ font: 0.6em/1.6 var(--deck-mono-font);
787
+ overflow: auto;
788
+ tab-size: 2;
789
+ background: transparent !important;
790
+ }
791
+ pre.deck-code code {
792
+ display: block;
793
+ min-width: 100%;
794
+ width: max-content;
795
+ }
796
+ pre.deck-code .line {
797
+ display: inline-block;
798
+ width: 100%;
799
+ box-sizing: border-box;
800
+ padding: 0 1.2em;
801
+ transition:
802
+ opacity 0.3s ease,
803
+ background 0.3s ease;
804
+ }
805
+ pre.deck-code .line.is-dim {
806
+ opacity: 0.35;
807
+ }
808
+ pre.deck-code .line.is-active {
809
+ background: var(--deck-code-active);
810
+ }
811
+ pre.deck-code.has-lines .line::before {
812
+ counter-increment: line;
813
+ content: counter(line);
814
+ display: inline-block;
815
+ width: 2.2em;
816
+ margin-inline-start: -0.4em;
817
+ color: var(--deck-muted);
818
+ opacity: 0.6;
819
+ text-align: end;
820
+ padding-inline-end: 1em;
821
+ user-select: none;
822
+ }
823
+ [data-color-scheme="light"] .shiki,
824
+ [data-color-scheme="light"] .shiki span {
825
+ color: var(--shiki-light, inherit);
826
+ }
827
+ [data-color-scheme="dark"] .shiki,
828
+ [data-color-scheme="dark"] .shiki span {
829
+ color: var(--shiki-dark, inherit);
830
+ }
831
+ .deck-code-copy {
832
+ position: absolute;
833
+ top: 0.4em;
834
+ right: 0.5em;
835
+ font: 0.45em var(--deck-mono-font);
836
+ padding: 0.3em 0.7em;
837
+ border-radius: 6px;
838
+ border: 1px solid var(--deck-border);
839
+ background: var(--deck-bg);
840
+ color: var(--deck-muted);
841
+ opacity: 0;
842
+ cursor: pointer;
843
+ transition: opacity 0.2s;
844
+ }
845
+ .deck-code-block.has-title .deck-code-copy {
846
+ top: 0.3em;
847
+ }
848
+ .deck-code-block:hover .deck-code-copy {
849
+ opacity: 1;
850
+ }
851
+ .shiki-magic-move-wrap {
852
+ padding: 0.7em 1.2em;
853
+ }
854
+ .shiki-magic-move-container {
855
+ font: inherit;
856
+ }
857
+
858
+ /* ── helpers ─────────────────────────────────────────────────────────────── */
859
+ .deck-stack {
860
+ display: grid;
861
+ place-items: center;
862
+ }
863
+ .deck-stack > * {
864
+ grid-area: 1 / 1;
865
+ }
866
+ .deck-layout > .deck-stretch,
867
+ .deck-stretch {
868
+ flex: 1 1 auto;
869
+ min-height: 0;
870
+ display: flex;
871
+ flex-direction: column;
872
+ }
873
+ .deck-stretch > :is(img, video, iframe) {
874
+ flex: 1;
875
+ min-height: 0;
876
+ object-fit: contain;
877
+ width: 100%;
878
+ }
879
+ .deck-cols,
880
+ .deck-grid {
881
+ display: grid;
882
+ width: 100%;
883
+ }
884
+ /* A ROW OF CARDS ENDS ON ONE LINE. A grid stretches its cells, not what is in them: two cards with
885
+ different amounts of text sat in equal cells at unequal heights. So a card that is the only
886
+ thing in its cell — a column, or the step wrapper that reveals it — fills the cell. Nothing
887
+ changes where the author asked otherwise (`<Cols align="start">` does not stretch its cells, so
888
+ there is nothing to fill), nor for a card that shares its column with other content. A deck's own
889
+ card components join in with the `deck-card` class. */
890
+ :is(.deck-col, div.deck-click):has(> :is(.deck-glass, .deck-callout, .deck-card):only-child) {
891
+ display: flex;
892
+ flex-direction: column;
893
+ }
894
+ :is(.deck-col, div.deck-click) > :is(.deck-glass, .deck-callout, .deck-card):only-child {
895
+ flex: 1 1 auto;
896
+ }
897
+ /* …and through both at once: a column whose one child is the step that reveals its one card. */
898
+ .deck-col:has(
899
+ > div.deck-click:only-child > :is(.deck-glass, .deck-callout, .deck-card):only-child
900
+ ) {
901
+ display: flex;
902
+ flex-direction: column;
903
+ }
904
+ .deck-col
905
+ > div.deck-click:only-child:has(> :is(.deck-glass, .deck-callout, .deck-card):only-child) {
906
+ flex: 1 1 auto;
907
+ }
908
+ .deck-center {
909
+ display: flex;
910
+ flex-direction: column;
911
+ align-items: center;
912
+ justify-content: center;
913
+ text-align: center;
914
+ height: 100%;
915
+ }
916
+ .deck-frame {
917
+ border: 4px solid var(--deck-border);
918
+ box-shadow: 0 0 40px rgba(0, 0, 0, 0.15);
919
+ border-radius: var(--deck-radius);
920
+ }
921
+ .deck-transform {
922
+ width: fit-content;
923
+ }
924
+ .deck-absolute {
925
+ position: absolute;
926
+ }
927
+ .deck-fit-text {
928
+ width: 100%;
929
+ line-height: 1;
930
+ }
931
+ .deck-kbd {
932
+ font: 0.75em var(--deck-mono-font);
933
+ border: 1px solid var(--deck-border);
934
+ border-bottom-width: 3px;
935
+ border-radius: 6px;
936
+ padding: 0.05em 0.45em;
937
+ background: var(--deck-surface);
938
+ }
939
+ .deck-badge {
940
+ display: inline-block;
941
+ font-size: 0.55em;
942
+ font-weight: 600;
943
+ letter-spacing: 0.06em;
944
+ text-transform: uppercase;
945
+ padding: 0.25em 0.7em;
946
+ border-radius: 999px;
947
+ border: 1px solid var(--deck-border);
948
+ vertical-align: middle;
949
+ }
950
+ .deck-badge.tone-accent {
951
+ color: var(--deck-accent);
952
+ border-color: currentColor;
953
+ }
954
+ .deck-badge.tone-good {
955
+ color: #16a34a;
956
+ border-color: currentColor;
957
+ }
958
+ .deck-badge.tone-warn {
959
+ color: #d97706;
960
+ border-color: currentColor;
961
+ }
962
+ .deck-badge.tone-bad {
963
+ color: #dc2626;
964
+ border-color: currentColor;
965
+ }
966
+ .deck-callout {
967
+ margin: 0.5em 0;
968
+ padding: 0.6em 1em;
969
+ border-radius: var(--deck-radius);
970
+ border: 1px solid var(--deck-border);
971
+ border-inline-start-width: 6px;
972
+ background: var(--deck-surface);
973
+ font-size: 0.85em;
974
+ }
975
+ .deck-callout.kind-info {
976
+ border-inline-start-color: var(--deck-accent);
977
+ }
978
+ .deck-callout.kind-tip {
979
+ border-inline-start-color: #16a34a;
980
+ }
981
+ .deck-callout.kind-warn {
982
+ border-inline-start-color: #d97706;
983
+ }
984
+ .deck-callout.kind-danger {
985
+ border-inline-start-color: #dc2626;
986
+ }
987
+ .deck-callout-title {
988
+ display: block;
989
+ margin-bottom: 0.2em;
990
+ }
991
+ .deck-counter {
992
+ font-variant-numeric: tabular-nums;
993
+ }
994
+ .deck-typewriter-cursor {
995
+ animation: deck-blink 1s steps(2) infinite;
996
+ }
997
+ @keyframes deck-blink {
998
+ to {
999
+ opacity: 0;
1000
+ }
1001
+ }
1002
+ .deck-timer {
1003
+ font-variant-numeric: tabular-nums;
1004
+ font-family: var(--deck-mono-font);
1005
+ }
1006
+ .deck-timer.is-done {
1007
+ color: #dc2626;
1008
+ }
1009
+ .deck-mark {
1010
+ position: relative;
1011
+ display: inline;
1012
+ }
1013
+ .deck-mark::after {
1014
+ content: "";
1015
+ position: absolute;
1016
+ pointer-events: none;
1017
+ opacity: 0;
1018
+ transition: opacity 0.35s ease;
1019
+ }
1020
+ .deck-mark.is-on::after {
1021
+ opacity: 1;
1022
+ }
1023
+ .deck-mark.type-underline::after {
1024
+ left: 0;
1025
+ right: 0;
1026
+ bottom: -0.05em;
1027
+ height: 0.15em;
1028
+ background: var(--mark-color);
1029
+ border-radius: 2px;
1030
+ transform: rotate(-0.6deg);
1031
+ }
1032
+ .deck-mark.type-highlight::after {
1033
+ inset: -0.05em -0.15em;
1034
+ background: color-mix(in oklab, var(--mark-color) 35%, transparent);
1035
+ border-radius: 4px;
1036
+ z-index: -1;
1037
+ }
1038
+ .deck-mark.type-box::after,
1039
+ .deck-mark.type-circle::after {
1040
+ inset: -0.2em -0.4em;
1041
+ border: 3px solid var(--mark-color);
1042
+ border-radius: 6px;
1043
+ }
1044
+ .deck-mark.type-circle::after {
1045
+ border-radius: 50% / 45%;
1046
+ transform: rotate(-2deg);
1047
+ }
1048
+ .deck-mark.type-strike::after {
1049
+ left: 0;
1050
+ right: 0;
1051
+ top: 50%;
1052
+ height: 0.12em;
1053
+ background: var(--mark-color);
1054
+ transform: rotate(-1.5deg);
1055
+ }
1056
+ .deck-confetti {
1057
+ position: absolute;
1058
+ inset: 0;
1059
+ width: 100%;
1060
+ height: 100%;
1061
+ pointer-events: none;
1062
+ }
1063
+ .deck-slide-background {
1064
+ /* covers the whole slide, padding included: the layout box plus a pad on every side */
1065
+ position: absolute;
1066
+ inset: calc(var(--deck-pad) * -1);
1067
+ z-index: 0;
1068
+ pointer-events: none;
1069
+ overflow: hidden;
1070
+ }
1071
+ .deck-slide-background > * {
1072
+ width: 100%;
1073
+ height: 100%;
1074
+ }
1075
+ .deck-toc {
1076
+ list-style: none;
1077
+ padding: 0;
1078
+ margin: 0;
1079
+ column-gap: 2em;
1080
+ }
1081
+ .deck-toc li {
1082
+ margin: 0.2em 0;
1083
+ break-inside: avoid;
1084
+ }
1085
+ .deck-toc li.is-current > a {
1086
+ color: var(--deck-accent);
1087
+ font-weight: 700;
1088
+ }
1089
+ .deck-toc li.is-past > a {
1090
+ color: var(--deck-muted);
1091
+ }
1092
+ .deck-toc a {
1093
+ text-decoration: none;
1094
+ color: inherit;
1095
+ }
1096
+ .deck-toc .level-2 {
1097
+ font-size: 0.85em;
1098
+ }
1099
+ .deck-toc .level-3 {
1100
+ font-size: 0.75em;
1101
+ }
1102
+ .deck-math .katex-display {
1103
+ margin: 0.4em 0;
1104
+ }
1105
+ .deck-mermaid svg {
1106
+ max-width: 100%;
1107
+ height: auto;
1108
+ }
1109
+ .deck-qr {
1110
+ border-radius: 8px;
1111
+ background: #fff;
1112
+ padding: 6px;
1113
+ }
1114
+ .deck-iframe {
1115
+ border: 0;
1116
+ width: 100%;
1117
+ height: 100%;
1118
+ }
1119
+
1120
+ /* ── chrome ──────────────────────────────────────────────────────────────── */
1121
+ .deck-controls {
1122
+ position: absolute;
1123
+ z-index: 20;
1124
+ display: grid;
1125
+ grid-template-columns: repeat(3, 44px);
1126
+ grid-template-rows: repeat(3, 44px);
1127
+ gap: 2px;
1128
+ --deck-controls-color: var(--deck-accent);
1129
+ }
1130
+ .deck-controls.layout-bottom-right {
1131
+ right: 12px;
1132
+ bottom: 12px;
1133
+ }
1134
+ .deck-controls.layout-edges {
1135
+ inset: 0;
1136
+ display: block;
1137
+ pointer-events: none;
1138
+ }
1139
+ .deck-control {
1140
+ appearance: none;
1141
+ border: 0;
1142
+ background: transparent;
1143
+ width: 44px;
1144
+ height: 44px;
1145
+ padding: 0;
1146
+ cursor: pointer;
1147
+ opacity: 0.1;
1148
+ transition:
1149
+ opacity 0.2s,
1150
+ transform 0.2s;
1151
+ display: grid;
1152
+ place-items: center;
1153
+ pointer-events: auto;
1154
+ }
1155
+ .deck-control span {
1156
+ width: 14px;
1157
+ height: 14px;
1158
+ border-top: 3px solid var(--deck-controls-color);
1159
+ border-right: 3px solid var(--deck-controls-color);
1160
+ display: block;
1161
+ }
1162
+ .deck-control-left span {
1163
+ transform: rotate(-135deg);
1164
+ }
1165
+ .deck-control-right span {
1166
+ transform: rotate(45deg);
1167
+ }
1168
+ .deck-control-up span {
1169
+ transform: rotate(-45deg);
1170
+ }
1171
+ .deck-control-down span {
1172
+ transform: rotate(135deg);
1173
+ }
1174
+ .deck-control.is-enabled {
1175
+ opacity: 0.9;
1176
+ }
1177
+ .deck-control.is-enabled.is-faded {
1178
+ opacity: 0.35;
1179
+ }
1180
+ .deck-control.is-enabled:hover {
1181
+ transform: scale(1.15);
1182
+ opacity: 1;
1183
+ }
1184
+ .deck-control:disabled {
1185
+ cursor: default;
1186
+ }
1187
+ .deck-control.is-highlight span {
1188
+ animation: deck-bounce 1.2s ease infinite;
1189
+ }
1190
+ @keyframes deck-bounce {
1191
+ 50% {
1192
+ transform: rotate(45deg) translate(3px, -3px);
1193
+ }
1194
+ }
1195
+ .deck-controls.layout-bottom-right .deck-control-left {
1196
+ grid-area: 2 / 1;
1197
+ }
1198
+ .deck-controls.layout-bottom-right .deck-control-right {
1199
+ grid-area: 2 / 3;
1200
+ }
1201
+ .deck-controls.layout-bottom-right .deck-control-up {
1202
+ grid-area: 1 / 2;
1203
+ }
1204
+ .deck-controls.layout-bottom-right .deck-control-down {
1205
+ grid-area: 3 / 2;
1206
+ }
1207
+ .deck-controls.layout-edges .deck-control {
1208
+ position: absolute;
1209
+ }
1210
+ .deck-controls.layout-edges .deck-control-left {
1211
+ left: 8px;
1212
+ top: 50%;
1213
+ margin-top: -22px;
1214
+ }
1215
+ .deck-controls.layout-edges .deck-control-right {
1216
+ right: 8px;
1217
+ top: 50%;
1218
+ margin-top: -22px;
1219
+ }
1220
+ .deck-controls.layout-edges .deck-control-up {
1221
+ top: 8px;
1222
+ left: 50%;
1223
+ margin-left: -22px;
1224
+ }
1225
+ .deck-controls.layout-edges .deck-control-down {
1226
+ bottom: 8px;
1227
+ left: 50%;
1228
+ margin-left: -22px;
1229
+ }
1230
+ .deck-progress {
1231
+ position: absolute;
1232
+ left: 0;
1233
+ right: 0;
1234
+ bottom: 0;
1235
+ height: 4px;
1236
+ z-index: 20;
1237
+ background: var(--deck-surface);
1238
+ cursor: pointer;
1239
+ }
1240
+ .deck-progress span {
1241
+ display: block;
1242
+ height: 100%;
1243
+ background: linear-gradient(90deg, var(--deck-accent), var(--deck-accent-2));
1244
+ transform-origin: 0 0;
1245
+ transition: transform 0.4s ease;
1246
+ }
1247
+ .deck-slide-number {
1248
+ position: absolute;
1249
+ right: 14px;
1250
+ bottom: 12px;
1251
+ z-index: 20;
1252
+ font: 14px var(--deck-mono-font);
1253
+ color: var(--deck-muted);
1254
+ text-decoration: none;
1255
+ background: var(--deck-surface);
1256
+ padding: 4px 8px;
1257
+ border-radius: 6px;
1258
+ }
1259
+ .deck-controls.layout-bottom-right ~ .deck-slide-number {
1260
+ right: 160px;
1261
+ }
1262
+ .deck-pause-curtain {
1263
+ position: absolute;
1264
+ inset: 0;
1265
+ z-index: 60;
1266
+ background: #000;
1267
+ opacity: 0;
1268
+ pointer-events: none;
1269
+ transition: opacity 0.3s;
1270
+ display: grid;
1271
+ place-items: end center;
1272
+ color: #444;
1273
+ font: 14px var(--deck-mono-font);
1274
+ padding-bottom: 24px;
1275
+ }
1276
+ .deck-pause-curtain[data-on] {
1277
+ opacity: 1;
1278
+ pointer-events: auto;
1279
+ }
1280
+ /* The same curtain over the slide in someone's hand. Smaller, and it never takes a tap: the
1281
+ viewer cannot lift a blackout, and swiping to another slide must still work under it. */
1282
+ .deck-pause-curtain.is-audience {
1283
+ font-size: 12px;
1284
+ padding-bottom: 10px;
1285
+ }
1286
+ .deck-pause-curtain.is-audience[data-on] {
1287
+ pointer-events: none;
1288
+ }
1289
+ .deck-sheet {
1290
+ position: absolute;
1291
+ inset: 0;
1292
+ z-index: 70;
1293
+ background: rgba(0, 0, 0, 0.55);
1294
+ backdrop-filter: blur(6px);
1295
+ display: grid;
1296
+ place-items: center;
1297
+ }
1298
+ .deck-sheet-panel {
1299
+ background: var(--deck-bg);
1300
+ color: var(--deck-fg);
1301
+ border: 1px solid var(--deck-border);
1302
+ border-radius: 16px;
1303
+ padding: 24px 28px;
1304
+ width: min(640px, 92vw);
1305
+ max-height: 84vh;
1306
+ overflow: auto;
1307
+ box-shadow: 0 30px 80px rgba(0, 0, 0, 0.4);
1308
+ font-size: 15px;
1309
+ }
1310
+ .deck-sheet-panel h2 {
1311
+ margin: 0 0 12px;
1312
+ font-size: 18px;
1313
+ }
1314
+ .deck-sheet-panel table {
1315
+ width: 100%;
1316
+ border-collapse: collapse;
1317
+ }
1318
+ .deck-sheet-panel td {
1319
+ padding: 5px 8px;
1320
+ border-bottom: 1px solid var(--deck-border);
1321
+ }
1322
+ .deck-sheet-panel kbd {
1323
+ font: 12px var(--deck-mono-font);
1324
+ border: 1px solid var(--deck-border);
1325
+ border-radius: 5px;
1326
+ padding: 2px 6px;
1327
+ background: var(--deck-surface);
1328
+ }
1329
+ .deck-sheet-hint {
1330
+ color: var(--deck-muted);
1331
+ font-size: 12px;
1332
+ margin: 12px 0 0;
1333
+ }
1334
+ .deck-sheet input,
1335
+ .deck-jump input {
1336
+ width: 100%;
1337
+ box-sizing: border-box;
1338
+ font: 18px var(--deck-body-font);
1339
+ padding: 12px 14px;
1340
+ border-radius: 10px;
1341
+ border: 1px solid var(--deck-border);
1342
+ background: var(--deck-surface);
1343
+ color: var(--deck-fg);
1344
+ outline: none;
1345
+ }
1346
+ .deck-search ul {
1347
+ list-style: none;
1348
+ margin: 12px 0 0;
1349
+ padding: 0;
1350
+ display: flex;
1351
+ flex-direction: column;
1352
+ gap: 4px;
1353
+ }
1354
+ .deck-search button {
1355
+ width: 100%;
1356
+ text-align: start;
1357
+ background: transparent;
1358
+ border: 0;
1359
+ color: inherit;
1360
+ padding: 10px 12px;
1361
+ border-radius: 8px;
1362
+ cursor: pointer;
1363
+ display: flex;
1364
+ flex-direction: column;
1365
+ gap: 2px;
1366
+ font: inherit;
1367
+ }
1368
+ .deck-search button:hover {
1369
+ background: var(--deck-surface);
1370
+ }
1371
+ .deck-search button span {
1372
+ color: var(--deck-muted);
1373
+ font-size: 13px;
1374
+ }
1375
+ .deck-search-empty {
1376
+ color: var(--deck-muted);
1377
+ padding: 10px 12px;
1378
+ }
1379
+ .deck-jump {
1380
+ position: absolute;
1381
+ z-index: 70;
1382
+ left: 50%;
1383
+ bottom: 40px;
1384
+ transform: translateX(-50%);
1385
+ width: 320px;
1386
+ }
1387
+ .deck-toast {
1388
+ position: absolute;
1389
+ z-index: 80;
1390
+ left: 50%;
1391
+ top: 24px;
1392
+ transform: translate(-50%, -20px);
1393
+ background: var(--deck-fg);
1394
+ color: var(--deck-bg);
1395
+ padding: 8px 14px;
1396
+ border-radius: 999px;
1397
+ font-size: 14px;
1398
+ opacity: 0;
1399
+ pointer-events: none;
1400
+ transition:
1401
+ opacity 0.2s,
1402
+ transform 0.2s;
1403
+ }
1404
+ .deck-toast[data-on] {
1405
+ opacity: 1;
1406
+ transform: translate(-50%, 0);
1407
+ }
1408
+ .deck-notes-footer {
1409
+ position: absolute;
1410
+ left: 0;
1411
+ right: 0;
1412
+ bottom: 0;
1413
+ z-index: 15;
1414
+ max-height: 30%;
1415
+ overflow: auto;
1416
+ background: rgba(0, 0, 0, 0.7);
1417
+ color: #fff;
1418
+ padding: 12px 20px;
1419
+ font-size: 16px;
1420
+ backdrop-filter: blur(6px);
1421
+ }
1422
+ .deck-lightbox {
1423
+ position: absolute;
1424
+ inset: 0;
1425
+ z-index: 90;
1426
+ background: rgba(0, 0, 0, 0.9);
1427
+ display: grid;
1428
+ place-items: center;
1429
+ }
1430
+ .deck-lightbox-media {
1431
+ width: 90vw;
1432
+ height: 88vh;
1433
+ display: grid;
1434
+ place-items: center;
1435
+ }
1436
+ .deck-lightbox-media > * {
1437
+ max-width: 100%;
1438
+ max-height: 100%;
1439
+ border-radius: 8px;
1440
+ }
1441
+ .deck-lightbox-media[data-fit="contain"] > :is(img, video) {
1442
+ width: 100%;
1443
+ height: 100%;
1444
+ object-fit: contain;
1445
+ }
1446
+ .deck-lightbox-media[data-fit="cover"] > :is(img, video) {
1447
+ width: 100%;
1448
+ height: 100%;
1449
+ object-fit: cover;
1450
+ }
1451
+ .deck-lightbox-media iframe {
1452
+ width: 100%;
1453
+ height: 100%;
1454
+ border: 0;
1455
+ background: #fff;
1456
+ }
1457
+ .deck-lightbox-close {
1458
+ position: absolute;
1459
+ top: 16px;
1460
+ right: 20px;
1461
+ background: transparent;
1462
+ color: #fff;
1463
+ border: 0;
1464
+ font-size: 36px;
1465
+ cursor: pointer;
1466
+ }
1467
+
1468
+ /* ── overview ────────────────────────────────────────────────────────────── */
1469
+ .deck-overview {
1470
+ position: absolute;
1471
+ inset: 0;
1472
+ z-index: 50;
1473
+ background: rgba(0, 0, 0, 0.82);
1474
+ backdrop-filter: blur(8px);
1475
+ overflow: auto;
1476
+ padding: 40px;
1477
+ }
1478
+ .deck-overview-grid {
1479
+ display: flex;
1480
+ gap: 24px;
1481
+ align-items: flex-start;
1482
+ min-height: 100%;
1483
+ }
1484
+ .deck-overview-column {
1485
+ display: flex;
1486
+ flex-direction: column;
1487
+ gap: 16px;
1488
+ }
1489
+ .deck-overview-tile {
1490
+ position: relative;
1491
+ border: 2px solid rgba(255, 255, 255, 0.15);
1492
+ border-radius: 8px;
1493
+ padding: 0;
1494
+ background: var(--deck-bg);
1495
+ overflow: hidden;
1496
+ cursor: pointer;
1497
+ flex: none;
1498
+ transition:
1499
+ transform 0.15s,
1500
+ border-color 0.15s;
1501
+ }
1502
+ .deck-overview-tile:hover {
1503
+ transform: scale(1.03);
1504
+ }
1505
+ .deck-overview-tile.is-current {
1506
+ border-color: var(--deck-accent);
1507
+ box-shadow: 0 0 0 4px color-mix(in oklab, var(--deck-accent) 40%, transparent);
1508
+ }
1509
+ .deck-overview-canvas {
1510
+ position: absolute;
1511
+ left: 0;
1512
+ top: 0;
1513
+ transform-origin: 0 0;
1514
+ pointer-events: none;
1515
+ }
1516
+ .deck-overview-label {
1517
+ position: absolute;
1518
+ left: 0;
1519
+ right: 0;
1520
+ bottom: 0;
1521
+ font: 11px var(--deck-mono-font);
1522
+ color: #fff;
1523
+ background: rgba(0, 0, 0, 0.6);
1524
+ padding: 3px 6px;
1525
+ text-align: start;
1526
+ white-space: nowrap;
1527
+ overflow: hidden;
1528
+ text-overflow: ellipsis;
1529
+ }
1530
+
1531
+ /* ── scroll view ─────────────────────────────────────────────────────────── */
1532
+ .deck-scroll {
1533
+ position: absolute;
1534
+ inset: 0;
1535
+ z-index: 1;
1536
+ overflow-y: auto;
1537
+ overflow-x: hidden;
1538
+ scroll-behavior: smooth;
1539
+ }
1540
+ .deck-scroll[data-snap="mandatory"] {
1541
+ scroll-snap-type: y mandatory;
1542
+ }
1543
+ .deck-scroll[data-snap="proximity"] {
1544
+ scroll-snap-type: y proximity;
1545
+ }
1546
+ .deck-scroll-segment {
1547
+ position: relative;
1548
+ scroll-snap-align: start;
1549
+ }
1550
+ .deck-scroll-sticky {
1551
+ position: sticky;
1552
+ top: 0;
1553
+ width: 100%;
1554
+ overflow: hidden;
1555
+ }
1556
+ .deck-scroll-canvas {
1557
+ position: absolute;
1558
+ left: 0;
1559
+ top: 0;
1560
+ transform-origin: 0 0;
1561
+ }
1562
+ .deck-scrollbar {
1563
+ position: fixed;
1564
+ right: 6px;
1565
+ top: 12px;
1566
+ bottom: 12px;
1567
+ width: 6px;
1568
+ display: flex;
1569
+ flex-direction: column;
1570
+ gap: 3px;
1571
+ z-index: 30;
1572
+ opacity: 0.6;
1573
+ }
1574
+ .deck-scrollbar span {
1575
+ display: block;
1576
+ background: var(--deck-border);
1577
+ border-radius: 3px;
1578
+ }
1579
+ .deck-scrollbar span.is-current {
1580
+ background: var(--deck-accent);
1581
+ }
1582
+
1583
+ /* ── print ───────────────────────────────────────────────────────────────── */
1584
+ .deck-print .deck-root,
1585
+ .deck-print body,
1586
+ .deck-print html {
1587
+ height: auto;
1588
+ overflow: visible;
1589
+ }
1590
+ .deck-print-pages {
1591
+ margin: 0 auto;
1592
+ }
1593
+ .deck-print-page {
1594
+ position: relative;
1595
+ overflow: hidden;
1596
+ page-break-after: always;
1597
+ break-after: page;
1598
+ background: var(--deck-bg);
1599
+ }
1600
+ .deck-print-page .deck-background {
1601
+ position: absolute;
1602
+ inset: 0;
1603
+ }
1604
+ .deck-print-page .deck-slide {
1605
+ position: absolute;
1606
+ inset: 0;
1607
+ }
1608
+ .deck-print-notes {
1609
+ position: absolute;
1610
+ left: 24px;
1611
+ right: 24px;
1612
+ bottom: 24px;
1613
+ max-height: 30%;
1614
+ overflow: hidden;
1615
+ background: rgba(255, 255, 255, 0.92);
1616
+ color: #111;
1617
+ padding: 16px 20px;
1618
+ border-radius: 10px;
1619
+ font-size: 20px;
1620
+ box-shadow: 0 4px 24px rgba(0, 0, 0, 0.2);
1621
+ }
1622
+ .deck-print-notes.is-full {
1623
+ position: static;
1624
+ max-height: none;
1625
+ padding: 80px;
1626
+ font-size: 28px;
1627
+ background: transparent;
1628
+ box-shadow: none;
1629
+ }
1630
+ @media screen {
1631
+ .deck-print-pages {
1632
+ padding: 16px 0;
1633
+ }
1634
+ .deck-print-page {
1635
+ margin: 0 auto 16px;
1636
+ box-shadow: 0 6px 28px rgba(0, 0, 0, 0.25);
1637
+ }
1638
+ }
1639
+ @media print {
1640
+ .deck-print-pages {
1641
+ zoom: 1 !important;
1642
+ padding: 0;
1643
+ }
1644
+ .deck-print-page {
1645
+ margin: 0;
1646
+ box-shadow: none;
1647
+ }
1648
+ .deck-controls,
1649
+ .deck-progress,
1650
+ .deck-scrollbar {
1651
+ display: none !important;
1652
+ }
1653
+ }
1654
+
1655
+ /* a slide that forces its own scheme repaints its text: `color` inherited from the body was
1656
+ resolved with the root's tokens, so it has to be re-read here */
1657
+ .deck-slide[data-color-scheme] {
1658
+ color: var(--deck-fg);
1659
+ }
1660
+
1661
+ /* named slots (`::right::` in a slide): the two-cols layout places them, others stack them */
1662
+ .deck-layout-two-cols > .deck-slot-default {
1663
+ grid-column: 1;
1664
+ }
1665
+ .deck-layout-two-cols > .deck-slot-right {
1666
+ grid-column: 2;
1667
+ }
1668
+ .deck-layout-two-cols > .deck-slot-default,
1669
+ .deck-layout-two-cols > .deck-slot-right {
1670
+ grid-row: 1;
1671
+ min-width: 0;
1672
+ }
1673
+ .deck-layout-two-cols > .deck-slot-bottom {
1674
+ grid-column: 1 / -1;
1675
+ }
1676
+
1677
+ /* "Made with Kadal Deck": the free-plan badge, bottom-left, out of the way of the slide number. */
1678
+ .deck-made-with {
1679
+ position: absolute;
1680
+ left: 14px;
1681
+ bottom: 12px;
1682
+ z-index: 20;
1683
+ font: 12px/1 var(--deck-body-font, system-ui, sans-serif);
1684
+ color: var(--deck-muted);
1685
+ text-decoration: none;
1686
+ background: var(--deck-surface);
1687
+ padding: 6px 9px;
1688
+ border-radius: 6px;
1689
+ opacity: 0.72;
1690
+ transition: opacity 0.2s ease;
1691
+ }
1692
+ .deck-made-with:hover,
1693
+ .deck-made-with:focus-visible {
1694
+ opacity: 1;
1695
+ color: var(--deck-fg);
1696
+ }
1697
+ .deck-made-with strong {
1698
+ font-weight: 600;
1699
+ }
1700
+ @media print {
1701
+ .deck-made-with {
1702
+ display: none;
1703
+ }
1704
+ }