fb-slides 0.5.1 → 0.6.2

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.
@@ -310,9 +310,9 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
310
310
  /* Full-bleed: this one is the demo, not a slide about the demo. */
311
311
  margin: 0;
312
312
  box-sizing: border-box;
313
- /* The toolbar, arrows and signature live in fixed viewport space along the
314
- bottom, where a full-height slide runs under them. Reserve that strip:
315
- 66px of viewport clears the toolbar (bottom 14px + 44px chip + air), minus
313
+ /* The arrows and signature live in fixed viewport space along the bottom,
314
+ where a full-height slide runs under them. Reserve that strip:
315
+ 66px of viewport clears them (bottom 14px + 44px of chrome + air), minus
316
316
  the letterbox gap the slide already has, converted to slide space through
317
317
  reveal's own scale. On tall windows the gap alone is enough and this
318
318
  resolves to zero. */
@@ -354,6 +354,170 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
354
354
  box-shadow: 0 18px 45px rgb(0 0 0 / 0.45);
355
355
  }
356
356
 
357
+ /* --- the slide vocabulary ------------------------------------------------ */
358
+ /* The classes a slide's Markdown can reach for, so the common layouts are a
359
+ word rather than a paragraph of inline styles. Every one of them is layout
360
+ only — no content, no colours of its own — and every number it fixes is a
361
+ token, so a project retunes it from its own theme.css instead of copying
362
+ this CSS. The edit drawer's `+` inserts the markup for each (snippets.js). */
363
+
364
+ /* Images and clips are centred, and lose the white card reveal's core CSS
365
+ gives every image: a screenshot on a dark slide wants no frame around it. */
366
+ .reveal .slides section img {
367
+ display: block;
368
+ max-width: 100%;
369
+ margin: 0.4em auto;
370
+ background: none;
371
+ border: 0;
372
+ border-radius: 10px;
373
+ }
374
+ .reveal .slides section video {
375
+ display: block;
376
+ max-width: 100%;
377
+ margin: 0.4em auto;
378
+ border-radius: 10px;
379
+ }
380
+
381
+ /* Two columns. `min-width: 0` on the children is the whole point: a flex item
382
+ is min-content wide by default, and a <pre> refuses to shrink — one code
383
+ block and the pair walks off the slide. */
384
+ .reveal .slides .cols {
385
+ display: flex;
386
+ gap: var(--cols-gap, 2rem);
387
+ align-items: var(--cols-align, flex-start);
388
+ }
389
+ /* Any direct child is a column; `style="flex: 1.4"` on one still tips the
390
+ balance, because the shorthand here sets the same property it does. */
391
+ .reveal .slides .cols > * { flex: 1 1 0; min-width: 0; }
392
+
393
+ /* An embedded page that is not the whole slide. The height is in px, not vh:
394
+ the slide is a fixed 1280x720 box reveal scales as a whole, so a viewport
395
+ unit here would size against the window instead of against the slide. */
396
+ .reveal .slides .frame { display: flex; justify-content: center; }
397
+ .reveal .slides .frame iframe {
398
+ width: var(--frame-w, min(860px, 100%));
399
+ height: var(--frame-h, 500px);
400
+ border: 0;
401
+ border-radius: 10px;
402
+ /* Most embeds assume a white page under them and draw nothing of their own. */
403
+ background: var(--frame-bg, #fff);
404
+ box-shadow: 0 18px 40px rgb(0 0 0 / 0.35);
405
+ }
406
+
407
+ /* A line under a figure, or an aside that should not carry the same weight as
408
+ the sentence above it. */
409
+ .reveal .slides .caption {
410
+ margin: 0.4em 0 0;
411
+ font-size: 0.8em;
412
+ line-height: 1.5;
413
+ color: var(--muted);
414
+ }
415
+
416
+ /* A bordered block: the point a slide keeps coming back to. */
417
+ .reveal .slides .box {
418
+ padding: 0.7em 1.05em;
419
+ border: 1px solid var(--box-line, var(--line));
420
+ border-radius: 10px;
421
+ background: color-mix(in srgb, var(--card) 55%, transparent);
422
+ }
423
+ .reveal .slides .box > :last-child { margin-bottom: 0; }
424
+
425
+ /* --- the author slide ---------------------------------------------------- */
426
+ /* `<!-- .slide: class="author-slide" -->` turns a slide into the speaker page:
427
+ photos filling the left edge to edge, the bio centred on the right. Who you
428
+ are stays in the Markdown — this only lays it out. */
429
+
430
+ .reveal .slides section.author-slide {
431
+ /* Reveal keeps a safe band around the 1280x720 slide box (`margin: 0.055`).
432
+ The photo bleeds through it with negative margins — `.reveal` is
433
+ `overflow: hidden`, so whatever spills past the viewport is clipped.
434
+ Sized with slack for 16:9 up to ~2:1 screens; overshooting only costs a
435
+ slightly tighter crop, never a visible seam. */
436
+ --author-bleed-y: 130px;
437
+ --author-bleed-x: 150px;
438
+ --author-photo: 40%;
439
+ --author-gap: 3rem;
440
+ /* Carousel timing: how long a photo holds, and how long the cross-fade is.
441
+ deck.js reads both to write the keyframes for this many photos. */
442
+ --author-hold: 3.5s;
443
+ --author-fade: 1.2s;
444
+ --author-slot: calc(var(--author-hold) + var(--author-fade));
445
+ /* One knob for the whole slide: every size below is in `em`, so bumping this
446
+ scales the title, the bullets and the muted lines together. */
447
+ font-size: 1.25em;
448
+
449
+ display: flex !important;
450
+ flex-direction: row;
451
+ align-items: stretch;
452
+ height: 100%;
453
+ margin: 0;
454
+ padding: 0;
455
+ gap: var(--author-gap);
456
+ }
457
+
458
+ .reveal .slides section.author-slide .author-photo {
459
+ flex: 0 0 calc(var(--author-photo) + var(--author-bleed-x));
460
+ margin: calc(var(--author-bleed-y) * -1) 0 calc(var(--author-bleed-y) * -1)
461
+ calc(var(--author-bleed-x) * -1);
462
+ position: relative;
463
+ overflow: hidden;
464
+ }
465
+
466
+ /* The photos stack on top of each other and cross-fade in DOM order: each one
467
+ starts a slot after the one before, and its fade-in lands exactly on that
468
+ one's fade-out. `--i` and the keyframes come from deck.js, which knows how
469
+ many there are; the first photo is visible from the start, so a single one —
470
+ or a deck where that script never ran — still shows a face.
471
+
472
+ `.present` is reveal's class for the slide on screen: the animation is only
473
+ attached while the slide is being shown, so every visit starts the sequence
474
+ from the first photo instead of dropping in mid-rotation. */
475
+ .reveal .slides section.author-slide .author-photo img {
476
+ position: absolute;
477
+ inset: 0;
478
+ width: 100%;
479
+ height: 100%;
480
+ object-fit: cover;
481
+ object-position: var(--author-crop, 50% 35%);
482
+ display: block;
483
+ margin: 0;
484
+ border: 0;
485
+ border-radius: 0;
486
+ box-shadow: none;
487
+ opacity: 0;
488
+ }
489
+ .reveal .slides section.author-slide .author-photo img:first-child { opacity: 1; }
490
+ .reveal .slides section.present.author-slide .author-photo img {
491
+ animation-name: var(--author-anim, none);
492
+ animation-duration: calc(var(--author-n, 1) * var(--author-slot));
493
+ animation-delay: calc(var(--i, 0) * var(--author-slot));
494
+ animation-iteration-count: infinite;
495
+ }
496
+
497
+ .reveal .slides section.author-slide .author-bio {
498
+ flex: 1 1 auto;
499
+ display: flex;
500
+ flex-direction: column;
501
+ justify-content: center;
502
+ padding-right: 2rem;
503
+ min-width: 0;
504
+ }
505
+ .reveal .slides section.author-slide .author-bio > :last-child { margin-bottom: 0; }
506
+ .reveal .slides section.author-slide h1 { margin: 0 0 1.4rem; }
507
+ .reveal .slides section.author-slide ul { margin: 0; font-size: 0.8em; line-height: 1.75; }
508
+ /* The quiet lines under the bio — what you work with, where to find you. */
509
+ .reveal .slides section.author-slide .author-meta {
510
+ margin: 1.4rem 0 0;
511
+ color: var(--muted);
512
+ font-size: 0.58em;
513
+ line-height: 1.7;
514
+ }
515
+ .reveal .slides section.author-slide .author-meta + .author-meta { margin-top: 0.7rem; }
516
+
517
+ /* The corner badge names the deck a slide belongs to. The speaker page is
518
+ full-bleed and belongs to itself — the badge would sit on the photo. */
519
+ .reveal:has(section.present.author-slide) + #deck-badge { display: none; }
520
+
357
521
  /* --- chrome -------------------------------------------------------------- */
358
522
 
359
523
  .reveal .progress { color: var(--accent); height: 3px; }
@@ -462,14 +626,17 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
462
626
  cursor: crosshair;
463
627
  }
464
628
 
465
- /* Faded back until it is wanted: on stage the slide is the point, and the
466
- toolbar keeps to the quiet strip along the bottom, between the arrows and
467
- the signature. */
629
+ /* Hidden until it is wanted: on stage the slide is the point, so the toolbar
630
+ sleeps just above the top edge of the screen. Parking the mouse along that
631
+ edge — or arming a tool, or tabbing into it — slides it back down. */
468
632
  #deck-tools {
469
633
  position: fixed;
470
- bottom: 14px;
634
+ top: 14px;
471
635
  left: 50%;
472
- transform: translateX(-50%);
636
+ /* Fully clear of the viewport, with a couple of pixels to spare for the
637
+ border. NOT hidden with opacity: that would take the ::before arrow —
638
+ the only piece meant to stay visible — down with it. */
639
+ transform: translateX(-50%) translateY(calc(-100% - 18px));
473
640
  z-index: 40;
474
641
  display: flex;
475
642
  gap: 4px;
@@ -478,12 +645,58 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
478
645
  border: 1px solid var(--line);
479
646
  border-radius: 999px;
480
647
  backdrop-filter: blur(6px);
481
- opacity: 0.4;
648
+ transition: transform 0.22s ease;
649
+ }
650
+ /* The wake strip: one invisible hover surface reaching from the very top of
651
+ the screen, across the chip, to a short stretch below it. While the toolbar
652
+ is away, its lower reach pokes into the viewport as the thing to hover; on
653
+ the way down it keeps the reveal alive over every pixel the mouse crosses,
654
+ the 14px gap above the chip included, so the bar never bounces. */
655
+ #deck-tools::before {
656
+ content: '';
657
+ position: absolute;
658
+ top: -14px;
659
+ bottom: -26px;
660
+ left: -60px;
661
+ right: -60px;
662
+ cursor: pointer;
663
+ }
664
+ /* The hint: a chevron breathing just under the top edge while the toolbar is
665
+ away — the one clue that a menu lives up here. Drawn through a mask so it
666
+ stays crisp at any size and wears whatever the theme's muted colour is. */
667
+ #deck-tools::after {
668
+ content: '';
669
+ position: absolute;
670
+ top: calc(100% + 7px);
671
+ left: 50%;
672
+ width: 20px;
673
+ height: 11px;
674
+ transform: translateX(-50%);
675
+ background: var(--muted);
676
+ -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 11'%3E%3Cpath d='M2 2l8 7 8-7' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
677
+ mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 11'%3E%3Cpath d='M2 2l8 7 8-7' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
678
+ opacity: 0.8;
679
+ pointer-events: none;
680
+ animation: deck-tools-hint 2.6s ease-in-out infinite;
482
681
  transition: opacity 0.18s ease;
483
682
  }
683
+ @keyframes deck-tools-hint {
684
+ 0%, 100% { transform: translateX(-50%) translateY(0); }
685
+ 50% { transform: translateX(-50%) translateY(3px); }
686
+ }
484
687
  #deck-tools:hover,
485
688
  #deck-tools:focus-within,
486
- #deck-tools.is-armed { opacity: 1; }
689
+ #deck-tools.is-armed {
690
+ transform: translateX(-50%) translateY(0);
691
+ }
692
+ /* Once the toolbar is out, the chevron has done its job — the strip stays as
693
+ a silent hover target. */
694
+ #deck-tools:hover::before,
695
+ #deck-tools:focus-within::before,
696
+ #deck-tools.is-armed::before { cursor: default; }
697
+ #deck-tools:hover::after,
698
+ #deck-tools:focus-within::after,
699
+ #deck-tools.is-armed::after { opacity: 0; }
487
700
 
488
701
  .deck-tool {
489
702
  position: relative;
@@ -537,11 +750,11 @@ html[data-reveal-theme] .reveal strong { color: var(--r-heading-color, var(--tex
537
750
  0 0 16px color-mix(in srgb, var(--pen, #ff8c1a) 55%, transparent);
538
751
  }
539
752
 
540
- /* The colours, floating above the toolbar while a tool is armed — the
541
- toolbar sits on the bottom edge, so up is where the room is. */
753
+ /* The colours, floating below the toolbar while a tool is armed — the
754
+ toolbar hangs from the top edge, so down is where the room is. */
542
755
  #deck-swatches {
543
756
  position: absolute;
544
- bottom: calc(100% + 9px);
757
+ top: calc(100% + 9px);
545
758
  left: 50%;
546
759
  transform: translateX(-50%);
547
760
  display: flex;
@@ -859,6 +1072,10 @@ body.outline-open #deck-outline { transform: none; }
859
1072
  /* The outline's mirror image: it takes room from the deck's right edge, so the
860
1073
  slide stays whole — and is the live preview — while its markdown is typed.
861
1074
  Only the dev server ever shows it; a built deck never builds this chrome. */
1075
+ /* The header's chevron trades the drawer's width for the deck's: half the page
1076
+ for a slide that is mostly markup. Everything that steps aside for the
1077
+ drawer reads the same token, so saying it once here moves all of it. */
1078
+ body.edit-wide { --editor-w: 50vw; }
862
1079
  body.edit-open > .reveal { width: calc(100% - var(--editor-w)); }
863
1080
  /* Both panels out at once: the deck keeps to the strip between them. */
864
1081
  body.outline-open.edit-open > .reveal { width: calc(100% - var(--outline-w) - var(--editor-w)); }
@@ -879,7 +1096,7 @@ body.edit-open #deck-sig { right: calc(var(--editor-w) + 14px); }
879
1096
  border-left: 1px solid var(--line);
880
1097
  backdrop-filter: blur(10px);
881
1098
  transform: translateX(100%);
882
- transition: transform 0.26s ease;
1099
+ transition: transform 0.26s ease, width 0.26s ease;
883
1100
  }
884
1101
  body.edit-open #deck-edit { transform: none; }
885
1102
 
@@ -890,12 +1107,6 @@ body.edit-open #deck-edit { transform: none; }
890
1107
  padding: 14px 10px 12px 16px;
891
1108
  border-bottom: 1px solid var(--line);
892
1109
  }
893
- #deck-edit > header span {
894
- font: 600 12px/1 var(--sans);
895
- letter-spacing: 0.1em;
896
- text-transform: uppercase;
897
- color: var(--muted);
898
- }
899
1110
  .deck-edit-file {
900
1111
  flex: 1;
901
1112
  font: 500 12px/1 var(--mono);
@@ -905,7 +1116,8 @@ body.edit-open #deck-edit { transform: none; }
905
1116
  white-space: nowrap;
906
1117
  }
907
1118
  .deck-edit-close,
908
- .deck-edit-nav {
1119
+ .deck-edit-nav,
1120
+ .deck-edit-wide {
909
1121
  display: grid;
910
1122
  place-items: center;
911
1123
  width: 28px;
@@ -918,16 +1130,23 @@ body.edit-open #deck-edit { transform: none; }
918
1130
  cursor: pointer;
919
1131
  }
920
1132
  .deck-edit-close:hover,
921
- .deck-edit-nav:hover { background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text); }
1133
+ .deck-edit-nav:hover,
1134
+ .deck-edit-wide:hover { background: color-mix(in srgb, var(--text) 10%, transparent); color: var(--text); }
922
1135
  .deck-edit-close svg,
923
- .deck-edit-nav svg { display: block; width: 16px; height: 16px; }
1136
+ .deck-edit-nav svg,
1137
+ .deck-edit-wide svg { display: block; width: 16px; height: 16px; }
1138
+ /* Widened, the chevron says so on its own — it is the one control in the
1139
+ header that is holding a state. */
1140
+ .deck-edit-wide[aria-pressed='true'] { color: var(--accent); }
924
1141
 
1142
+ /* The labels are also the handles that swap which box has the room. */
925
1143
  .deck-edit-label {
926
1144
  padding: 12px 16px 6px;
927
1145
  font: 600 10px/1 var(--sans);
928
1146
  letter-spacing: 0.12em;
929
1147
  text-transform: uppercase;
930
1148
  color: var(--muted);
1149
+ cursor: pointer;
931
1150
  }
932
1151
 
933
1152
  #deck-edit textarea {
@@ -979,16 +1198,24 @@ body.edit-open #deck-edit { transform: none; }
979
1198
  scrollbar-color: color-mix(in srgb, var(--accent) 45%, transparent) transparent;
980
1199
  }
981
1200
  }
982
- /* Whichever box holds the cursor gets the room, the other keeps a readable
983
- strip — edit.js writes [data-focus] as the focus moves, and the swap
984
- animates through flex. The slide box starts big: notes are the side dish. */
1201
+ /* Whichever box holds the cursor gets the room edit.js writes [data-focus]
1202
+ as the focus moves, and the swap animates through flex. The slide box starts
1203
+ big and leaves the notes a readable strip; the notes, focused, take the
1204
+ whole drawer and the slide box folds away entirely — its label stays as the
1205
+ handle that brings it back. */
985
1206
  #deck-edit textarea {
986
1207
  min-height: 0;
987
- transition: flex-grow 0.25s ease, flex-basis 0.25s ease;
1208
+ transition: flex-grow 0.25s ease, flex-basis 0.25s ease,
1209
+ padding 0.25s ease, border-width 0.25s ease;
988
1210
  }
989
1211
  #deck-edit-source { flex: 1 1 0; }
990
1212
  #deck-edit-notes { flex: 0 0 120px; }
991
- #deck-edit[data-focus='notes'] #deck-edit-source { flex: 0 0 120px; }
1213
+ #deck-edit[data-focus='notes'] #deck-edit-source {
1214
+ flex: 0 0 0px;
1215
+ padding-block: 0;
1216
+ border-width: 0;
1217
+ overflow: hidden;
1218
+ }
992
1219
  #deck-edit[data-focus='notes'] #deck-edit-notes { flex: 1 1 0; }
993
1220
 
994
1221
  #deck-edit > footer {
@@ -1023,6 +1250,7 @@ body.edit-open #deck-edit { transform: none; }
1023
1250
  border: 1px solid var(--line);
1024
1251
  border-radius: 999px;
1025
1252
  font: 600 12px/1 var(--sans);
1253
+ white-space: nowrap;
1026
1254
  color: var(--muted);
1027
1255
  background: transparent;
1028
1256
  cursor: pointer;
@@ -1071,6 +1299,97 @@ body.edit-open #deck-edit { transform: none; }
1071
1299
  }
1072
1300
  .deck-edit-confirm-delete:hover { background: #f2555a; }
1073
1301
 
1302
+ /* The label line over the slide box carries the block picker's `+`. */
1303
+ .deck-edit-row {
1304
+ display: flex;
1305
+ align-items: center;
1306
+ justify-content: space-between;
1307
+ padding-right: 12px;
1308
+ }
1309
+ .deck-edit-snip {
1310
+ display: grid;
1311
+ place-items: center;
1312
+ width: 24px;
1313
+ height: 24px;
1314
+ padding: 0;
1315
+ border: 1px solid var(--line);
1316
+ border-radius: 999px;
1317
+ background: transparent;
1318
+ color: var(--muted);
1319
+ cursor: pointer;
1320
+ }
1321
+ .deck-edit-snip:hover {
1322
+ border-color: color-mix(in srgb, var(--accent) 55%, transparent);
1323
+ color: var(--text);
1324
+ }
1325
+ .deck-edit-snip svg { display: block; width: 14px; height: 14px; }
1326
+
1327
+ /* The block picker (snippets.js) — over the drawer, like the delete question,
1328
+ so the deck keeps the stage while a block is chosen. */
1329
+ .deck-snip {
1330
+ position: absolute;
1331
+ inset: 0;
1332
+ z-index: 2;
1333
+ display: flex;
1334
+ flex-direction: column;
1335
+ gap: 10px;
1336
+ padding: 14px 12px;
1337
+ background: color-mix(in srgb, var(--bg) 80%, transparent);
1338
+ backdrop-filter: blur(6px);
1339
+ }
1340
+ .deck-snip[hidden] { display: none; }
1341
+
1342
+ .deck-snip-filter {
1343
+ flex: 0 0 auto;
1344
+ padding: 9px 12px;
1345
+ font: 400 13px/1.4 var(--sans);
1346
+ color: var(--text);
1347
+ background: color-mix(in srgb, var(--card) 80%, transparent);
1348
+ border: 1px solid var(--line);
1349
+ border-radius: 8px;
1350
+ }
1351
+ .deck-snip-filter:focus {
1352
+ outline: none;
1353
+ border-color: color-mix(in srgb, var(--accent) 55%, transparent);
1354
+ }
1355
+
1356
+ .deck-snip-list {
1357
+ flex: 1 1 auto;
1358
+ margin: 0;
1359
+ padding: 0;
1360
+ list-style: none;
1361
+ overflow-y: auto;
1362
+ }
1363
+ .deck-snip-list li {
1364
+ display: flex;
1365
+ flex-direction: column;
1366
+ gap: 2px;
1367
+ padding: 7px 10px;
1368
+ border-radius: 8px;
1369
+ cursor: pointer;
1370
+ }
1371
+ .deck-snip-list li[hidden] { display: none; }
1372
+ .deck-snip-list li span { font: 600 13px/1.3 var(--sans); color: var(--text); }
1373
+ .deck-snip-list li small { font: 400 11.5px/1.45 var(--sans); color: var(--muted); }
1374
+ /* Keyboard and pointer land on the same row: the arrows move this class, and
1375
+ the pointer moving over an entry takes it. */
1376
+ .deck-snip-list li.is-current { background: color-mix(in srgb, var(--accent) 18%, transparent); }
1377
+
1378
+ /* The hairline the outline list and the drawer's boxes wear. */
1379
+ .deck-snip-list::-webkit-scrollbar { width: 5px; }
1380
+ .deck-snip-list::-webkit-scrollbar-track { background: transparent; }
1381
+ .deck-snip-list::-webkit-scrollbar-thumb {
1382
+ border-radius: 999px;
1383
+ background: var(--outline-bar);
1384
+ }
1385
+ .deck-snip-list::-webkit-scrollbar-thumb:hover { background: var(--outline-bar-hover); }
1386
+ @supports not selector(::-webkit-scrollbar) {
1387
+ .deck-snip-list {
1388
+ scrollbar-width: thin;
1389
+ scrollbar-color: var(--outline-bar) transparent;
1390
+ }
1391
+ }
1392
+
1074
1393
  /* The open drawer's button wears the accent — it draws in nothing, like the
1075
1394
  pointer's; the id outweighs the generic armed-tool rule. */
1076
1395
  #tool-edit[aria-pressed='true'] {
@@ -1174,10 +1493,10 @@ html.deck-pointer-on * { cursor: none !important; }
1174
1493
  0 0 16px color-mix(in srgb, var(--accent) 55%, transparent);
1175
1494
  }
1176
1495
 
1177
- /* The kind picker, floating above the toolbar like the pen's swatches. */
1496
+ /* The kind picker, floating below the toolbar like the pen's swatches. */
1178
1497
  #deck-pointer-kinds {
1179
1498
  position: absolute;
1180
- bottom: calc(100% + 9px);
1499
+ top: calc(100% + 9px);
1181
1500
  left: 50%;
1182
1501
  transform: translateX(-50%);
1183
1502
  display: flex;
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 800" width="600" height="800">
2
+ <defs>
3
+ <linearGradient id="g1" x1="0" y1="0" x2="0.6" y2="1">
4
+ <stop offset="0" stop-color="#1f2937" />
5
+ <stop offset="1" stop-color="#4b5563" />
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="600" height="800" fill="url(#g1)" />
9
+ <text x="300" y="400" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif"
10
+ font-size="34" fill="#e8ebf0" fill-opacity="0.55">your photo 1</text>
11
+ </svg>
@@ -0,0 +1,11 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 800" width="600" height="800">
2
+ <defs>
3
+ <linearGradient id="g2" x1="0" y1="0" x2="0.6" y2="1">
4
+ <stop offset="0" stop-color="#1e3a5f" />
5
+ <stop offset="1" stop-color="#2f6f8f" />
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="600" height="800" fill="url(#g2)" />
9
+ <text x="300" y="400" text-anchor="middle" font-family="ui-sans-serif, system-ui, sans-serif"
10
+ font-size="34" fill="#e8ebf0" fill-opacity="0.55">your photo 2</text>
11
+ </svg>
@@ -10,6 +10,28 @@ The subtitle goes here.
10
10
 
11
11
  ---
12
12
 
13
+ <!-- .slide: class="author-slide" -->
14
+
15
+ <div class="author-photo">
16
+ <img src="assets/author/photo-1.svg" alt="" />
17
+ <img src="assets/author/photo-2.svg" alt="" />
18
+ </div>
19
+
20
+ <div class="author-bio">
21
+ <h1>Your name</h1>
22
+ <ul>
23
+ <li>What you do</li>
24
+ <li>What you are <strong>known for</strong></li>
25
+ <li>Where people can find you</li>
26
+ </ul>
27
+ <p class="author-meta">The stack · you · work · with</p>
28
+ <p class="author-meta">❤️ Life outside work — <strong>yoursite.dev</strong></p>
29
+ </div>
30
+
31
+ Note: thirty seconds, no more. Swap the two placeholders in assets/author/ for your own photos — add as many as you like, they cross-fade in the order they are written.
32
+
33
+ ---
34
+
13
35
  ## A slide
14
36
 
15
37
  A slide is whatever sits between two `---` lines.
@@ -20,25 +20,52 @@ section: Demos
20
20
 
21
21
  ---
22
22
 
23
- <!-- demo: https://stage.mokup.dev/embed/95ff8eab-3c34-4eaf-9f53-e263ee1c6062 -->
23
+ ## An embed that shares the slide
24
24
 
25
- ## A mokup embed
26
-
27
- <div class="mockup-frame">
28
- <iframe src="https://stage.mokup.dev/embed/95ff8eab-3c34-4eaf-9f53-e263ee1c6062" width="800" height="500" style="border:0;" allowfullscreen></iframe>
25
+ <div class="frame">
26
+ <iframe src="demo/counter/"></iframe>
29
27
  </div>
30
28
 
29
+ Not every demo wants the whole slide. `.frame` sizes one so the heading stays.
30
+
31
+ ---
32
+
33
+ ## The mechanism, in one picture
34
+
35
+ ```mermaid
36
+ sequenceDiagram
37
+ autonumber
38
+ participant U as User
39
+ participant A as Your App
40
+ participant M as Model
41
+ participant S as Your Services
42
+
43
+ U->>A: "how are the running shoes doing?"
44
+ A->>M: prompt + tool list + component catalog
45
+ M->>A: tool call: getSales('running shoes')
46
+ A->>S: getSales('running shoes')
47
+ S-->>A: data
48
+ A->>M: tool result
49
+ M-->>A: UI description (JSON)
50
+ A->>A: render with YOUR components
51
+ A-->>U: a chart, product cards, a form
52
+ ```
53
+
54
+ Note what never happens: the model never touches the DOM, the network, or your state.
55
+
31
56
  ---
32
57
 
33
- ## How those two slides work
58
+ ## How those slides work
34
59
 
35
60
  ```markdown
36
61
  <!-- demo: counter --> a folder in demo/
37
62
  <!-- demo: http://…:4200/ --> anything else
63
+ <div class="frame">…</div> an embed that shares the slide
38
64
  ```
39
65
 
40
66
  - the marker must be the first thing in the slide
41
67
  - what follows it is the fallback for GitHub and Marp
42
68
  - `demo/angular-hello` is started by `servers:` in `slides.config.js`
69
+ - the `+` in the edit drawer writes all three, and `/` opens the same list
43
70
 
44
71
  Note: the iframe is reloaded every time you arrive on the slide, so a demo is always in its initial state.
@@ -2,17 +2,6 @@
2
2
  Redefining a token here reskins the whole deck. Delete this file if the
3
3
  default dark theme is fine as it is. */
4
4
 
5
- .mockup-frame {
6
- display: flex;
7
- justify-content: center;
8
- }
9
-
10
- .mockup-frame iframe {
11
- max-width: 100%;
12
- border-radius: 8px;
13
- background: #fff;
14
- }
15
-
16
5
  /*
17
6
  :root {
18
7
  --bg: #0e1116;