@cyber-dash-tech/revela 0.1.2 → 0.1.4

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.
@@ -1,1079 +0,0 @@
1
- ---
2
- name: minimal
3
- description: Warm off-white light theme — frosted-glass cards, typographic, distraction-free
4
- author: slides-it
5
- version: 1.0.0
6
- preview: bundled
7
- ---
8
-
9
- ## Visual Style — Minimal Theme
10
-
11
- Apply this visual style when generating all slides in this session.
12
-
13
- This theme pairs a warm, off-white background with frosted-glass cards and subtle geometric depth. Think: a well-designed printed magazine with a modern glass layer — warm paper feel, elevated with translucency.
14
-
15
- <!-- @section:global:start -->
16
-
17
- ### Color Palette (Unchanged)
18
-
19
- ```css
20
- :root {
21
- --bg-primary: #FAF9F6; /* warm off-white — main background */
22
- --bg-secondary: #F0EEE8; /* slightly darker warm grey */
23
- --bg-card: rgba(255, 255, 255, 0.55); /* frosted glass white */
24
- --text-primary: #1A1916; /* near-black warm ink */
25
- --text-secondary:#6B6560; /* warm mid-grey */
26
- --text-muted: #A09890; /* subtle captions */
27
- --accent: #1A1916; /* same as text — monochrome accent */
28
- --accent-2: #6B6560; /* secondary accent — warm grey */
29
- --border: rgba(226, 222, 213, 0.6); /* soft warm border, semi-transparent */
30
- --border-strong: #C9C4B8; /* stronger divider */
31
- }
32
- ```
33
-
34
- ### Typography
35
-
36
- - **Display font**: `DM Serif Display` (headings) — load from Google Fonts
37
- - **Body font**: `DM Sans` (body, captions) — load from Google Fonts
38
- - Font link tag:
39
- ```html
40
- <link rel="preconnect" href="https://fonts.googleapis.com">
41
- <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&display=swap" rel="stylesheet">
42
- ```
43
- - Title size (h1): `64px`, weight 400
44
- - Section heading (h2): `42px`, weight 400
45
- - Subtitle size: `22px`, weight 300
46
- - Body size: `18px`
47
- - Label: `13px`, letter-spacing `0.1em`, uppercase
48
- - Card title: `24px` (DM Serif Display)
49
- - Card body: `17px`
50
- - Stat number: `64px`, weight 400
51
- - Stat label: `15px`, uppercase
52
- - Line height: `1.75` for body, `1.15` for h1, `1.2` for h2
53
- - Letter spacing: `-0.02em` for large headings
54
- - Card title: weight 400 (DM Serif Display)
55
- - Card body / body-text: weight 400
56
- - Stat label: weight 400
57
-
58
- All sizes are fixed `px` — designed for the 1920×1080 canvas. JS `transform: scale()`
59
- handles viewport adaptation. **Never use `clamp()` or viewport-relative units.**
60
-
61
- ### Background Layers (Subtle Geometric Depth)
62
-
63
- **Layer 1 — Base gradient (subtle warmth):**
64
- ```css
65
- body::before {
66
- content: '';
67
- position: fixed;
68
- inset: 0;
69
- background: linear-gradient(180deg, #FAF9F6 0%, #F5F3EE 50%, #FAF9F6 100%);
70
- z-index: -3;
71
- }
72
- ```
73
-
74
- **Layer 2 — Geometric circles (blurred, warm amber tones):**
75
- ```css
76
- .geo-shape-1, .geo-shape-2, .geo-shape-3 {
77
- position: fixed;
78
- border-radius: 50%;
79
- filter: blur(60px);
80
- opacity: 0.20;
81
- z-index: -2;
82
- pointer-events: none;
83
- }
84
- .geo-shape-1 {
85
- width: 600px;
86
- height: 600px;
87
- background: #FFB347;
88
- top: -200px;
89
- right: -100px;
90
- }
91
- .geo-shape-2 {
92
- width: 400px;
93
- height: 400px;
94
- background: #FFA633;
95
- bottom: -100px;
96
- left: -100px;
97
- }
98
- .geo-shape-3 {
99
- width: 300px;
100
- height: 300px;
101
- background: #EE9526;
102
- top: 50%;
103
- left: 30%;
104
- opacity: 0.15;
105
- }
106
- ```
107
-
108
- **Layer 3 — Subtle diagonal lines (paper texture):**
109
- ```css
110
- body::after {
111
- content: '';
112
- position: fixed;
113
- inset: 0;
114
- background: repeating-linear-gradient(
115
- 45deg,
116
- transparent,
117
- transparent 3px,
118
- rgba(0, 0, 0, 0.008) 3px,
119
- rgba(0, 0, 0, 0.008) 6px
120
- );
121
- z-index: -1;
122
- pointer-events: none;
123
- }
124
- ```
125
-
126
- ### Slide Layout
127
-
128
- - **1920×1080 fixed canvas** — each slide uses a `.slide-canvas` (1920×1080px),
129
- scaled to fit the viewport via JS `transform: scale()`.
130
- - Content width tiers (inside canvas, via `max-width` + `margin: 0 auto`):
131
- - Default (`1200px`): Cover, Quote, Closing
132
- - Wide (`1600px`): content-heavy slides (grids, multi-column, process flows)
133
- - Canvas padding: `60px 80px`
134
- - **No `clamp()` — use fixed `px` for all sizes.** The canvas is always
135
- 1920×1080 and JS handles scaling, so all typography and spacing must be fixed `px`.
136
- - **Canvas utilization** — Elements should fill approximately 70–80% of the
137
- 1920×1080 canvas area. Even in a minimal design, slides should not feel empty.
138
- Use larger serif headings, more generous card heights, wider grids, and
139
- comfortable padding to occupy the space. The calm feeling comes from typography
140
- and whitespace *rhythm*, not from leaving the canvas half-empty.
141
- - **Content slides** (Feature Cards, Stats, Two-Column, Step Flow): grid/flex
142
- containers should stretch toward the canvas edges. Frosted-glass cards should
143
- have ample internal padding and body text so they feel substantial.
144
- - **Sparse slides** (Cover, Quote, Closing): add decorative fills — thin geometric
145
- rules, positioned warm-amber circles (low opacity), large typographic ornaments
146
- (e.g. oversized `"` for quotes in `var(--border)` color), or horizontal `1px`
147
- dividers that span most of the canvas width. These anchor the composition
148
- without breaking the calm, paper-like feel.
149
- - **Never** leave more than ~20% of the canvas visually empty on any slide.
150
- - Title slide: large serif heading left-aligned + thin `1px` rule beneath + muted subtitle
151
- - Content slides: heading top with `border-bottom: 1px solid var(--border)` separator, content below
152
-
153
- ### HTML Structure
154
-
155
- Every generated presentation must use this exact HTML skeleton:
156
-
157
- ```html
158
- <!DOCTYPE html>
159
- <html lang="{language}">
160
- <head>
161
- <meta charset="UTF-8">
162
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
163
- <title>{Presentation Title}</title>
164
- <link rel="preconnect" href="https://fonts.googleapis.com">
165
- <link href="https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&display=swap" rel="stylesheet">
166
- <script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/umd/lucide.js"></script>
167
- <!-- <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> ← only if charts needed -->
168
- <style>/* all CSS here */</style>
169
- </head>
170
- <body>
171
- <!-- Geometric background shapes -->
172
- <div class="geo-shape-1"></div>
173
- <div class="geo-shape-2"></div>
174
- <div class="geo-shape-3"></div>
175
-
176
- <!-- Navigation -->
177
- <div class="progress-bar" id="progressBar"></div>
178
- <nav class="nav-dots" id="navDots" aria-label="Slide navigation"></nav>
179
-
180
- <!-- Slides -->
181
- <section class="slide title-slide" data-slide-type="cover" data-index="0">
182
- <div class="slide-canvas"> ... </div>
183
- </section>
184
- <section class="slide" data-slide-type="content" data-index="1">
185
- <div class="slide-canvas"> ... </div>
186
- </section>
187
- <!-- every <section class="slide"> must have data-slide-type — see SKILL.md for valid values -->
188
-
189
- <script>/* all JS here */</script>
190
- </body>
191
- </html>
192
- ```
193
-
194
- ### Core CSS
195
-
196
- ```css
197
- * { box-sizing: border-box; margin: 0; padding: 0; }
198
-
199
- html {
200
- scroll-snap-type: y mandatory;
201
- overflow-y: scroll;
202
- height: 100%;
203
- }
204
-
205
- body {
206
- background: var(--bg-primary);
207
- color: var(--text-primary);
208
- font-family: 'DM Sans', ui-sans-serif, sans-serif;
209
- -webkit-font-smoothing: antialiased;
210
- height: 100%;
211
- }
212
-
213
- .slide {
214
- height: 100dvh;
215
- scroll-snap-align: start;
216
- overflow: hidden;
217
- display: flex;
218
- align-items: center;
219
- justify-content: center;
220
- }
221
-
222
- .slide-canvas {
223
- width: 1920px;
224
- height: 1080px;
225
- flex-shrink: 0;
226
- transform-origin: center center;
227
- /* scale set by JS setupScaling() */
228
- overflow: hidden;
229
- position: relative;
230
- display: flex;
231
- flex-direction: column;
232
- justify-content: center;
233
- padding: 60px 80px;
234
- }
235
- ```
236
-
237
- ### Navigation & Progress
238
-
239
- #### Progress Bar
240
-
241
- ```css
242
- .progress-bar {
243
- position: fixed;
244
- top: 0;
245
- left: 0;
246
- height: 2px;
247
- background: var(--border-strong);
248
- width: 0%;
249
- z-index: 100;
250
- transition: width 0.2s ease;
251
- }
252
- ```
253
-
254
- No glow, no gradient — a quiet, thin line.
255
-
256
- #### Nav Dots
257
-
258
- ```css
259
- .nav-dots {
260
- position: fixed;
261
- right: 20px;
262
- top: 50%;
263
- transform: translateY(-50%);
264
- display: flex;
265
- flex-direction: column;
266
- gap: 8px;
267
- z-index: 100;
268
- }
269
- .nav-dots button {
270
- width: 6px;
271
- height: 6px;
272
- border-radius: 50%;
273
- border: 1px solid var(--border-strong);
274
- background: transparent;
275
- cursor: pointer;
276
- padding: 0;
277
- transition: background 0.2s;
278
- }
279
- .nav-dots button.active {
280
- background: var(--text-primary);
281
- border-color: var(--text-primary);
282
- }
283
- ```
284
-
285
- No glow, no box-shadow — solid fill only.
286
-
287
- #### Reduced Motion
288
-
289
- ```css
290
- @media (prefers-reduced-motion: reduce) {
291
- .reveal {
292
- transition: opacity 0.3s ease;
293
- opacity: 1;
294
- }
295
- }
296
- ```
297
-
298
- ### SlidePresentation Class (Complete JavaScript)
299
-
300
- All presentations must include this complete `SlidePresentation` class. Every
301
- method is fully implemented — copy this exactly and include it in the `<script>`
302
- block.
303
-
304
- ```javascript
305
- class SlidePresentation {
306
- constructor() {
307
- this.slides = document.querySelectorAll('.slide');
308
- this.currentSlide = 0;
309
- this.setupScaling();
310
- this.setupProgressBar();
311
- this.setupNavDots();
312
- this.setupIntersectionObserver();
313
- this.setupKeyboardNav();
314
- this.setupTouchNav();
315
- this.setupMouseWheel();
316
- }
317
-
318
- /* Scale 1920×1080 canvases to fit viewport */
319
- setupScaling() {
320
- const canvases = document.querySelectorAll('.slide-canvas');
321
- const BASE_W = 1920, BASE_H = 1080;
322
- const update = () => {
323
- const vw = window.innerWidth;
324
- const vh = window.innerHeight;
325
- const scale = Math.min(vw / BASE_W, vh / BASE_H);
326
- canvases.forEach(c => { c.style.transform = `scale(${scale})`; });
327
- };
328
- window.addEventListener('resize', update);
329
- update();
330
- }
331
-
332
- /* Horizontal progress bar at top */
333
- setupProgressBar() {
334
- const bar = document.getElementById('progressBar');
335
- const update = () => {
336
- const scrolled = window.scrollY;
337
- const total = document.body.scrollHeight - window.innerHeight;
338
- bar.style.width = total > 0 ? (scrolled / total * 100) + '%' : '0%';
339
- };
340
- window.addEventListener('scroll', update, { passive: true });
341
- update();
342
- }
343
-
344
- /* Vertical dot navigation on right side */
345
- setupNavDots() {
346
- const nav = document.getElementById('navDots');
347
- this.slides.forEach((_, i) => {
348
- const btn = document.createElement('button');
349
- btn.setAttribute('aria-label', `Go to slide ${i + 1}`);
350
- if (i === 0) btn.classList.add('active');
351
- btn.addEventListener('click', () => this.goTo(i));
352
- nav.appendChild(btn);
353
- });
354
- this.dots = nav.querySelectorAll('button');
355
-
356
- const obs = new IntersectionObserver((entries) => {
357
- entries.forEach(e => {
358
- if (e.isIntersecting) {
359
- const idx = parseInt(e.target.dataset.index);
360
- this.dots.forEach((d, i) => d.classList.toggle('active', i === idx));
361
- this.currentSlide = idx;
362
- }
363
- });
364
- }, { threshold: 0.5 });
365
- this.slides.forEach(s => obs.observe(s));
366
- }
367
-
368
- /* Reveal animations on scroll — opacity only, no translateY */
369
- setupIntersectionObserver() {
370
- const obs = new IntersectionObserver((entries) => {
371
- entries.forEach(e => {
372
- if (e.isIntersecting) {
373
- e.target.querySelectorAll('.reveal').forEach(el => el.classList.add('visible'));
374
- }
375
- });
376
- }, { threshold: 0.15 });
377
- this.slides.forEach(s => obs.observe(s));
378
- }
379
-
380
- /* Arrow keys, Space, PageUp/PageDown */
381
- setupKeyboardNav() {
382
- document.addEventListener('keydown', e => {
383
- if (['ArrowDown', 'ArrowRight', ' ', 'PageDown'].includes(e.key)) {
384
- e.preventDefault();
385
- this.goTo(this.currentSlide + 1);
386
- } else if (['ArrowUp', 'ArrowLeft', 'PageUp'].includes(e.key)) {
387
- e.preventDefault();
388
- this.goTo(this.currentSlide - 1);
389
- }
390
- });
391
- }
392
-
393
- /* Swipe support for touch devices */
394
- setupTouchNav() {
395
- let startY = 0;
396
- document.addEventListener('touchstart', e => { startY = e.touches[0].clientY; }, { passive: true });
397
- document.addEventListener('touchend', e => {
398
- const dy = startY - e.changedTouches[0].clientY;
399
- if (Math.abs(dy) > 40) this.goTo(this.currentSlide + (dy > 0 ? 1 : -1));
400
- }, { passive: true });
401
- }
402
-
403
- /* Debounced mouse wheel navigation (800ms) */
404
- setupMouseWheel() {
405
- let last = 0;
406
- document.addEventListener('wheel', e => {
407
- const now = Date.now();
408
- if (now - last < 800) return;
409
- last = now;
410
- this.goTo(this.currentSlide + (e.deltaY > 0 ? 1 : -1));
411
- }, { passive: true });
412
- }
413
-
414
- /* Scroll to slide by index */
415
- goTo(idx) {
416
- const clamped = Math.max(0, Math.min(this.slides.length - 1, idx));
417
- this.slides[clamped].scrollIntoView({ behavior: 'smooth' });
418
- this.currentSlide = clamped;
419
- }
420
- }
421
-
422
- new SlidePresentation();
423
- ```
424
-
425
- After the `SlidePresentation` class, include:
426
- 1. `lucide.createIcons();` to render Lucide icons (if icons are used)
427
- 2. ECharts initialization (if charts are present)
428
- 3. Inline editing code (see SKILL.md)
429
-
430
- <!-- @section:global:end -->
431
-
432
- <!-- @section:components:start -->
433
-
434
- ### Component Library
435
-
436
- These are independent, composable building blocks. Mix them freely on any slide —
437
- they are not locked to specific layouts.
438
-
439
- <!-- @component:reveal:start -->
440
- #### Reveal Animation (.reveal)
441
-
442
- Add `.reveal` to any element that should animate on scroll. JS adds `.visible`
443
- via IntersectionObserver. This theme uses opacity-only transitions — no
444
- directional motion (translateY/translateX) — to preserve the calm, paper-like feel.
445
-
446
- ```css
447
- .reveal {
448
- opacity: 0;
449
- transition: opacity 0.4s ease;
450
- }
451
- .reveal.visible {
452
- opacity: 1;
453
- }
454
- /* Stagger children */
455
- .reveal:nth-child(1) { transition-delay: 0s; }
456
- .reveal:nth-child(2) { transition-delay: 0.06s; }
457
- .reveal:nth-child(3) { transition-delay: 0.12s; }
458
- .reveal:nth-child(4) { transition-delay: 0.18s; }
459
- .reveal:nth-child(5) { transition-delay: 0.24s; }
460
- .reveal:nth-child(6) { transition-delay: 0.30s; }
461
- .reveal:nth-child(7) { transition-delay: 0.36s; }
462
- .reveal:nth-child(8) { transition-delay: 0.42s; }
463
- ```
464
-
465
- No `.title-reveal` in this theme — cover headings use the same `.reveal` fade.
466
-
467
- <!-- @component:reveal:end -->
468
-
469
- <!-- @component:showcase:start -->
470
- #### Showcase (.showcase)
471
-
472
- Semi-transparent container that frames a component or image with padding and
473
- visual depth. Use inside `.two-col-aside`, `.two-col-main`, or as a standalone
474
- wrapper when a component needs a "stage" rather than sitting directly on the
475
- slide background. Vertically and horizontally centers its content.
476
-
477
- ```css
478
- .showcase {
479
- padding: 28px;
480
- border: 1px solid var(--border);
481
- background: var(--bg-card);
482
- backdrop-filter: blur(16px);
483
- -webkit-backdrop-filter: blur(16px);
484
- border-radius: 12px;
485
- display: flex;
486
- align-items: center;
487
- justify-content: center;
488
- flex: 1;
489
- }
490
- ```
491
-
492
- <!-- @component:showcase:end -->
493
-
494
- <!-- @component:card:start -->
495
- #### Card (.card)
496
-
497
- Frosted-glass container for any grouped content — features, evidence, info blocks.
498
-
499
- ```html
500
- <div class="card">
501
- <i data-lucide="circle-dashed" class="card-icon"></i>
502
- <p class="card-label">01</p>
503
- <p class="card-title">Title</p>
504
- <p class="card-body">Body text describing the item.</p>
505
- </div>
506
- ```
507
-
508
- All inner elements are optional — use only what the content needs.
509
-
510
- ```css
511
- .card {
512
- background: var(--bg-card);
513
- backdrop-filter: blur(16px);
514
- -webkit-backdrop-filter: blur(16px);
515
- border: 1px solid var(--border);
516
- border-radius: 12px;
517
- padding: 28px;
518
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
519
- display: flex;
520
- flex-direction: column;
521
- justify-content: flex-start;
522
- transition: transform 0.25s ease, box-shadow 0.25s ease;
523
- }
524
- .card:hover {
525
- transform: translateY(-2px);
526
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.10);
527
- }
528
- .card-icon { width: 28px; height: 28px; color: var(--accent-2); margin-bottom: 12px; transition: transform 0.2s ease; }
529
- .card:hover .card-icon { transform: scale(1.05); }
530
- .card-label { font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 10px; }
531
- .card-title { font-family: 'DM Serif Display', serif; font-size: 24px; margin-bottom: 12px; }
532
- .card-body { font-size: 17px; color: var(--text-secondary); line-height: 1.7; flex: 1; }
533
- ```
534
-
535
- <!-- @component:card:end -->
536
-
537
- <!-- @component:image-card:start -->
538
- #### Image Card (.image-card)
539
-
540
- Standalone image with rounded corners and optional caption. Use for product shots,
541
- screenshots, team photos, or any visual that deserves its own space.
542
-
543
- ```html
544
- <div class="image-card">
545
- <img src="photo.jpg" alt="Description">
546
- <p class="image-card-caption">Optional caption text</p>
547
- </div>
548
- ```
549
-
550
- Caption is optional — omit when the image is self-explanatory.
551
-
552
- ```css
553
- .image-card {
554
- border-radius: 12px;
555
- overflow: hidden;
556
- border: 1px solid var(--border);
557
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
558
- display: flex;
559
- flex-direction: column;
560
- }
561
- .image-card img {
562
- width: 100%;
563
- height: 100%;
564
- object-fit: cover;
565
- display: block;
566
- }
567
- .image-card-caption {
568
- padding: 14px 18px;
569
- font-size: 14px;
570
- color: var(--text-muted);
571
- background: var(--bg-card);
572
- backdrop-filter: blur(16px);
573
- font-family: 'DM Sans', sans-serif;
574
- }
575
- ```
576
-
577
- Sizing: set `width` and `height` on `.image-card` via inline style to control
578
- aspect ratio. Typical: `width:100%; height:400px` in a column, or
579
- `width:480px; height:320px` standalone.
580
-
581
- <!-- @component:image-card:end -->
582
-
583
- <!-- @component:card-img:start -->
584
- #### Card with Image Header (.card-img)
585
-
586
- Card variant with an image at the top and text content below. Use for team
587
- members, portfolio items, or any card where a visual header adds context.
588
-
589
- ```html
590
- <div class="card card-img">
591
- <div class="card-img-top">
592
- <img src="photo.jpg" alt="Description">
593
- </div>
594
- <p class="card-title">Title</p>
595
- <p class="card-body">Description text goes here.</p>
596
- </div>
597
- ```
598
-
599
- ```css
600
- .card-img {
601
- padding: 0;
602
- overflow: hidden;
603
- }
604
- .card-img-top {
605
- width: 100%;
606
- aspect-ratio: 16 / 10;
607
- overflow: hidden;
608
- }
609
- .card-img-top img {
610
- width: 100%;
611
- height: 100%;
612
- object-fit: cover;
613
- display: block;
614
- }
615
- .card-img .card-title,
616
- .card-img .card-body,
617
- .card-img .card-label {
618
- padding-left: 28px;
619
- padding-right: 28px;
620
- }
621
- .card-img .card-title { padding-top: 20px; }
622
- .card-img .card-body { padding-bottom: 28px; }
623
- ```
624
-
625
- <!-- @component:card-img:end -->
626
-
627
- <!-- @component:avatar:start -->
628
- #### Avatar (.avatar)
629
-
630
- Circular cropped image for people, team members, or profile pictures.
631
-
632
- ```html
633
- <img src="person.jpg" alt="Name" class="avatar avatar-lg">
634
- ```
635
-
636
- ```css
637
- .avatar {
638
- width: 64px;
639
- height: 64px;
640
- border-radius: 50%;
641
- object-fit: cover;
642
- border: 2px solid var(--border-strong);
643
- flex-shrink: 0;
644
- }
645
- .avatar-sm { width: 48px; height: 48px; }
646
- .avatar-lg { width: 96px; height: 96px; }
647
- ```
648
-
649
- No glow, no shadow — clean circle with a thin warm border. Pair with card text
650
- for team slides: avatar left, name + role right.
651
-
652
- <!-- @component:avatar:end -->
653
-
654
- <!-- @component:stat-card:start -->
655
- #### Stat Card (.stat-card)
656
-
657
- Large metric display. Numbers appear statically with fade-in — no counter animation.
658
-
659
- ```html
660
- <div class="stat-card">
661
- <div class="stat-number">85%</div>
662
- <div class="stat-label">Growth Rate</div>
663
- <div class="stat-desc">Year over year revenue increase</div>
664
- </div>
665
- ```
666
-
667
- ```css
668
- .stat-card {
669
- background: var(--bg-card);
670
- backdrop-filter: blur(16px);
671
- border: 1px solid var(--border);
672
- border-radius: 12px;
673
- padding: 48px 40px;
674
- text-align: center;
675
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
676
- border-bottom: 2px solid var(--border-strong);
677
- display: flex;
678
- flex-direction: column;
679
- align-items: center;
680
- justify-content: center;
681
- }
682
- .stat-number { font-family: 'DM Serif Display', serif; font-size: 64px; font-weight: 400; color: var(--text-primary); line-height: 1; letter-spacing: -0.03em; margin-bottom: 12px; }
683
- .stat-label { font-size: 15px; color: var(--text-muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 12px; }
684
- .stat-desc { font-size: 15px; color: var(--text-secondary); line-height: 1.5; opacity: 0.8; }
685
- ```
686
-
687
- No `.gradient-text` on numbers — minimal stays monochrome.
688
-
689
- <!-- @component:stat-card:end -->
690
-
691
- <!-- @component:quote-block:start -->
692
- #### Quote Block (.quote-block)
693
-
694
- ```html
695
- <div class="quote-deco">&ldquo;</div>
696
- <div class="quote-block">
697
- <blockquote>&ldquo;The quote text goes here.&rdquo;</blockquote>
698
- <cite>Attribution</cite>
699
- </div>
700
- ```
701
-
702
- ```css
703
- .quote-block { display: flex; flex-direction: column; justify-content: center; border-left: 2px solid var(--border-strong); padding-left: 32px; max-width: 1200px; }
704
- .quote-block blockquote { font-family: 'DM Serif Display', serif; font-size: 40px; font-style: italic; line-height: 1.4; margin-bottom: 20px; }
705
- .quote-block cite { font-size: 14px; color: var(--text-muted); letter-spacing: 0.05em; text-transform: uppercase; font-style: normal; font-family: 'DM Sans', sans-serif; }
706
- .quote-deco { position: absolute; font-family: 'DM Serif Display', serif; font-size: 280px; line-height: 1; color: var(--border); opacity: 0.3; pointer-events: none; z-index: 0; }
707
- ```
708
-
709
- No background color on `.quote-block` — let the typography speak.
710
-
711
- <!-- @component:quote-block:end -->
712
-
713
- <!-- @component:step-flow:start -->
714
- #### Step Flow (.step-flow)
715
-
716
- Horizontal process with numbered circles and connectors. Alternate `.step`
717
- and `.step-connector` as siblings inside `.step-flow`.
718
-
719
- ```html
720
- <div class="step-flow">
721
- <div class="step">
722
- <div class="step-circle">1</div>
723
- <div class="step-title">Describe</div>
724
- <div class="step-desc">Tell us your topic and audience.</div>
725
- </div>
726
- <div class="step-connector"></div>
727
- <div class="step">
728
- <div class="step-circle">2</div>
729
- <div class="step-title">Generate</div>
730
- <div class="step-desc">AI creates your slides.</div>
731
- </div>
732
- <!-- more steps + connectors as needed -->
733
- </div>
734
- ```
735
-
736
- ```css
737
- .step-flow { display: flex; align-items: flex-start; max-width: 1600px; margin: 0 auto; }
738
- .step { flex: 1; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 16px; }
739
- .step-circle { width: 64px; height: 64px; border-radius: 50%; background: var(--text-primary); color: var(--bg-primary); font-family: 'DM Serif Display', serif; font-size: 24px; font-weight: 400; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
740
- .step-connector { flex: 0 0 32px; height: 1px; background: var(--border); margin-top: 32px; align-self: flex-start; }
741
- .step-title { font-family: 'DM Serif Display', serif; font-size: 20px; }
742
- .step-desc { font-size: 16px; color: var(--text-secondary); line-height: 1.6; max-width: 200px; }
743
- ```
744
-
745
- Circles are solid fill — no gradient, no glow, no shadow.
746
-
747
- <!-- @component:step-flow:end -->
748
-
749
- <!-- @component:evidence-list:start -->
750
- #### Evidence List (.evidence-list)
751
-
752
- Styled bullet list with em-dash markers. Use inside `.card`, `.two-col-main`, or any container.
753
-
754
- ```html
755
- <ul class="evidence-list">
756
- <li>First piece of evidence or supporting point</li>
757
- <li>Second supporting point</li>
758
- </ul>
759
- ```
760
-
761
- ```css
762
- .evidence-list { list-style: none; padding: 0; display: flex; flex-direction: column; gap: 12px; }
763
- .evidence-list li { padding-left: 18px; position: relative; font-size: 18px; color: var(--text-primary); line-height: 1.5; }
764
- .evidence-list li::before { content: '\2014'; position: absolute; left: 0; top: 0; color: var(--border-strong); font-family: 'DM Serif Display', serif; }
765
- ```
766
-
767
- <!-- @component:evidence-list:end -->
768
-
769
- <!-- @component:chart-container:start -->
770
- #### Chart Container (.chart-container)
771
-
772
- Wrapper for any ECharts visualization. Can appear on any slide, in any layout.
773
- See §Data Visualization for chart type selection and theme-specific styling.
774
-
775
- ```html
776
- <div class="chart-container" id="chart-{purpose}"
777
- style="width:{w}px; height:{h}px"></div>
778
- ```
779
-
780
- ```css
781
- .chart-container { position: relative; flex-shrink: 0; }
782
- ```
783
-
784
- Common sizing by context:
785
- - Inside a column (`.two-col-main`, `.two-col-aside`): `width:100%; height:320–400px`
786
- - Full-width standalone: `max-width:1400px; height:500px; margin:0 auto`
787
- - Inside a `.card` (sparkline/mini): `width:100%; height:140–200px`
788
- - Below a stats row: `max-width:1200px; height:300px; margin:24px auto 0`
789
-
790
- JS init pattern (inside `window.addEventListener('load', ...)`):
791
- ```javascript
792
- if (typeof echarts !== 'undefined') {
793
- const el = document.getElementById('chart-{purpose}');
794
- if (el) {
795
- const chart = echarts.init(el, null, { renderer: 'canvas' });
796
- chart.setOption({ /* see §Data Visualization for theme options */ });
797
- }
798
- }
799
- ```
800
-
801
- <!-- @component:chart-container:end -->
802
-
803
- <!-- @component:text-helpers:start -->
804
- #### Text Helpers
805
-
806
- ```css
807
- h1 { font-family: 'DM Serif Display', serif; font-size: 64px; font-weight: 400; line-height: 1.15; letter-spacing: -0.02em; }
808
- h2 { font-family: 'DM Serif Display', serif; font-size: 42px; font-weight: 400; line-height: 1.2; letter-spacing: -0.01em; }
809
- .label { font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-muted); font-weight: 400; }
810
- .subtitle { font-size: 22px; color: var(--text-secondary); font-weight: 300; line-height: 1.6; }
811
- .body-text { font-size: 18px; color: var(--text-secondary); line-height: 1.75; }
812
- ```
813
-
814
- Use `<em>` (italic) on the single most important phrase in a heading — never bold,
815
- never color, never gradient. Max one emphasized phrase per slide.
816
-
817
- <!-- @component:text-helpers:end -->
818
-
819
- <!-- @component:dividers:start -->
820
- #### Dividers and Rules
821
-
822
- ```css
823
- .divider { border: none; border-top: 1px solid var(--border); margin: 24px 0; }
824
- .divider-wide { border: none; border-top: 1px solid var(--border); width: 300px; }
825
- .heading-rule { border: none; border-bottom: 1px solid var(--border); padding-bottom: 16px; margin-bottom: 24px; }
826
- ```
827
-
828
- - `.divider` (full-width, `1px`): structural — separate heading from content
829
- - `.divider-wide` (`300px`): decorative anchor — bottom of sparse slides
830
- - `.heading-rule` (border-bottom on heading): separate title from body on content slides
831
- - Never use gradient lines, colored borders, or thick rules
832
-
833
- <!-- @component:dividers:end -->
834
-
835
- <!-- @component:icons:start -->
836
- #### Icons (Lucide)
837
-
838
- Load via CDN: `<script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/umd/lucide.js"></script>`
839
- Use `<i data-lucide="icon-name" class="card-icon"></i>` and call `lucide.createIcons()` in JS.
840
-
841
- - Icons are **optional** in this theme — typography and whitespace provide the hierarchy
842
- - Icon color: `var(--accent-2)` (warm grey), size: `1.75rem`, hover: `scale(1.05)`
843
- - When used, pick simple stroke-style icons: `circle-dashed` → restraint, `eye` → clarity,
844
- `text` → typography, `book-open` → research, `target` → precision
845
- - Cards may include icons, but omitting them often feels more "minimal"
846
- - Stats, quotes, step flow: never add icons
847
-
848
- <!-- @component:icons:end -->
849
-
850
- <!-- @component:deco-fills:start -->
851
- #### Decorative Fills (.deco-circle, .deco-rule)
852
-
853
- Positioned-absolute background elements behind content.
854
-
855
- ```css
856
- .deco-circle { position: absolute; border-radius: 50%; pointer-events: none; z-index: 0; }
857
- .deco-rule { position: absolute; pointer-events: none; z-index: 0; }
858
-
859
- /* Ensure content stacks above decorative fills */
860
- .slide-canvas > *:not(.deco-circle):not(.deco-rule):not(.quote-deco) { position: relative; z-index: 1; }
861
- ```
862
-
863
- Set size, color, opacity, and position via inline styles:
864
- - Typical `.deco-circle`: `width:200–400px; height:same; background:rgba(255,179,71,0.04–0.06); filter:blur(30–40px)`
865
- - Typical `.deco-rule`: `width:120–200px; height:1px; background:linear-gradient(90deg, transparent, var(--border-strong), transparent); opacity:0.3–0.5`
866
- - Sparse slides (cover, quote, closing): 2–3 deco elements
867
- - Dense slides (grids, multi-column): 0 deco elements — content is the fill
868
- - Never exceed 3 per slide
869
-
870
- <!-- @component:deco-fills:end -->
871
-
872
- <!-- @section:components:end -->
873
-
874
- <!-- @section:layouts:start -->
875
- ### Layout Primitives
876
-
877
- Components can be placed in any of these layout arrangements.
878
- Mix layouts and components freely — these are tools, not templates.
879
-
880
- #### Centered Stack
881
-
882
- `.slide-canvas` default behavior — `flex-direction: column; justify-content: center`.
883
- Use for: cover, closing, quote-focused, single-statement slides.
884
-
885
- #### Top-Aligned Stack
886
-
887
- Override `.slide-canvas` with `style="justify-content: flex-start; padding-top: 80px"`.
888
- Use for: content-heavy slides where vertical space matters.
889
-
890
- #### Two-Column Grid (.two-col)
891
-
892
- ```html
893
- <div class="two-col">
894
- <div class="two-col-main"><!-- primary content --></div>
895
- <div class="two-col-aside"><!-- secondary content --></div>
896
- </div>
897
- ```
898
-
899
- ```css
900
- .two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: stretch; max-width: 1600px; margin: 0 auto; flex: 1; }
901
- .two-col-main { display: flex; flex-direction: column; justify-content: center; }
902
- .two-col-main h2 { font-size: 36px; margin-bottom: 16px; }
903
- .two-col-main p { font-size: 18px; color: var(--text-secondary); line-height: 1.75; }
904
- .two-col-aside { display: flex; flex-direction: column; justify-content: center; }
905
- .two-col-aside .card { flex: 1; }
906
- ```
907
-
908
- Either side can contain any components — cards, charts, text, evidence lists, stat cards.
909
-
910
- #### Three-Column Grid
911
-
912
- ```css
913
- .card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; max-width: 1600px; margin: 0 auto; flex: 1; align-content: stretch; }
914
- .stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; max-width: 1600px; margin: 0 auto; }
915
- ```
916
-
917
- Use `.card-grid` for cards, `.stats-row` for stat cards, or create a custom grid.
918
- For 2 items: `repeat(2, 1fr)`. For 4: `repeat(2, 1fr)` (2×2 grid).
919
- The grid container can hold any mix of components.
920
-
921
- #### Horizontal Flow
922
-
923
- Used by `.step-flow` — `display: flex; align-items: flex-start; max-width: 1600px`.
924
- Also works for timelines, comparison strips, or any horizontal sequence.
925
-
926
- <!-- @section:layouts:end -->
927
-
928
- <!-- @section:charts:start -->
929
- ### Data Visualization (ECharts)
930
-
931
- When a slide includes charts or data visualization, use [ECharts](https://echarts.apache.org/)
932
- loaded via CDN:
933
-
934
- ```html
935
- <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
936
- ```
937
-
938
- #### Chart Type Selection
939
-
940
- Choose the chart type based on the data, not by habit. Different data patterns
941
- demand different visualizations:
942
-
943
- | Data Pattern | Chart Type | Common Placements |
944
- |---|---|---|
945
- | Proportions / composition (parts of a whole) | Pie / Donut | Any layout — pair with narrative or standalone |
946
- | Trends over time (growth, decline, cycles) | Line or Area | Full-width for detail, two-col for trend + commentary |
947
- | Category comparisons (A vs B vs C) | Vertical Bar | Full-width or two-col |
948
- | Rankings / sorted magnitudes | Horizontal Bar | Full-width (labels need room) |
949
- | Distribution / histogram | Vertical Bar (binned) | Full-width |
950
- | KPIs with sparkline context | Stats Row + small Line chart below | Custom composite |
951
-
952
- Layout is not fixed — pick the layout that serves the narrative. A chart can
953
- occupy one column of Two-Column, span full-width on its own slide, or sit
954
- inside a Feature Card as a small sparkline. Let the data and story decide.
955
-
956
- #### Shared monochrome chart styles
957
-
958
- All chart types share these minimal theme defaults:
959
-
960
- - **Color palette**: `['#1A1916', '#6B6560', '#C9C4B8']` (monochrome warm — ink, mid-grey, border).
961
- For >3 series, extend with `#A09890` (muted) and `#D5D0C8` (light warm).
962
- - **Background**: `'transparent'`
963
- - **Axis labels / legend text**: `var(--text-muted)` (`#A09890`), `14px` DM Sans font
964
- - **Grid lines**: `var(--border)` (`#C9C4B8`) at 30% opacity — barely visible
965
- - **Animation**: `false` or very subtle fade-in only (consistent with minimal's stillness)
966
- - **Tooltip**: light background (`var(--bg-card)`), `var(--text-primary)` text, thin `var(--border)` border
967
-
968
- #### Pie / Donut
969
-
970
- - Inner radius `55-65%` for donut; `0` for full pie
971
- - `borderRadius: 6`, `borderColor: var(--bg-primary)`, `borderWidth: 3` for segment gaps
972
- - Center label: large text in `var(--text-primary)`, DM Serif Display font
973
- - Legend: bottom-aligned, `itemWidth: 12`, `itemGap: 20`
974
- - Container: `280–360px` square is typical
975
-
976
- #### Bar (vertical & horizontal)
977
-
978
- - No rounded caps — flat bar ends for a cleaner, more structural look
979
- - Bar width: `40-60%` of category gap — never touch adjacent bars
980
- - Solid fills only — no gradient fills (gradients break the monochrome discipline)
981
- - For ≤5 categories: one shade per bar from monochrome warm. For single-series: solid `var(--text-primary)`
982
- - Axis line: `1px` `var(--border)`. Tick marks: hidden
983
-
984
- #### Line / Area
985
-
986
- - Line width: `1.5-2px`, smooth curves (`smooth: true`) — thinner than aurora to feel quieter
987
- - No glow or shadow effects
988
- - Area fill: solid color at 6-10% opacity — no gradients
989
- - Data points: show on hover only (`symbol: 'none'`, `emphasis: { symbol: 'circle' }`)
990
- - For multiple series: distinguish with solid vs dashed lines, all within monochrome warm palette
991
-
992
- #### Integration rules
993
-
994
- - Initialize charts inside a `window.addEventListener('load', ...)` or after DOM ready
995
- - Use `echarts.init(container, null, { renderer: 'canvas' })` — canvas renderer for performance
996
- - Charts must use the monochrome warm palette — never default ECharts colors or colored accents
997
- - Responsive: charts are inside the 1920×1080 canvas, scaled by JS `transform: scale()` —
998
- no need for ECharts `resize()` handling
999
-
1000
- <!-- @section:charts:end -->
1001
-
1002
- <!-- @section:guide:start -->
1003
- ### Composition Guide
1004
-
1005
- #### Common Recipes
1006
-
1007
- These are starting points — not constraints. Combine any components with any
1008
- layout primitive as the content demands.
1009
-
1010
- | Content Pattern | Suggested Recipe | Minimal Notes |
1011
- |---|---|---|
1012
- | 3–4 parallel features | 3-col grid + card ×3 | Number labels (`01`, `02`). Icon optional. |
1013
- | Key metrics (2–4 KPIs) | 3-col grid + stat-card ×3 | Static numbers, no counter animation. DM Serif Display. |
1014
- | Narrative + evidence | two-col + serif heading in main, frosted card with evidence-list in aside | Em-dash bullets |
1015
- | Sequential process (3–5 steps) | horizontal flow + step-flow | Filled dark circles, `1px` connectors. Quiet. |
1016
- | Memorable quote | centered stack + quote-block + quote-deco | DM Serif Display italic, `border-left: 2px`. |
1017
- | Single powerful statement | centered stack + large italic heading + deco fills | `<em>` on key phrase. No gradient-text. |
1018
- | Data visualization | any layout + chart-container | Chart type per data — see §Data Visualization. Monochrome warm. |
1019
- | KPIs with trend context | 3-col grid + stat-cards, then chart below | Static numbers + supporting chart |
1020
- | Team / people (3–4) | 3-col grid + card ×3 (no icons) | card-title → name (serif), card-body → role |
1021
- | Before vs After | two-col + content per side | Serif heading + em-dash evidence-list each column |
1022
- | 6+ items on one topic | Split across 2 slides | Max 4 items per slide (stricter than other themes) |
1023
-
1024
- #### Element Usage Rules
1025
-
1026
- **Emphasis (`<em>`):** Use italic on the single most important phrase in a heading —
1027
- never bold, never color, never gradient. Typical: core concept (`clear presentation`),
1028
- key insight (`nothing left to take away`). Max one per slide.
1029
-
1030
- **Dividers:** `.divider` (full-width) for structural separation. `.divider-wide` (`300px`)
1031
- as decorative anchor at bottom of sparse slides. `.heading-rule` on content slide headings.
1032
- Never gradient lines, colored borders, or thick rules.
1033
-
1034
- **Icons (Lucide):** Optional. Typography and whitespace provide the hierarchy.
1035
- When used: simple stroke-style in `var(--accent-2)`. Cards may include icons,
1036
- but omitting often feels more "minimal." Stats, quotes, step flow: never add icons.
1037
-
1038
- **Card labels:** Sequential numbers (`01`, `02`, `03`) preferred — orderly and typographic.
1039
- Short category words acceptable when items are unordered. Omit when the title is clear.
1040
-
1041
- **Decorative fills:** Sparse slides: 2–3 deco elements (warm-amber circles, thin rules).
1042
- Dense slides: 0 — content is the fill. Never exceed 3 per slide.
1043
-
1044
- #### Common Mistakes
1045
-
1046
- - Using colored accents, gradients, or glows → stay monochrome warm.
1047
- - Adding icons to every card when the heading is already clear → less is more.
1048
- - Using counter animations on numbers → minimal uses static numbers with fade-in.
1049
- - Using more than 4 items per slide → split across slides.
1050
- - Adding decorative fills to dense content slides → content is the fill.
1051
- - Always using donut charts for data → match chart type to data pattern (see §Data Visualization).
1052
- - Leaving more than ~20% of canvas visually empty → expand content or add thin rules.
1053
-
1054
- ### Code Blocks (if any)
1055
-
1056
- ```css
1057
- pre, code {
1058
- background: #F0EEE8;
1059
- border: 1px solid var(--border);
1060
- border-radius: 6px;
1061
- font-family: 'DM Mono', 'Söhne Mono', ui-monospace, monospace;
1062
- font-size: 14px;
1063
- color: var(--text-primary);
1064
- }
1065
- ```
1066
-
1067
- ### Do & Don't
1068
-
1069
- - **Do** use light backgrounds throughout — never dark
1070
- - **Do** let the subtle geometric shapes add depth without overwhelming
1071
- - **Do** use serif headings (`DM Serif Display`) contrasted with sans-serif body (`DM Sans`)
1072
- - **Do** keep the accent monochrome — no colored accents
1073
- - **Do** use frosted-glass cards with `backdrop-filter: blur(16px)` and `rgba(255,255,255,0.55)` background
1074
- - **Do** use minimal animations — this theme values stillness
1075
- - **Don't** use gradients, glows, or colored borders
1076
- - **Don't** add too many geometric shapes — 2-3 is enough
1077
- - **Don't** use more than 4 bullet points per slide
1078
-
1079
- <!-- @section:guide:end -->