@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.
- package/README.md +3 -4
- package/README.zh-CN.md +3 -4
- package/lib/agents/research-prompt.ts +7 -3
- package/lib/config.ts +1 -1
- package/lib/design/designs.ts +97 -7
- package/lib/log.ts +3 -2
- package/lib/prompt-builder.ts +29 -50
- package/lib/qa/checks.ts +6 -49
- package/lib/qa/measure.ts +8 -7
- package/package.json +1 -1
- package/plugin.ts +15 -14
- package/skill/SKILL.md +23 -198
- package/tools/designs.ts +21 -5
- package/tools/workspace-scan.ts +17 -2
- package/designs/default/DESIGN.md +0 -1100
- package/designs/editorial-ribbon/DESIGN.md +0 -1092
- package/designs/minimal/DESIGN.md +0 -1079
|
@@ -1,1092 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: editorial-ribbon
|
|
3
|
-
description: High-contrast editorial light theme — condensed typography, vivid orange/mint ribbons, crisp print-like layouts
|
|
4
|
-
author: OpenAI
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
preview: bundled
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Visual Style — Editorial Ribbon Theme
|
|
10
|
-
|
|
11
|
-
<!-- @section:global:start -->
|
|
12
|
-
|
|
13
|
-
Apply this visual style when generating all slides in this session.
|
|
14
|
-
|
|
15
|
-
This theme keeps the existing component system and layout logic intact, but changes the art direction to an editorial annual-report look inspired by the reference: bold condensed headlines, clean off-white content pages, sharp black separators, and large diagonal ribbon shapes in saturated orange, mint, blush, and soft aqua. The result should feel like a design-forward impact report rather than a software deck.
|
|
16
|
-
|
|
17
|
-
### Core Principle
|
|
18
|
-
|
|
19
|
-
Do **not** change component layout, HTML structure, slide architecture, spacing system, or JS behavior. Only restyle surfaces, typography, color, decoration, chart treatment, and visual hierarchy.
|
|
20
|
-
|
|
21
|
-
### Color Palette
|
|
22
|
-
|
|
23
|
-
```css
|
|
24
|
-
:root {
|
|
25
|
-
--bg-primary: #F3F1ED; /* soft editorial paper */
|
|
26
|
-
--bg-secondary: #E8E5DF; /* light warm grey */
|
|
27
|
-
--bg-card: rgba(255, 255, 255, 0.72); /* translucent paper card */
|
|
28
|
-
--bg-card-solid: #F7F5F1; /* solid card fill when translucency is not desired */
|
|
29
|
-
|
|
30
|
-
--text-primary: #111111; /* near-black ink */
|
|
31
|
-
--text-secondary: #434343; /* dark neutral grey */
|
|
32
|
-
--text-muted: #7A7872; /* muted editorial caption */
|
|
33
|
-
|
|
34
|
-
--accent: #F45A2A; /* ustwo-like orange */
|
|
35
|
-
--accent-2: #87D8B8; /* mint ribbon */
|
|
36
|
-
--accent-3: #CFE8DB; /* pale mint */
|
|
37
|
-
--accent-4: #F3B7D9; /* pink/lilac accent */
|
|
38
|
-
--accent-5: #D9E6F6; /* pale blue support */
|
|
39
|
-
|
|
40
|
-
--border: rgba(17, 17, 17, 0.12);
|
|
41
|
-
--border-strong: rgba(17, 17, 17, 0.32);
|
|
42
|
-
--shadow-soft: 0 8px 30px rgba(0, 0, 0, 0.06);
|
|
43
|
-
--shadow-strong: 0 18px 50px rgba(0, 0, 0, 0.10);
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
### Typography
|
|
48
|
-
|
|
49
|
-
- **Display font**: `Oswald` — for all major headings, section titles, stat labels that need the compressed editorial feel.
|
|
50
|
-
- **Body font**: `Inter` — for paragraph text, labels, captions, lists, and UI.
|
|
51
|
-
- Font link tag:
|
|
52
|
-
```html
|
|
53
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
54
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Oswald:wght@300;400;500;600&display=swap" rel="stylesheet">
|
|
55
|
-
```
|
|
56
|
-
- Title size (h1): `92px`, weight 500, uppercase by default
|
|
57
|
-
- Section heading (h2): `58px`, weight 500, uppercase by default
|
|
58
|
-
- Subtitle size: `22px`, weight 400
|
|
59
|
-
- Body size: `18px`
|
|
60
|
-
- Label: `13px`, letter-spacing `0.12em`, uppercase
|
|
61
|
-
- Card title: `28px` (`Oswald`)
|
|
62
|
-
- Card body: `17px`
|
|
63
|
-
- Stat number: `72px`, weight 500
|
|
64
|
-
- Stat label: `15px`, uppercase
|
|
65
|
-
- Line height: `1.6` for body, `0.96` for h1, `1.0` for h2
|
|
66
|
-
- Letter spacing: `-0.02em` for large headings
|
|
67
|
-
|
|
68
|
-
All sizes are fixed `px` for the 1920×1080 canvas. Do not use `clamp()` or viewport-relative units.
|
|
69
|
-
|
|
70
|
-
### Background Layers
|
|
71
|
-
|
|
72
|
-
This theme uses clean paper backgrounds on most slides, and stronger graphic treatment on cover or section-divider slides.
|
|
73
|
-
|
|
74
|
-
**Layer 1 — Editorial paper base:**
|
|
75
|
-
```css
|
|
76
|
-
body::before {
|
|
77
|
-
content: '';
|
|
78
|
-
position: fixed;
|
|
79
|
-
inset: 0;
|
|
80
|
-
background:
|
|
81
|
-
linear-gradient(180deg, #F4F1EC 0%, #F0ECE6 100%);
|
|
82
|
-
z-index: -4;
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
**Layer 2 — Faint print grain:**
|
|
87
|
-
```css
|
|
88
|
-
body::after {
|
|
89
|
-
content: '';
|
|
90
|
-
position: fixed;
|
|
91
|
-
inset: 0;
|
|
92
|
-
background-image:
|
|
93
|
-
radial-gradient(rgba(0,0,0,0.025) 0.6px, transparent 0.6px);
|
|
94
|
-
background-size: 10px 10px;
|
|
95
|
-
opacity: 0.20;
|
|
96
|
-
z-index: -3;
|
|
97
|
-
pointer-events: none;
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
**Layer 3 — Ribbon / panel shapes:**
|
|
102
|
-
```css
|
|
103
|
-
.geo-shape-1, .geo-shape-2, .geo-shape-3 {
|
|
104
|
-
position: fixed;
|
|
105
|
-
pointer-events: none;
|
|
106
|
-
z-index: -2;
|
|
107
|
-
opacity: 0.95;
|
|
108
|
-
}
|
|
109
|
-
.geo-shape-1 {
|
|
110
|
-
width: 1200px;
|
|
111
|
-
height: 1200px;
|
|
112
|
-
right: -320px;
|
|
113
|
-
top: -220px;
|
|
114
|
-
background: linear-gradient(135deg, var(--accent-2) 0%, var(--accent-3) 100%);
|
|
115
|
-
clip-path: polygon(32% 0, 100% 0, 100% 100%, 60% 100%, 16% 48%);
|
|
116
|
-
}
|
|
117
|
-
.geo-shape-2 {
|
|
118
|
-
width: 960px;
|
|
119
|
-
height: 960px;
|
|
120
|
-
left: -200px;
|
|
121
|
-
top: -120px;
|
|
122
|
-
background: linear-gradient(135deg, #D93C09 0%, var(--accent) 55%, #F86D3E 100%);
|
|
123
|
-
clip-path: polygon(0 0, 78% 0, 42% 100%, 0 100%);
|
|
124
|
-
}
|
|
125
|
-
.geo-shape-3 {
|
|
126
|
-
width: 760px;
|
|
127
|
-
height: 760px;
|
|
128
|
-
right: 280px;
|
|
129
|
-
top: 160px;
|
|
130
|
-
background: radial-gradient(circle at 30% 60%, rgba(32,180,126,0.95) 0%, rgba(135,216,184,0.82) 35%, rgba(135,216,184,0) 72%);
|
|
131
|
-
filter: blur(24px);
|
|
132
|
-
border-radius: 40% 60% 52% 48% / 58% 38% 62% 42%;
|
|
133
|
-
opacity: 0.75;
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Slide Layout
|
|
138
|
-
|
|
139
|
-
- **1920×1080 fixed canvas** — each slide uses a `.slide-canvas` (1920×1080px),
|
|
140
|
-
scaled to fit the viewport via JS `transform: scale()`.
|
|
141
|
-
- Content width tiers (inside canvas, via `max-width` + `margin: 0 auto`):
|
|
142
|
-
- Default (`1200px`): Cover, Quote, Closing
|
|
143
|
-
- Wide (`1600px`): content-heavy slides (grids, multi-column, process flows)
|
|
144
|
-
- Canvas padding: `60px 80px`
|
|
145
|
-
- **No `clamp()` — use fixed `px` for all sizes.** The canvas is always
|
|
146
|
-
1920×1080 and JS handles scaling, so all typography and spacing must be fixed `px`.
|
|
147
|
-
- **Canvas utilization** — Elements should fill approximately 70–80% of the
|
|
148
|
-
1920×1080 canvas area. The editorial feel comes from bold typography and
|
|
149
|
-
controlled whitespace, not from leaving the canvas half-empty.
|
|
150
|
-
- **Content slides**: feel like clean report pages on soft paper. Grid/flex
|
|
151
|
-
containers should stretch toward the canvas edges. Cards should have ample
|
|
152
|
-
internal padding and body text so they feel substantial.
|
|
153
|
-
- **Cover and section-divider slides**: feel graphic and poster-like. Use
|
|
154
|
-
oversized condensed headlines, vivid ribbon shapes, and strong asymmetrical
|
|
155
|
-
compositions. Add decorative fills — diagonal ribbon blocks, gradient rules,
|
|
156
|
-
or large typographic ornaments.
|
|
157
|
-
- **Never** leave more than ~20% of the canvas visually empty on any slide.
|
|
158
|
-
- Title slide: large condensed uppercase heading + graphic ribbon decoration
|
|
159
|
-
- Content slides: heading top with rule separator, content below in clean editorial blocks
|
|
160
|
-
|
|
161
|
-
### HTML Structure
|
|
162
|
-
|
|
163
|
-
Every generated presentation must use this exact HTML skeleton:
|
|
164
|
-
|
|
165
|
-
```html
|
|
166
|
-
<!DOCTYPE html>
|
|
167
|
-
<html lang="{language}">
|
|
168
|
-
<head>
|
|
169
|
-
<meta charset="UTF-8">
|
|
170
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
171
|
-
<title>{Presentation Title}</title>
|
|
172
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
173
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&family=Oswald:wght@300;400;500;600&display=swap" rel="stylesheet">
|
|
174
|
-
<script src="https://cdn.jsdelivr.net/npm/lucide@latest/dist/umd/lucide.js"></script>
|
|
175
|
-
<!-- <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> ← only if charts needed -->
|
|
176
|
-
<style>/* all CSS here */</style>
|
|
177
|
-
</head>
|
|
178
|
-
<body>
|
|
179
|
-
<!-- Geometric ribbon shapes -->
|
|
180
|
-
<div class="geo-shape-1"></div>
|
|
181
|
-
<div class="geo-shape-2"></div>
|
|
182
|
-
<div class="geo-shape-3"></div>
|
|
183
|
-
|
|
184
|
-
<!-- Navigation -->
|
|
185
|
-
<div class="progress-bar" id="progressBar"></div>
|
|
186
|
-
<nav class="nav-dots" id="navDots" aria-label="Slide navigation"></nav>
|
|
187
|
-
|
|
188
|
-
<!-- Slides -->
|
|
189
|
-
<section class="slide title-slide" data-slide-type="cover" data-index="0">
|
|
190
|
-
<div class="slide-canvas"> ... </div>
|
|
191
|
-
</section>
|
|
192
|
-
<section class="slide" data-slide-type="content" data-index="1">
|
|
193
|
-
<div class="slide-canvas"> ... </div>
|
|
194
|
-
</section>
|
|
195
|
-
<!-- every <section class="slide"> must have data-slide-type — see SKILL.md for valid values -->
|
|
196
|
-
|
|
197
|
-
<script>/* all JS here */</script>
|
|
198
|
-
</body>
|
|
199
|
-
</html>
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
### Core CSS
|
|
203
|
-
|
|
204
|
-
```css
|
|
205
|
-
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
206
|
-
|
|
207
|
-
html {
|
|
208
|
-
scroll-snap-type: y mandatory;
|
|
209
|
-
overflow-y: scroll;
|
|
210
|
-
height: 100%;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
body {
|
|
214
|
-
background: var(--bg-primary);
|
|
215
|
-
color: var(--text-primary);
|
|
216
|
-
font-family: 'Inter', ui-sans-serif, sans-serif;
|
|
217
|
-
-webkit-font-smoothing: antialiased;
|
|
218
|
-
height: 100%;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.slide {
|
|
222
|
-
height: 100dvh;
|
|
223
|
-
scroll-snap-align: start;
|
|
224
|
-
overflow: hidden;
|
|
225
|
-
display: flex;
|
|
226
|
-
align-items: center;
|
|
227
|
-
justify-content: center;
|
|
228
|
-
background: transparent;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.slide-canvas {
|
|
232
|
-
width: 1920px;
|
|
233
|
-
height: 1080px;
|
|
234
|
-
flex-shrink: 0;
|
|
235
|
-
transform-origin: center center;
|
|
236
|
-
overflow: hidden;
|
|
237
|
-
position: relative;
|
|
238
|
-
display: flex;
|
|
239
|
-
flex-direction: column;
|
|
240
|
-
justify-content: center;
|
|
241
|
-
padding: 60px 80px;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
/* Default content-slide treatment: editorial page */
|
|
245
|
-
.slide:not(.title-slide) .slide-canvas {
|
|
246
|
-
background: linear-gradient(180deg, rgba(255,255,255,0.34) 0%, rgba(255,255,255,0.14) 100%);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
/* Cover slide gets graphic treatment */
|
|
250
|
-
.title-slide .slide-canvas {
|
|
251
|
-
background: #0D0D0D;
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### Navigation & Progress
|
|
256
|
-
|
|
257
|
-
```css
|
|
258
|
-
.progress-bar {
|
|
259
|
-
position: fixed;
|
|
260
|
-
top: 0;
|
|
261
|
-
left: 0;
|
|
262
|
-
height: 3px;
|
|
263
|
-
background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
|
|
264
|
-
width: 0%;
|
|
265
|
-
z-index: 100;
|
|
266
|
-
transition: width 0.2s ease;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.nav-dots {
|
|
270
|
-
position: fixed;
|
|
271
|
-
right: 20px;
|
|
272
|
-
top: 50%;
|
|
273
|
-
transform: translateY(-50%);
|
|
274
|
-
display: flex;
|
|
275
|
-
flex-direction: column;
|
|
276
|
-
gap: 9px;
|
|
277
|
-
z-index: 100;
|
|
278
|
-
}
|
|
279
|
-
.nav-dots button {
|
|
280
|
-
width: 8px;
|
|
281
|
-
height: 8px;
|
|
282
|
-
border-radius: 50%;
|
|
283
|
-
border: 1px solid rgba(17,17,17,0.35);
|
|
284
|
-
background: rgba(255,255,255,0.45);
|
|
285
|
-
cursor: pointer;
|
|
286
|
-
padding: 0;
|
|
287
|
-
transition: transform 0.2s ease, background 0.2s ease;
|
|
288
|
-
}
|
|
289
|
-
.nav-dots button.active {
|
|
290
|
-
background: var(--accent);
|
|
291
|
-
border-color: var(--accent);
|
|
292
|
-
transform: scale(1.1);
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### Reduced Motion
|
|
297
|
-
|
|
298
|
-
```css
|
|
299
|
-
@media (prefers-reduced-motion: reduce) {
|
|
300
|
-
.reveal {
|
|
301
|
-
transition: opacity 0.3s ease;
|
|
302
|
-
opacity: 1;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
### SlidePresentation Class (Complete JavaScript)
|
|
308
|
-
|
|
309
|
-
Keep the original `SlidePresentation` class unchanged.
|
|
310
|
-
|
|
311
|
-
```javascript
|
|
312
|
-
class SlidePresentation {
|
|
313
|
-
constructor() {
|
|
314
|
-
this.slides = document.querySelectorAll('.slide');
|
|
315
|
-
this.currentSlide = 0;
|
|
316
|
-
this.setupScaling();
|
|
317
|
-
this.setupProgressBar();
|
|
318
|
-
this.setupNavDots();
|
|
319
|
-
this.setupIntersectionObserver();
|
|
320
|
-
this.setupKeyboardNav();
|
|
321
|
-
this.setupTouchNav();
|
|
322
|
-
this.setupMouseWheel();
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
setupScaling() {
|
|
326
|
-
const canvases = document.querySelectorAll('.slide-canvas');
|
|
327
|
-
const BASE_W = 1920, BASE_H = 1080;
|
|
328
|
-
const update = () => {
|
|
329
|
-
const vw = window.innerWidth;
|
|
330
|
-
const vh = window.innerHeight;
|
|
331
|
-
const scale = Math.min(vw / BASE_W, vh / BASE_H);
|
|
332
|
-
canvases.forEach(c => { c.style.transform = `scale(${scale})`; });
|
|
333
|
-
};
|
|
334
|
-
window.addEventListener('resize', update);
|
|
335
|
-
update();
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
setupProgressBar() {
|
|
339
|
-
const bar = document.getElementById('progressBar');
|
|
340
|
-
const update = () => {
|
|
341
|
-
const scrolled = window.scrollY;
|
|
342
|
-
const total = document.body.scrollHeight - window.innerHeight;
|
|
343
|
-
bar.style.width = total > 0 ? (scrolled / total * 100) + '%' : '0%';
|
|
344
|
-
};
|
|
345
|
-
window.addEventListener('scroll', update, { passive: true });
|
|
346
|
-
update();
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
setupNavDots() {
|
|
350
|
-
const nav = document.getElementById('navDots');
|
|
351
|
-
this.slides.forEach((_, i) => {
|
|
352
|
-
const btn = document.createElement('button');
|
|
353
|
-
btn.setAttribute('aria-label', `Go to slide ${i + 1}`);
|
|
354
|
-
if (i === 0) btn.classList.add('active');
|
|
355
|
-
btn.addEventListener('click', () => this.goTo(i));
|
|
356
|
-
nav.appendChild(btn);
|
|
357
|
-
});
|
|
358
|
-
this.dots = nav.querySelectorAll('button');
|
|
359
|
-
|
|
360
|
-
const obs = new IntersectionObserver((entries) => {
|
|
361
|
-
entries.forEach(e => {
|
|
362
|
-
if (e.isIntersecting) {
|
|
363
|
-
const idx = parseInt(e.target.dataset.index);
|
|
364
|
-
this.dots.forEach((d, i) => d.classList.toggle('active', i === idx));
|
|
365
|
-
this.currentSlide = idx;
|
|
366
|
-
}
|
|
367
|
-
});
|
|
368
|
-
}, { threshold: 0.5 });
|
|
369
|
-
this.slides.forEach(s => obs.observe(s));
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
setupIntersectionObserver() {
|
|
373
|
-
const obs = new IntersectionObserver((entries) => {
|
|
374
|
-
entries.forEach(e => {
|
|
375
|
-
if (e.isIntersecting) {
|
|
376
|
-
e.target.querySelectorAll('.reveal').forEach(el => el.classList.add('visible'));
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
}, { threshold: 0.15 });
|
|
380
|
-
this.slides.forEach(s => obs.observe(s));
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
setupKeyboardNav() {
|
|
384
|
-
document.addEventListener('keydown', e => {
|
|
385
|
-
if (['ArrowDown', 'ArrowRight', ' ', 'PageDown'].includes(e.key)) {
|
|
386
|
-
e.preventDefault();
|
|
387
|
-
this.goTo(this.currentSlide + 1);
|
|
388
|
-
} else if (['ArrowUp', 'ArrowLeft', 'PageUp'].includes(e.key)) {
|
|
389
|
-
e.preventDefault();
|
|
390
|
-
this.goTo(this.currentSlide - 1);
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
setupTouchNav() {
|
|
396
|
-
let startY = 0;
|
|
397
|
-
document.addEventListener('touchstart', e => { startY = e.touches[0].clientY; }, { passive: true });
|
|
398
|
-
document.addEventListener('touchend', e => {
|
|
399
|
-
const dy = startY - e.changedTouches[0].clientY;
|
|
400
|
-
if (Math.abs(dy) > 40) this.goTo(this.currentSlide + (dy > 0 ? 1 : -1));
|
|
401
|
-
}, { passive: true });
|
|
402
|
-
}
|
|
403
|
-
|
|
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
|
-
goTo(idx) {
|
|
415
|
-
const clamped = Math.max(0, Math.min(this.slides.length - 1, idx));
|
|
416
|
-
this.slides[clamped].scrollIntoView({ behavior: 'smooth' });
|
|
417
|
-
this.currentSlide = clamped;
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
new SlidePresentation();
|
|
422
|
-
```
|
|
423
|
-
|
|
424
|
-
After the class, still include:
|
|
425
|
-
1. `lucide.createIcons();` if icons are used
|
|
426
|
-
2. ECharts initialization if charts are present
|
|
427
|
-
3. Inline editing code
|
|
428
|
-
|
|
429
|
-
<!-- @section:global:end -->
|
|
430
|
-
|
|
431
|
-
### Component Library
|
|
432
|
-
|
|
433
|
-
All component layout and HTML structure remain unchanged. Only art direction changes.
|
|
434
|
-
|
|
435
|
-
<!-- @section:components:start -->
|
|
436
|
-
|
|
437
|
-
<!-- @component:reveal:start -->
|
|
438
|
-
#### Reveal Animation (.reveal)
|
|
439
|
-
|
|
440
|
-
Keep the same behavior, but make the fade slightly snappier.
|
|
441
|
-
|
|
442
|
-
```css
|
|
443
|
-
.reveal {
|
|
444
|
-
opacity: 0;
|
|
445
|
-
transition: opacity 0.32s ease;
|
|
446
|
-
}
|
|
447
|
-
.reveal.visible {
|
|
448
|
-
opacity: 1;
|
|
449
|
-
}
|
|
450
|
-
.reveal:nth-child(1) { transition-delay: 0s; }
|
|
451
|
-
.reveal:nth-child(2) { transition-delay: 0.05s; }
|
|
452
|
-
.reveal:nth-child(3) { transition-delay: 0.10s; }
|
|
453
|
-
.reveal:nth-child(4) { transition-delay: 0.15s; }
|
|
454
|
-
.reveal:nth-child(5) { transition-delay: 0.20s; }
|
|
455
|
-
.reveal:nth-child(6) { transition-delay: 0.25s; }
|
|
456
|
-
.reveal:nth-child(7) { transition-delay: 0.30s; }
|
|
457
|
-
.reveal:nth-child(8) { transition-delay: 0.35s; }
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
<!-- @component:reveal:end -->
|
|
461
|
-
|
|
462
|
-
<!-- @component:showcase:start -->
|
|
463
|
-
#### Showcase (.showcase)
|
|
464
|
-
|
|
465
|
-
Semi-transparent container that frames a component or image with padding and
|
|
466
|
-
visual depth. Use inside `.two-col-aside`, `.two-col-main`, or as a standalone
|
|
467
|
-
wrapper when a component needs a "stage" rather than sitting directly on the
|
|
468
|
-
slide background. Vertically and horizontally centers its content.
|
|
469
|
-
|
|
470
|
-
```css
|
|
471
|
-
.showcase {
|
|
472
|
-
padding: 28px;
|
|
473
|
-
border: 1px solid rgba(17, 17, 17, 0.10);
|
|
474
|
-
background: rgba(255, 255, 255, 0.42);
|
|
475
|
-
display: flex;
|
|
476
|
-
align-items: center;
|
|
477
|
-
justify-content: center;
|
|
478
|
-
flex: 1;
|
|
479
|
-
}
|
|
480
|
-
.title-slide .showcase {
|
|
481
|
-
background: rgba(255, 255, 255, 0.05);
|
|
482
|
-
border-color: rgba(255, 255, 255, 0.12);
|
|
483
|
-
}
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
<!-- @component:showcase:end -->
|
|
487
|
-
|
|
488
|
-
<!-- @component:card:start -->
|
|
489
|
-
#### Card (.card)
|
|
490
|
-
|
|
491
|
-
Cards should feel like editorial blocks placed on paper, not glassmorphism widgets.
|
|
492
|
-
|
|
493
|
-
```html
|
|
494
|
-
<div class="card">
|
|
495
|
-
<i data-lucide="circle-dashed" class="card-icon"></i>
|
|
496
|
-
<p class="card-label">01</p>
|
|
497
|
-
<p class="card-title">Title</p>
|
|
498
|
-
<p class="card-body">Body text describing the item.</p>
|
|
499
|
-
</div>
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
```css
|
|
503
|
-
.card {
|
|
504
|
-
background: linear-gradient(180deg, rgba(255,255,255,0.78) 0%, rgba(250,248,244,0.92) 100%);
|
|
505
|
-
backdrop-filter: blur(8px);
|
|
506
|
-
-webkit-backdrop-filter: blur(8px);
|
|
507
|
-
border: 1px solid rgba(17,17,17,0.10);
|
|
508
|
-
border-radius: 0;
|
|
509
|
-
padding: 30px;
|
|
510
|
-
box-shadow: var(--shadow-soft);
|
|
511
|
-
display: flex;
|
|
512
|
-
flex-direction: column;
|
|
513
|
-
justify-content: flex-start;
|
|
514
|
-
transition: transform 0.22s ease, box-shadow 0.22s ease;
|
|
515
|
-
position: relative;
|
|
516
|
-
overflow: hidden;
|
|
517
|
-
}
|
|
518
|
-
.card::before {
|
|
519
|
-
content: '';
|
|
520
|
-
position: absolute;
|
|
521
|
-
left: 0;
|
|
522
|
-
top: 0;
|
|
523
|
-
width: 8px;
|
|
524
|
-
height: 100%;
|
|
525
|
-
background: linear-gradient(180deg, var(--accent) 0%, var(--accent-2) 100%);
|
|
526
|
-
opacity: 0.92;
|
|
527
|
-
}
|
|
528
|
-
.card:hover {
|
|
529
|
-
transform: translateY(-2px);
|
|
530
|
-
box-shadow: var(--shadow-strong);
|
|
531
|
-
}
|
|
532
|
-
.card-icon {
|
|
533
|
-
width: 26px;
|
|
534
|
-
height: 26px;
|
|
535
|
-
color: var(--accent);
|
|
536
|
-
margin-bottom: 14px;
|
|
537
|
-
transition: transform 0.2s ease;
|
|
538
|
-
}
|
|
539
|
-
.card:hover .card-icon { transform: scale(1.05); }
|
|
540
|
-
.card-label {
|
|
541
|
-
font-size: 13px;
|
|
542
|
-
letter-spacing: 0.12em;
|
|
543
|
-
text-transform: uppercase;
|
|
544
|
-
color: var(--text-muted);
|
|
545
|
-
margin-bottom: 10px;
|
|
546
|
-
padding-left: 0;
|
|
547
|
-
}
|
|
548
|
-
.card-title {
|
|
549
|
-
font-family: 'Oswald', sans-serif;
|
|
550
|
-
font-size: 28px;
|
|
551
|
-
line-height: 1.0;
|
|
552
|
-
text-transform: uppercase;
|
|
553
|
-
letter-spacing: -0.01em;
|
|
554
|
-
margin-bottom: 14px;
|
|
555
|
-
}
|
|
556
|
-
.card-body {
|
|
557
|
-
font-size: 17px;
|
|
558
|
-
color: var(--text-secondary);
|
|
559
|
-
line-height: 1.65;
|
|
560
|
-
flex: 1;
|
|
561
|
-
}
|
|
562
|
-
```
|
|
563
|
-
|
|
564
|
-
<!-- @component:card:end -->
|
|
565
|
-
|
|
566
|
-
<!-- @component:image-card:start -->
|
|
567
|
-
#### Image Card (.image-card)
|
|
568
|
-
|
|
569
|
-
```css
|
|
570
|
-
.image-card {
|
|
571
|
-
border-radius: 0;
|
|
572
|
-
overflow: hidden;
|
|
573
|
-
border: 1px solid rgba(17,17,17,0.10);
|
|
574
|
-
box-shadow: var(--shadow-soft);
|
|
575
|
-
background: #FFFFFF;
|
|
576
|
-
display: flex;
|
|
577
|
-
flex-direction: column;
|
|
578
|
-
}
|
|
579
|
-
.image-card img {
|
|
580
|
-
width: 100%;
|
|
581
|
-
height: 100%;
|
|
582
|
-
object-fit: cover;
|
|
583
|
-
display: block;
|
|
584
|
-
}
|
|
585
|
-
.image-card-caption {
|
|
586
|
-
padding: 14px 18px;
|
|
587
|
-
font-size: 14px;
|
|
588
|
-
color: var(--text-muted);
|
|
589
|
-
background: #FBF9F5;
|
|
590
|
-
border-top: 1px solid rgba(17,17,17,0.08);
|
|
591
|
-
font-family: 'Inter', sans-serif;
|
|
592
|
-
}
|
|
593
|
-
```
|
|
594
|
-
|
|
595
|
-
<!-- @component:image-card:end -->
|
|
596
|
-
|
|
597
|
-
<!-- @component:card-img:start -->
|
|
598
|
-
#### Card with Image Header (.card-img)
|
|
599
|
-
|
|
600
|
-
```css
|
|
601
|
-
.card-img {
|
|
602
|
-
padding: 0;
|
|
603
|
-
overflow: hidden;
|
|
604
|
-
}
|
|
605
|
-
.card-img-top {
|
|
606
|
-
width: 100%;
|
|
607
|
-
aspect-ratio: 16 / 10;
|
|
608
|
-
overflow: hidden;
|
|
609
|
-
position: relative;
|
|
610
|
-
}
|
|
611
|
-
.card-img-top::after {
|
|
612
|
-
content: '';
|
|
613
|
-
position: absolute;
|
|
614
|
-
inset: auto 0 0 0;
|
|
615
|
-
height: 8px;
|
|
616
|
-
background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
|
|
617
|
-
}
|
|
618
|
-
.card-img-top img {
|
|
619
|
-
width: 100%;
|
|
620
|
-
height: 100%;
|
|
621
|
-
object-fit: cover;
|
|
622
|
-
display: block;
|
|
623
|
-
}
|
|
624
|
-
.card-img .card-title,
|
|
625
|
-
.card-img .card-body,
|
|
626
|
-
.card-img .card-label {
|
|
627
|
-
padding-left: 30px;
|
|
628
|
-
padding-right: 30px;
|
|
629
|
-
}
|
|
630
|
-
.card-img .card-title { padding-top: 22px; }
|
|
631
|
-
.card-img .card-body { padding-bottom: 30px; }
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
<!-- @component:card-img:end -->
|
|
635
|
-
|
|
636
|
-
<!-- @component:avatar:start -->
|
|
637
|
-
#### Avatar (.avatar)
|
|
638
|
-
|
|
639
|
-
```css
|
|
640
|
-
.avatar {
|
|
641
|
-
width: 64px;
|
|
642
|
-
height: 64px;
|
|
643
|
-
border-radius: 50%;
|
|
644
|
-
object-fit: cover;
|
|
645
|
-
border: 3px solid #FFFFFF;
|
|
646
|
-
box-shadow: 0 0 0 1px rgba(17,17,17,0.12);
|
|
647
|
-
flex-shrink: 0;
|
|
648
|
-
}
|
|
649
|
-
.avatar-sm { width: 48px; height: 48px; }
|
|
650
|
-
.avatar-lg { width: 96px; height: 96px; }
|
|
651
|
-
```
|
|
652
|
-
|
|
653
|
-
<!-- @component:avatar:end -->
|
|
654
|
-
|
|
655
|
-
<!-- @component:stat-card:start -->
|
|
656
|
-
#### Stat Card (.stat-card)
|
|
657
|
-
|
|
658
|
-
Stat cards should feel graphic and report-like.
|
|
659
|
-
|
|
660
|
-
```css
|
|
661
|
-
.stat-card {
|
|
662
|
-
background: linear-gradient(180deg, rgba(255,255,255,0.86) 0%, rgba(249,246,241,0.96) 100%);
|
|
663
|
-
border: 1px solid rgba(17,17,17,0.10);
|
|
664
|
-
border-radius: 0;
|
|
665
|
-
padding: 48px 40px;
|
|
666
|
-
text-align: center;
|
|
667
|
-
box-shadow: var(--shadow-soft);
|
|
668
|
-
position: relative;
|
|
669
|
-
overflow: hidden;
|
|
670
|
-
display: flex;
|
|
671
|
-
flex-direction: column;
|
|
672
|
-
align-items: center;
|
|
673
|
-
justify-content: center;
|
|
674
|
-
}
|
|
675
|
-
.stat-card::before {
|
|
676
|
-
content: '';
|
|
677
|
-
position: absolute;
|
|
678
|
-
inset: 0 auto auto 0;
|
|
679
|
-
width: 100%;
|
|
680
|
-
height: 6px;
|
|
681
|
-
background: linear-gradient(90deg, var(--accent) 0%, var(--accent-4) 52%, var(--accent-2) 100%);
|
|
682
|
-
}
|
|
683
|
-
.stat-number {
|
|
684
|
-
font-family: 'Oswald', sans-serif;
|
|
685
|
-
font-size: 72px;
|
|
686
|
-
font-weight: 500;
|
|
687
|
-
color: var(--text-primary);
|
|
688
|
-
line-height: 0.95;
|
|
689
|
-
letter-spacing: -0.03em;
|
|
690
|
-
margin-bottom: 12px;
|
|
691
|
-
}
|
|
692
|
-
.stat-label {
|
|
693
|
-
font-size: 15px;
|
|
694
|
-
color: var(--text-muted);
|
|
695
|
-
text-transform: uppercase;
|
|
696
|
-
letter-spacing: 0.12em;
|
|
697
|
-
margin-bottom: 12px;
|
|
698
|
-
}
|
|
699
|
-
.stat-desc {
|
|
700
|
-
font-size: 15px;
|
|
701
|
-
color: var(--text-secondary);
|
|
702
|
-
line-height: 1.5;
|
|
703
|
-
}
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
<!-- @component:stat-card:end -->
|
|
707
|
-
|
|
708
|
-
<!-- @component:quote-block:start -->
|
|
709
|
-
#### Quote Block (.quote-block)
|
|
710
|
-
|
|
711
|
-
```css
|
|
712
|
-
.quote-block {
|
|
713
|
-
display: flex;
|
|
714
|
-
flex-direction: column;
|
|
715
|
-
justify-content: center;
|
|
716
|
-
border-left: 8px solid var(--accent);
|
|
717
|
-
padding-left: 32px;
|
|
718
|
-
max-width: 1200px;
|
|
719
|
-
}
|
|
720
|
-
.quote-block blockquote {
|
|
721
|
-
font-family: 'Oswald', sans-serif;
|
|
722
|
-
font-size: 52px;
|
|
723
|
-
font-weight: 400;
|
|
724
|
-
text-transform: uppercase;
|
|
725
|
-
line-height: 1.02;
|
|
726
|
-
letter-spacing: -0.02em;
|
|
727
|
-
margin-bottom: 18px;
|
|
728
|
-
}
|
|
729
|
-
.quote-block cite {
|
|
730
|
-
font-size: 14px;
|
|
731
|
-
color: var(--text-muted);
|
|
732
|
-
letter-spacing: 0.08em;
|
|
733
|
-
text-transform: uppercase;
|
|
734
|
-
font-style: normal;
|
|
735
|
-
font-family: 'Inter', sans-serif;
|
|
736
|
-
}
|
|
737
|
-
.quote-deco {
|
|
738
|
-
position: absolute;
|
|
739
|
-
font-family: 'Oswald', sans-serif;
|
|
740
|
-
font-size: 320px;
|
|
741
|
-
line-height: 0.8;
|
|
742
|
-
color: rgba(244,90,42,0.10);
|
|
743
|
-
pointer-events: none;
|
|
744
|
-
z-index: 0;
|
|
745
|
-
}
|
|
746
|
-
```
|
|
747
|
-
|
|
748
|
-
<!-- @component:quote-block:end -->
|
|
749
|
-
|
|
750
|
-
<!-- @component:step-flow:start -->
|
|
751
|
-
#### Step Flow (.step-flow)
|
|
752
|
-
|
|
753
|
-
```css
|
|
754
|
-
.step-flow { display: flex; align-items: flex-start; max-width: 1600px; margin: 0 auto; }
|
|
755
|
-
.step { flex: 1; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 16px; }
|
|
756
|
-
.step-circle {
|
|
757
|
-
width: 66px;
|
|
758
|
-
height: 66px;
|
|
759
|
-
border-radius: 50%;
|
|
760
|
-
background: linear-gradient(135deg, var(--accent) 0%, #E24216 100%);
|
|
761
|
-
color: #FFFFFF;
|
|
762
|
-
font-family: 'Oswald', sans-serif;
|
|
763
|
-
font-size: 26px;
|
|
764
|
-
font-weight: 500;
|
|
765
|
-
display: flex;
|
|
766
|
-
align-items: center;
|
|
767
|
-
justify-content: center;
|
|
768
|
-
flex-shrink: 0;
|
|
769
|
-
box-shadow: 0 8px 18px rgba(244, 90, 42, 0.22);
|
|
770
|
-
}
|
|
771
|
-
.step-connector {
|
|
772
|
-
flex: 0 0 32px;
|
|
773
|
-
height: 4px;
|
|
774
|
-
background: linear-gradient(90deg, var(--accent-4) 0%, var(--accent-2) 100%);
|
|
775
|
-
margin-top: 31px;
|
|
776
|
-
align-self: flex-start;
|
|
777
|
-
}
|
|
778
|
-
.step-title {
|
|
779
|
-
font-family: 'Oswald', sans-serif;
|
|
780
|
-
font-size: 22px;
|
|
781
|
-
line-height: 1.0;
|
|
782
|
-
text-transform: uppercase;
|
|
783
|
-
}
|
|
784
|
-
.step-desc {
|
|
785
|
-
font-size: 16px;
|
|
786
|
-
color: var(--text-secondary);
|
|
787
|
-
line-height: 1.55;
|
|
788
|
-
max-width: 220px;
|
|
789
|
-
}
|
|
790
|
-
```
|
|
791
|
-
|
|
792
|
-
<!-- @component:step-flow:end -->
|
|
793
|
-
|
|
794
|
-
<!-- @component:evidence-list:start -->
|
|
795
|
-
#### Evidence List (.evidence-list)
|
|
796
|
-
|
|
797
|
-
```css
|
|
798
|
-
.evidence-list {
|
|
799
|
-
list-style: none;
|
|
800
|
-
padding: 0;
|
|
801
|
-
display: flex;
|
|
802
|
-
flex-direction: column;
|
|
803
|
-
gap: 12px;
|
|
804
|
-
}
|
|
805
|
-
.evidence-list li {
|
|
806
|
-
padding-left: 20px;
|
|
807
|
-
position: relative;
|
|
808
|
-
font-size: 18px;
|
|
809
|
-
color: var(--text-primary);
|
|
810
|
-
line-height: 1.5;
|
|
811
|
-
}
|
|
812
|
-
.evidence-list li::before {
|
|
813
|
-
content: '';
|
|
814
|
-
position: absolute;
|
|
815
|
-
left: 0;
|
|
816
|
-
top: 11px;
|
|
817
|
-
width: 10px;
|
|
818
|
-
height: 3px;
|
|
819
|
-
background: var(--accent);
|
|
820
|
-
}
|
|
821
|
-
```
|
|
822
|
-
|
|
823
|
-
<!-- @component:evidence-list:end -->
|
|
824
|
-
|
|
825
|
-
<!-- @component:chart-container:start -->
|
|
826
|
-
#### Chart Container (.chart-container)
|
|
827
|
-
|
|
828
|
-
```css
|
|
829
|
-
.chart-container { position: relative; flex-shrink: 0; }
|
|
830
|
-
```
|
|
831
|
-
|
|
832
|
-
<!-- @component:chart-container:end -->
|
|
833
|
-
|
|
834
|
-
<!-- @component:text-helpers:start -->
|
|
835
|
-
### Text Helpers
|
|
836
|
-
|
|
837
|
-
```css
|
|
838
|
-
h1 {
|
|
839
|
-
font-family: 'Oswald', sans-serif;
|
|
840
|
-
font-size: 92px;
|
|
841
|
-
font-weight: 500;
|
|
842
|
-
line-height: 0.96;
|
|
843
|
-
letter-spacing: -0.02em;
|
|
844
|
-
text-transform: uppercase;
|
|
845
|
-
}
|
|
846
|
-
h2 {
|
|
847
|
-
font-family: 'Oswald', sans-serif;
|
|
848
|
-
font-size: 58px;
|
|
849
|
-
font-weight: 500;
|
|
850
|
-
line-height: 1.0;
|
|
851
|
-
letter-spacing: -0.02em;
|
|
852
|
-
text-transform: uppercase;
|
|
853
|
-
}
|
|
854
|
-
.label {
|
|
855
|
-
font-size: 13px;
|
|
856
|
-
letter-spacing: 0.12em;
|
|
857
|
-
text-transform: uppercase;
|
|
858
|
-
color: var(--text-muted);
|
|
859
|
-
font-weight: 500;
|
|
860
|
-
}
|
|
861
|
-
.subtitle {
|
|
862
|
-
font-size: 22px;
|
|
863
|
-
color: var(--text-secondary);
|
|
864
|
-
font-weight: 400;
|
|
865
|
-
line-height: 1.55;
|
|
866
|
-
}
|
|
867
|
-
.body-text {
|
|
868
|
-
font-size: 18px;
|
|
869
|
-
color: var(--text-secondary);
|
|
870
|
-
line-height: 1.68;
|
|
871
|
-
}
|
|
872
|
-
```
|
|
873
|
-
|
|
874
|
-
Rules for text:
|
|
875
|
-
- Headings should default to uppercase.
|
|
876
|
-
- Major titles should be tall, condensed, and vertically stacked when useful.
|
|
877
|
-
- Use strong alignment and line breaks to create poster-like impact.
|
|
878
|
-
- Avoid serif typography entirely in this theme.
|
|
879
|
-
|
|
880
|
-
<!-- @component:text-helpers:end -->
|
|
881
|
-
|
|
882
|
-
<!-- @component:dividers:start -->
|
|
883
|
-
### Dividers and Rules
|
|
884
|
-
|
|
885
|
-
```css
|
|
886
|
-
.divider {
|
|
887
|
-
border: none;
|
|
888
|
-
border-top: 1px solid rgba(17,17,17,0.16);
|
|
889
|
-
margin: 24px 0;
|
|
890
|
-
}
|
|
891
|
-
.divider-wide {
|
|
892
|
-
border: none;
|
|
893
|
-
border-top: 4px solid var(--accent);
|
|
894
|
-
width: 260px;
|
|
895
|
-
}
|
|
896
|
-
.heading-rule {
|
|
897
|
-
border: none;
|
|
898
|
-
border-bottom: 2px solid rgba(17,17,17,0.14);
|
|
899
|
-
padding-bottom: 18px;
|
|
900
|
-
margin-bottom: 26px;
|
|
901
|
-
}
|
|
902
|
-
```
|
|
903
|
-
|
|
904
|
-
Use thicker graphic rules on sparse slides and lighter rules on content slides.
|
|
905
|
-
|
|
906
|
-
<!-- @component:dividers:end -->
|
|
907
|
-
|
|
908
|
-
<!-- @component:icons:start -->
|
|
909
|
-
### Icons (Lucide)
|
|
910
|
-
|
|
911
|
-
Icons remain optional.
|
|
912
|
-
|
|
913
|
-
- Default icon color: `var(--accent)`
|
|
914
|
-
- Keep stroke icons simple and editorial
|
|
915
|
-
- Good choices: `arrow-up-right`, `circle`, `sparkles`, `target`, `book-open`, `activity`
|
|
916
|
-
- Do not overuse icons; typography should still dominate
|
|
917
|
-
|
|
918
|
-
<!-- @component:icons:end -->
|
|
919
|
-
|
|
920
|
-
<!-- @component:deco-fills:start -->
|
|
921
|
-
### Decorative Fills (.deco-circle, .deco-rule)
|
|
922
|
-
|
|
923
|
-
Decorative fills should echo the ribbon language from the reference image.
|
|
924
|
-
|
|
925
|
-
```css
|
|
926
|
-
.deco-circle { position: absolute; border-radius: 50%; pointer-events: none; z-index: 0; }
|
|
927
|
-
.deco-rule { position: absolute; pointer-events: none; z-index: 0; }
|
|
928
|
-
.slide-canvas > *:not(.deco-circle):not(.deco-rule):not(.quote-deco) { position: relative; z-index: 1; }
|
|
929
|
-
```
|
|
930
|
-
|
|
931
|
-
Recommended usage:
|
|
932
|
-
- On title slides: use 2–3 oversized diagonal blocks or soft ribbon glows.
|
|
933
|
-
- On content slides: use at most one subtle blush, mint, or pale-blue block tucked into a corner.
|
|
934
|
-
- Section title slides may use vivid orange, mint, and pink gradients.
|
|
935
|
-
|
|
936
|
-
Suggested styles:
|
|
937
|
-
- `.deco-circle`: `background: radial-gradient(circle, rgba(244,90,42,0.30) 0%, rgba(244,90,42,0) 72%)`
|
|
938
|
-
- `.deco-rule`: `height: 6px; background: linear-gradient(90deg, var(--accent), var(--accent-2))`
|
|
939
|
-
|
|
940
|
-
<!-- @component:deco-fills:end -->
|
|
941
|
-
|
|
942
|
-
<!-- @section:components:end -->
|
|
943
|
-
|
|
944
|
-
<!-- @section:layouts:start -->
|
|
945
|
-
|
|
946
|
-
### Layout Primitives
|
|
947
|
-
|
|
948
|
-
All layout primitives remain unchanged.
|
|
949
|
-
|
|
950
|
-
#### Centered Stack
|
|
951
|
-
|
|
952
|
-
Use for cover, quote, closing, and section-divider slides. Same structure as original.
|
|
953
|
-
|
|
954
|
-
#### Top-Aligned Stack
|
|
955
|
-
|
|
956
|
-
Use for content-heavy report slides. Same structure as original.
|
|
957
|
-
|
|
958
|
-
#### Two-Column Grid (.two-col)
|
|
959
|
-
|
|
960
|
-
Keep exactly the same layout definition:
|
|
961
|
-
|
|
962
|
-
```css
|
|
963
|
-
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: stretch; max-width: 1600px; margin: 0 auto; flex: 1; }
|
|
964
|
-
.two-col-main { display: flex; flex-direction: column; justify-content: center; }
|
|
965
|
-
.two-col-main h2 { font-size: 52px; margin-bottom: 16px; }
|
|
966
|
-
.two-col-main p { font-size: 18px; color: var(--text-secondary); line-height: 1.68; }
|
|
967
|
-
.two-col-aside { display: flex; flex-direction: column; justify-content: center; }
|
|
968
|
-
.two-col-aside .card { flex: 1; }
|
|
969
|
-
```
|
|
970
|
-
|
|
971
|
-
#### Three-Column Grid
|
|
972
|
-
|
|
973
|
-
Keep same structure; only art changes.
|
|
974
|
-
|
|
975
|
-
```css
|
|
976
|
-
.card-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; max-width: 1600px; margin: 0 auto; flex: 1; align-content: stretch; }
|
|
977
|
-
.stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; max-width: 1600px; margin: 0 auto; }
|
|
978
|
-
```
|
|
979
|
-
|
|
980
|
-
#### Horizontal Flow
|
|
981
|
-
|
|
982
|
-
Keep same structure.
|
|
983
|
-
|
|
984
|
-
<!-- @section:layouts:end -->
|
|
985
|
-
|
|
986
|
-
<!-- @section:charts:start -->
|
|
987
|
-
|
|
988
|
-
### Data Visualization (ECharts)
|
|
989
|
-
|
|
990
|
-
Charts must adopt the same editorial report look.
|
|
991
|
-
|
|
992
|
-
#### Shared chart styles
|
|
993
|
-
|
|
994
|
-
- **Color palette**: `['#F45A2A', '#82DCC2', '#F3B7D9', '#D6E4F5', '#111111']`
|
|
995
|
-
- **Background**: `'transparent'`
|
|
996
|
-
- **Axis labels / legend text**: `#5D5B56`, `14px`, `Inter`
|
|
997
|
-
- **Grid lines**: `rgba(17,17,17,0.10)`
|
|
998
|
-
- **Tooltip**: warm white background with thin dark border
|
|
999
|
-
- **Animation**: subtle fade only; no bouncy motion
|
|
1000
|
-
|
|
1001
|
-
#### Pie / Donut
|
|
1002
|
-
|
|
1003
|
-
- Donuts are encouraged for impact-score slides
|
|
1004
|
-
- Use thin rings and generous whitespace
|
|
1005
|
-
- Center labels should use `Oswald`
|
|
1006
|
-
- Segment colors should prioritize orange, mint, pink, then pale blue
|
|
1007
|
-
- Ring backgrounds should be very light neutral grey
|
|
1008
|
-
|
|
1009
|
-
#### Bar Charts
|
|
1010
|
-
|
|
1011
|
-
- Use flat fills, not gradients, unless the chart is on a cover or divider slide
|
|
1012
|
-
- Prefer horizontal bars for rankings
|
|
1013
|
-
- Use orange for primary series and mint/pink for secondary series
|
|
1014
|
-
- Avoid rounded corners larger than `3px`
|
|
1015
|
-
|
|
1016
|
-
#### Line / Area Charts
|
|
1017
|
-
|
|
1018
|
-
- Line width: `2.5px`
|
|
1019
|
-
- Use smooth curves only when it improves readability
|
|
1020
|
-
- Area fills may use 8–14% opacity in mint, orange, or pink
|
|
1021
|
-
- No glow effects
|
|
1022
|
-
|
|
1023
|
-
<!-- @section:charts:end -->
|
|
1024
|
-
|
|
1025
|
-
<!-- @section:guide:start -->
|
|
1026
|
-
|
|
1027
|
-
### Composition Guide
|
|
1028
|
-
|
|
1029
|
-
#### Overall Visual Behavior
|
|
1030
|
-
|
|
1031
|
-
- Cover slides: bold, graphic, asymmetrical, high color contrast
|
|
1032
|
-
- Section slides: can use saturated ribbons and oversized typography
|
|
1033
|
-
- Standard content slides: mostly pale paper backgrounds with one focal graphic accent
|
|
1034
|
-
- Dense content slides: let typography and charts carry the slide; use minimal decoration
|
|
1035
|
-
|
|
1036
|
-
#### Common Recipes
|
|
1037
|
-
|
|
1038
|
-
| Content Pattern | Suggested Recipe | Editorial Ribbon Notes |
|
|
1039
|
-
|---|---|---|
|
|
1040
|
-
| 3–4 parallel features | 3-col grid + card ×3 | Use colored left-edge accents in cards |
|
|
1041
|
-
| Key metrics | 3-col grid + stat-card ×3 | Large Oswald numerals, colored top bars |
|
|
1042
|
-
| Narrative + evidence | two-col + large condensed title + card | Clean annual-report feel |
|
|
1043
|
-
| Sequential process | horizontal flow + step-flow | Graphic circles and thicker gradient connectors |
|
|
1044
|
-
| Memorable quote | centered stack + quote-block | Poster-like uppercase quote |
|
|
1045
|
-
| Data-heavy insight | two-col or full-width chart | Keep backgrounds quiet |
|
|
1046
|
-
| Section divider | centered stack + huge heading + ribbon background | Strong graphic page |
|
|
1047
|
-
|
|
1048
|
-
#### Element Usage Rules
|
|
1049
|
-
|
|
1050
|
-
- Typography should do most of the work.
|
|
1051
|
-
- Use uppercase headlines generously.
|
|
1052
|
-
- Use vivid accent color sparingly but deliberately.
|
|
1053
|
-
- Keep content slides mostly light; do not flood every slide with strong orange/mint ribbons.
|
|
1054
|
-
- Preserve the original spacing, grid logic, and component placement.
|
|
1055
|
-
|
|
1056
|
-
#### Common Mistakes
|
|
1057
|
-
|
|
1058
|
-
- Making every slide look like the cover
|
|
1059
|
-
- Adding too many gradients inside content cards
|
|
1060
|
-
- Using soft startup-style UI treatment instead of print-editorial sharpness
|
|
1061
|
-
- Switching layout structure to imitate the reference — do not do this
|
|
1062
|
-
- Over-rounding corners — keep corners mostly square
|
|
1063
|
-
- Returning to monochrome minimalism — this theme needs controlled color
|
|
1064
|
-
|
|
1065
|
-
### Code Blocks (if any)
|
|
1066
|
-
|
|
1067
|
-
```css
|
|
1068
|
-
pre, code {
|
|
1069
|
-
background: #F7F3EE;
|
|
1070
|
-
border: 1px solid rgba(17,17,17,0.10);
|
|
1071
|
-
border-radius: 0;
|
|
1072
|
-
font-family: 'SFMono-Regular', 'Menlo', ui-monospace, monospace;
|
|
1073
|
-
font-size: 14px;
|
|
1074
|
-
color: var(--text-primary);
|
|
1075
|
-
}
|
|
1076
|
-
```
|
|
1077
|
-
|
|
1078
|
-
### Do & Don't
|
|
1079
|
-
|
|
1080
|
-
- **Do** keep the original component and layout system intact
|
|
1081
|
-
- **Do** use condensed editorial typography
|
|
1082
|
-
- **Do** use pale paper backgrounds for most content slides
|
|
1083
|
-
- **Do** use vivid orange/mint/pink accents for covers, dividers, and data highlights
|
|
1084
|
-
- **Do** create strong poster-like hierarchy with line breaks and uppercase text
|
|
1085
|
-
- **Do** use flat or lightly translucent cards with square edges
|
|
1086
|
-
- **Don't** use serif fonts
|
|
1087
|
-
- **Don't** use heavy glassmorphism
|
|
1088
|
-
- **Don't** use neon or tech-blue UI styling
|
|
1089
|
-
- **Don't** alter layout primitives or component HTML
|
|
1090
|
-
- **Don't** make every slide dark; only covers/section dividers may be dark or heavily graphic
|
|
1091
|
-
|
|
1092
|
-
<!-- @section:guide:end -->
|