@cyber-dash-tech/revela 0.15.0 → 0.15.1
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 +6 -7
- package/README.zh-CN.md +6 -7
- package/designs/starter/DESIGN.md +168 -171
- package/designs/starter/preview.html +2 -2
- package/designs/summit/DESIGN.md +283 -129
- package/lib/commands/edit.ts +2 -21
- package/lib/commands/help.ts +1 -2
- package/lib/commands/narrative.ts +26 -0
- package/lib/commands/review.ts +49 -12
- package/lib/decks-state.ts +122 -3
- package/lib/design/designs.ts +1 -2
- package/lib/edit/prompt.ts +6 -5
- package/lib/edit/resolve-deck.ts +1 -1
- package/lib/narrative-state/render-plan.ts +10 -1
- package/lib/qa/artifact.ts +77 -0
- package/lib/qa/checks.ts +100 -10
- package/lib/qa/index.ts +8 -6
- package/lib/qa/measure.ts +85 -0
- package/lib/refine/open.ts +21 -1
- package/lib/refine/server.ts +127 -4
- package/lib/workspace-state/types.ts +1 -0
- package/package.json +1 -1
- package/plugin.ts +36 -130
- package/skill/NARRATIVE_SKILL.md +1 -1
- package/skill/SKILL.md +5 -10
- package/tools/decks.ts +29 -3
- package/tools/narrative-view.ts +1 -1
- package/tools/qa.ts +17 -11
|
@@ -79,9 +79,11 @@ Before generating a derived design, extract a visual schema from references:
|
|
|
79
79
|
|
|
80
80
|
Preserve composition, not only color and shape.
|
|
81
81
|
|
|
82
|
-
###
|
|
82
|
+
### Visual Motif Rules
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
Do not use decorative SVG as a default content component. Use `media` for normal images, screenshots, diagrams, logos, and portraits. Use `hero` for full-bleed cover, divider, closing, or strong visual-statement slides with overlaid text.
|
|
85
|
+
|
|
86
|
+
For explicit illustration/icon-like requests or when authoring a new design from flat vector, doodle, mascot, blob, line-art, or geometric references, a small SVG motif may be used as an implementation detail. Use a fixed `viewBox`; place the SVG with CSS; keep facial features, doodles, and geometric details inside the SVG coordinate system. Do not build complex illustration details from scattered CSS absolute-positioned divs.
|
|
85
87
|
|
|
86
88
|
For photography, UI screenshots, webpages, and product surfaces, do not convert the reference to SVG. Extract palette, type scale, spacing, layout rhythm, borders, image treatment, and surface behavior instead.
|
|
87
89
|
|
|
@@ -136,6 +138,7 @@ body { background: var(--bg-frame); color: var(--text-primary); font-family: var
|
|
|
136
138
|
.page { position: relative; width: 100%; height: 100%; background: var(--bg-page); color: var(--text-primary); padding: 56px 64px 64px; box-shadow: 0 24px 80px var(--shadow-soft); display: flex; flex-direction: column; overflow: hidden; }
|
|
137
139
|
.page.alt { background: var(--bg-page-alt); }
|
|
138
140
|
.eyebrow, .caption, .meta-label { font-size: var(--font-size-meta); line-height: 1.4; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }
|
|
141
|
+
.source, .source-note { font-family: "Times New Roman", Times, serif; font-size: 11px; line-height: 1.35; letter-spacing: 0; text-transform: none; color: var(--text-muted); }
|
|
139
142
|
h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 750; letter-spacing: -0.035em; color: var(--text-primary); }
|
|
140
143
|
h1 { font-size: 96px; line-height: 0.94; }
|
|
141
144
|
h2 { font-size: 46px; line-height: 1.04; }
|
|
@@ -146,6 +149,7 @@ p, li { font-size: var(--font-size-body); line-height: 1.6; color: var(--text-se
|
|
|
146
149
|
.media-frame { position: relative; overflow: hidden; background: var(--surface-strong); }
|
|
147
150
|
.media-frame img { width: 100%; height: 100%; display: block; object-fit: cover; }
|
|
148
151
|
.media-caption { margin-top: 12px; font-size: var(--font-size-meta); line-height: 1.5; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }
|
|
152
|
+
.media-caption.source, .media-caption.source-note { font-family: "Times New Roman", Times, serif; font-size: 11px; line-height: 1.35; letter-spacing: 0; text-transform: none; }
|
|
149
153
|
.editorial-list { list-style: none; display: flex; flex-direction: column; gap: 14px; }
|
|
150
154
|
.editorial-list li { position: relative; padding-left: 20px; font-size: var(--font-size-body); line-height: 1.58; color: var(--text-secondary); }
|
|
151
155
|
.editorial-list li::before { content: ''; position: absolute; left: 0; top: 8px; width: 6px; height: 6px; background: var(--accent-primary); }
|
|
@@ -228,8 +232,11 @@ new SlidePresentation();
|
|
|
228
232
|
- **Preserve composition.** A bottom strip stays bottom anchored; a small corner motif stays small; a sparse reference stays sparse.
|
|
229
233
|
- **Stable layout CSS.** Do not rewrite base layout/container CSS unless the structure itself must change. Prefer tokens, typography, component skins, and small motif components.
|
|
230
234
|
- **Reusable class vocabulary.** New classes must be documented in this DESIGN.md. Avoid many one-off selectors in generated decks.
|
|
231
|
-
- **SVG
|
|
235
|
+
- **SVG is exceptional.** Use decorative SVG only when the user explicitly asks for an illustration/icon-like visual or when design authoring requires a motif.
|
|
232
236
|
- **Images for photographic references.** Use image treatment rules rather than fake SVG when the reference is photographic, UI, webpage, or product imagery.
|
|
237
|
+
- **Content pages need a stable title block.** Except cover, TOC, closing, section divider, and full-bleed hero slides, every normal content slide should include a visible title block from the upper-left safe area. It should contain a compact chapter/section label plus a slide title written as the page's claim or takeaway.
|
|
238
|
+
- **Do not hide the page title inside a card.** Body components may have their own headings, but the slide-level title block should remain separate and easy to scan unless the chosen layout explicitly defines a compact side-title variant.
|
|
239
|
+
- **Text panels are not decorative rule panels.** Do not add a default left border, vertical accent bar, yellow/gold line, or inline rule to `text-panel`. Use typography, spacing, boxes, stats, quotes, or layout-level dividers for emphasis.
|
|
233
240
|
- **Preview must be real.** A design preview should show actual layout/component behavior, not empty placeholder boxes only.
|
|
234
241
|
|
|
235
242
|
### Common Mistakes
|
|
@@ -248,16 +255,18 @@ new SlidePresentation();
|
|
|
248
255
|
|
|
249
256
|
Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. Use the QA flag on each layout marker. It must also set `data-slide-index="N"`, where `N` is the 1-based `DECKS.json` `slides[].index` value.
|
|
250
257
|
|
|
258
|
+
Normal `qa=true` content layouts should start with a slide-level title block unless the layout marker explicitly says otherwise. Use this structure as the default: an eyebrow for chapter/section context, then an `h2` that states the slide's claim or takeaway. Keep body boxes, charts, media, and text panels below or beside that title region.
|
|
259
|
+
|
|
251
260
|
<!-- @layout:fullbleed:start qa=false -->
|
|
252
261
|
#### Fullbleed
|
|
253
262
|
|
|
254
|
-
Full-page layout for a single dominant component such as `
|
|
263
|
+
Full-page layout for a single dominant component such as `hero`, a full-screen chart/media element, or a sparse title field.
|
|
255
264
|
|
|
256
265
|
```html
|
|
257
266
|
<section class="slide" slide-qa="false" data-slide-index="N">
|
|
258
267
|
<div class="slide-canvas">
|
|
259
268
|
<div class="page" style="padding:0;">
|
|
260
|
-
<!-- [slot: content] — usually
|
|
269
|
+
<!-- [slot: content] — usually hero, media, echart-panel, or a sparse title field -->
|
|
261
270
|
</div>
|
|
262
271
|
</div>
|
|
263
272
|
</section>
|
|
@@ -272,10 +281,16 @@ Asymmetric two-column layout. Use when one side needs more visual or reading wei
|
|
|
272
281
|
```html
|
|
273
282
|
<section class="slide" slide-qa="true" data-slide-index="N">
|
|
274
283
|
<div class="slide-canvas">
|
|
275
|
-
<div class="page"
|
|
276
|
-
<div
|
|
277
|
-
<
|
|
278
|
-
<
|
|
284
|
+
<div class="page">
|
|
285
|
+
<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:680px;">
|
|
286
|
+
<p class="eyebrow">Chapter / Section</p>
|
|
287
|
+
<h2>Slide claim or takeaway</h2>
|
|
288
|
+
</div>
|
|
289
|
+
<div style="flex:1;min-height:0;">
|
|
290
|
+
<div class="narrative-grid">
|
|
291
|
+
<div><!-- [slot: left] — 1+ components --></div>
|
|
292
|
+
<div><!-- [slot: right] — 1+ components --></div>
|
|
293
|
+
</div>
|
|
279
294
|
</div>
|
|
280
295
|
</div>
|
|
281
296
|
</div>
|
|
@@ -297,10 +312,16 @@ Mirrored asymmetric two-column layout. Same structure as `narrative`, with the w
|
|
|
297
312
|
```html
|
|
298
313
|
<section class="slide" slide-qa="true" data-slide-index="N">
|
|
299
314
|
<div class="slide-canvas">
|
|
300
|
-
<div class="page"
|
|
301
|
-
<div
|
|
302
|
-
<
|
|
303
|
-
<
|
|
315
|
+
<div class="page">
|
|
316
|
+
<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:680px;">
|
|
317
|
+
<p class="eyebrow">Chapter / Section</p>
|
|
318
|
+
<h2>Slide claim or takeaway</h2>
|
|
319
|
+
</div>
|
|
320
|
+
<div style="flex:1;min-height:0;">
|
|
321
|
+
<div class="narrative-grid narrative-grid--reverse">
|
|
322
|
+
<div><!-- [slot: left] — 1+ components --></div>
|
|
323
|
+
<div><!-- [slot: right] — 1+ components --></div>
|
|
324
|
+
</div>
|
|
304
325
|
</div>
|
|
305
326
|
</div>
|
|
306
327
|
</div>
|
|
@@ -345,10 +366,16 @@ Symmetric two-column layout for direct comparison, paired evidence, or split wor
|
|
|
345
366
|
```html
|
|
346
367
|
<section class="slide" slide-qa="true" data-slide-index="N">
|
|
347
368
|
<div class="slide-canvas">
|
|
348
|
-
<div class="page"
|
|
349
|
-
<div
|
|
350
|
-
<
|
|
351
|
-
<
|
|
369
|
+
<div class="page">
|
|
370
|
+
<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:680px;">
|
|
371
|
+
<p class="eyebrow">Chapter / Section</p>
|
|
372
|
+
<h2>Slide claim or takeaway</h2>
|
|
373
|
+
</div>
|
|
374
|
+
<div style="flex:1;min-height:0;">
|
|
375
|
+
<div class="halves-grid">
|
|
376
|
+
<div><!-- [slot: left] --></div>
|
|
377
|
+
<div><!-- [slot: right] --></div>
|
|
378
|
+
</div>
|
|
352
379
|
</div>
|
|
353
380
|
</div>
|
|
354
381
|
</div>
|
|
@@ -369,10 +396,16 @@ Two-row layout for a compact header/summary above a larger evidence, chart, or f
|
|
|
369
396
|
```html
|
|
370
397
|
<section class="slide" slide-qa="true" data-slide-index="N">
|
|
371
398
|
<div class="slide-canvas">
|
|
372
|
-
<div class="page"
|
|
373
|
-
<div
|
|
374
|
-
<
|
|
375
|
-
<
|
|
399
|
+
<div class="page">
|
|
400
|
+
<div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:680px;">
|
|
401
|
+
<p class="eyebrow">Chapter / Section</p>
|
|
402
|
+
<h2>Slide claim or takeaway</h2>
|
|
403
|
+
</div>
|
|
404
|
+
<div style="flex:1;min-height:0;">
|
|
405
|
+
<div class="stacked-grid">
|
|
406
|
+
<div class="stacked-top"><!-- [slot: top] --></div>
|
|
407
|
+
<div class="stacked-bottom"><!-- [slot: bottom] --></div>
|
|
408
|
+
</div>
|
|
376
409
|
</div>
|
|
377
410
|
</div>
|
|
378
411
|
</div>
|
|
@@ -391,12 +424,56 @@ Two-row layout for a compact header/summary above a larger evidence, chart, or f
|
|
|
391
424
|
|
|
392
425
|
### Components
|
|
393
426
|
|
|
394
|
-
Components are reusable primitives.
|
|
427
|
+
Components are reusable primitives. Use this hierarchy: `layout -> box/card -> text-panel + media/chart/table/stat/quote`.
|
|
428
|
+
|
|
429
|
+
LLM-facing vocabulary:
|
|
430
|
+
- `box` — card/group primitive for one idea, case, evidence item, metric, objection, risk, or action.
|
|
431
|
+
- `text-panel` — language module for title, body text, bullets, and source notes.
|
|
432
|
+
- `media` — normal image/screenshot/diagram/logo/portrait component; use `hero` instead for full-bleed covers.
|
|
433
|
+
- `echart-panel` — chart frame with caption/source structure.
|
|
434
|
+
- `data-table` — structured table component for tabular data and source notes.
|
|
435
|
+
- `steps` — process or phase sequence; compatibility implementation may use `.flow-*` classes.
|
|
436
|
+
- `roadmap-horizontal` and `roadmap-vertical` — dated phases, milestones, historical evolution, or future plans; compatibility implementation may use `.timeline-journey-*` classes.
|
|
437
|
+
- `hero` — full-bleed cover, section divider, closing, or strong visual statement with overlaid title/subtitle.
|
|
438
|
+
- `stat-card`, `quote`, and `toc` — pattern components for their specific use cases.
|
|
439
|
+
- `page-number` and `brand-watermark` — utility components.
|
|
440
|
+
|
|
441
|
+
Do not expose `image-title`, `media--cover`, `editorial-*`, `flow-*`, `timeline-journey-*`, or `svg-motif` as new component choices. Old classes may remain in CSS as compatibility implementation details.
|
|
442
|
+
|
|
443
|
+
Source and citation text should use `.source` or `.source-note`, not `.caption`. Source text uses Times New Roman at 11px and never uses uppercase letter-spacing treatment.
|
|
444
|
+
|
|
445
|
+
Density guidance: normal content slides usually need 2-4 boxes. Evidence slides should use 2-3 evidence boxes or one main chart/table with 2 supporting boxes. Process slides should use 3-5 steps. Use one dominant element only for covers, section dividers, closing asks, full-screen charts/visuals, or deliberate emphasis.
|
|
446
|
+
|
|
447
|
+
<!-- @component:box:start -->
|
|
448
|
+
#### Box (.box)
|
|
449
|
+
|
|
450
|
+
Card/group primitive for one idea, case, evidence item, metric, objection, risk, or action. Put `text-panel`, `media`, `echart-panel`, `data-table`, `stat-card`, or `quote` inside a box when they support the same idea.
|
|
451
|
+
|
|
452
|
+
```html
|
|
453
|
+
<div class="box">
|
|
454
|
+
<div class="text-panel text-panel--plain">
|
|
455
|
+
<div class="text-panel-body">
|
|
456
|
+
<p class="eyebrow">Evidence</p>
|
|
457
|
+
<h3>One clear idea</h3>
|
|
458
|
+
<p>Short supporting copy or source-bound explanation.</p>
|
|
459
|
+
</div>
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
```css
|
|
465
|
+
.box { height: 100%; min-height: 0; padding: 28px; border: 1px solid var(--line); background: var(--surface); display: flex; flex-direction: column; gap: 18px; overflow: hidden; }
|
|
466
|
+
.box--quiet { background: transparent; }
|
|
467
|
+
.box--accent { border-color: var(--accent-primary); background: var(--accent-soft); }
|
|
468
|
+
```
|
|
469
|
+
<!-- @component:box:end -->
|
|
395
470
|
|
|
396
471
|
<!-- @component:text-panel:start -->
|
|
397
472
|
#### Text Panel (.text-panel)
|
|
398
473
|
|
|
399
|
-
|
|
474
|
+
Language module for headings, body copy, lists, and footer/source metadata. It can sit inside `box` or directly in a layout slot.
|
|
475
|
+
|
|
476
|
+
`text-panel` is a neutral language container. Do not add a default left border, vertical accent bar, yellow/gold rule, or decorative stripe to it. If a slide needs emphasis, use a `box`, `stat-card`, `quote`, `toc`, or a layout-level divider instead.
|
|
400
477
|
|
|
401
478
|
```html
|
|
402
479
|
<div class="text-panel text-panel--light">
|
|
@@ -405,12 +482,13 @@ Reusable text container for headings, body copy, lists, and footer metadata.
|
|
|
405
482
|
<h2>Panel heading</h2>
|
|
406
483
|
<ul class="editorial-list"><li><strong>Signal.</strong> Supporting copy.</li></ul>
|
|
407
484
|
</div>
|
|
408
|
-
<div class="text-panel-footer"><span class="
|
|
485
|
+
<div class="text-panel-footer"><span class="source">Source: dataset</span><span class="caption">01</span></div>
|
|
409
486
|
</div>
|
|
410
487
|
```
|
|
411
488
|
|
|
412
489
|
```css
|
|
413
490
|
.text-panel { height: 100%; padding: 56px 48px 34px; display: flex; flex-direction: column; justify-content: space-between; gap: 32px; }
|
|
491
|
+
.text-panel--plain { padding: 0; background: transparent; }
|
|
414
492
|
.text-panel--light { background: var(--bg-page-alt); color: var(--text-primary); }
|
|
415
493
|
.text-panel--dark { background: #1f242b; color: #f8fafc; --text-primary: #f8fafc; --text-secondary: #cbd5e1; --text-muted: #94a3b8; --line: rgba(248,250,252,0.16); }
|
|
416
494
|
.text-panel-body { display: flex; flex-direction: column; gap: 14px; }
|
|
@@ -418,6 +496,28 @@ Reusable text container for headings, body copy, lists, and footer metadata.
|
|
|
418
496
|
```
|
|
419
497
|
<!-- @component:text-panel:end -->
|
|
420
498
|
|
|
499
|
+
<!-- @component:media:start -->
|
|
500
|
+
#### Media (.media)
|
|
501
|
+
|
|
502
|
+
Normal image, screenshot, diagram, logo, or portrait component. Keep important visual information understandable. Do not use `media` for full-bleed covers/dividers/closings; use `hero` for those.
|
|
503
|
+
|
|
504
|
+
```html
|
|
505
|
+
<figure class="media">
|
|
506
|
+
<div class="media-frame"><img src="..." alt="Concise description"></div>
|
|
507
|
+
<figcaption class="media-caption source-note">Source or note</figcaption>
|
|
508
|
+
</figure>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
```css
|
|
512
|
+
.media { height: 100%; min-height: 0; display: flex; flex-direction: column; gap: 12px; }
|
|
513
|
+
.media-frame { position: relative; overflow: hidden; background: var(--surface-strong); }
|
|
514
|
+
.media-frame img { width: 100%; height: 100%; display: block; object-fit: cover; }
|
|
515
|
+
.media--contain .media-frame img { object-fit: contain; }
|
|
516
|
+
.media-caption { margin-top: 0; font-size: var(--font-size-meta); line-height: 1.5; letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-muted); }
|
|
517
|
+
.media-caption.source, .media-caption.source-note { font-family: "Times New Roman", Times, serif; font-size: 11px; line-height: 1.35; letter-spacing: 0; text-transform: none; }
|
|
518
|
+
```
|
|
519
|
+
<!-- @component:media:end -->
|
|
520
|
+
|
|
421
521
|
<!-- @component:stat-card:start -->
|
|
422
522
|
#### Stat Card (.stat-card)
|
|
423
523
|
|
|
@@ -439,67 +539,6 @@ Compact data statement with large numeric value, label, and explanatory copy.
|
|
|
439
539
|
```
|
|
440
540
|
<!-- @component:stat-card:end -->
|
|
441
541
|
|
|
442
|
-
<!-- @component:editorial-image-top:start -->
|
|
443
|
-
#### Editorial Image Top (.editorial-image-top)
|
|
444
|
-
|
|
445
|
-
Media-over-copy module. Use for examples, visual proof, screenshots, or neutral placeholders.
|
|
446
|
-
|
|
447
|
-
```html
|
|
448
|
-
<div class="editorial-image-top">
|
|
449
|
-
<div class="media-frame editorial-media"><img src="..." alt=""></div>
|
|
450
|
-
<div class="editorial-module-body"><p class="eyebrow">Label</p><h3>Module heading</h3><p>Short supporting text.</p></div>
|
|
451
|
-
</div>
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
```css
|
|
455
|
-
.editorial-image-top { display: flex; flex-direction: column; gap: 16px; height: 100%; }
|
|
456
|
-
.editorial-image-top .editorial-media { height: 240px; border: 1px solid var(--line); }
|
|
457
|
-
.editorial-module-body { display: flex; flex-direction: column; gap: 12px; }
|
|
458
|
-
```
|
|
459
|
-
<!-- @component:editorial-image-top:end -->
|
|
460
|
-
|
|
461
|
-
<!-- @component:editorial-text-top:start -->
|
|
462
|
-
#### Editorial Text Top (.editorial-text-top)
|
|
463
|
-
|
|
464
|
-
Text-over-media module for explanation first, visual second.
|
|
465
|
-
|
|
466
|
-
```html
|
|
467
|
-
<div class="editorial-text-top">
|
|
468
|
-
<div class="editorial-module-body"><p class="eyebrow">Label</p><h3>Module heading</h3><p>Short supporting text.</p></div>
|
|
469
|
-
<div class="media-frame editorial-media"></div>
|
|
470
|
-
</div>
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
```css
|
|
474
|
-
.editorial-text-top { display: flex; flex-direction: column; gap: 16px; height: 100%; }
|
|
475
|
-
.editorial-text-top .editorial-media { flex: 1; min-height: 180px; border: 1px solid var(--line); }
|
|
476
|
-
```
|
|
477
|
-
<!-- @component:editorial-text-top:end -->
|
|
478
|
-
|
|
479
|
-
<!-- @component:editorial-text-left:start -->
|
|
480
|
-
#### Editorial Text Left (.editorial-text-left)
|
|
481
|
-
|
|
482
|
-
Horizontal text-and-visual module for compact evidence or feature explanation.
|
|
483
|
-
|
|
484
|
-
```html
|
|
485
|
-
<div class="editorial-text-left">
|
|
486
|
-
<div class="editorial-text-left-header"><p class="eyebrow">Label</p><h3>Module heading</h3></div>
|
|
487
|
-
<div class="editorial-text-left-content">
|
|
488
|
-
<div class="editorial-text-left-copy"><p>Short copy.</p></div>
|
|
489
|
-
<div class="editorial-text-left-visual"><div class="media-frame"></div></div>
|
|
490
|
-
</div>
|
|
491
|
-
</div>
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
```css
|
|
495
|
-
.editorial-text-left { display: flex; flex-direction: column; gap: 0; height: 100%; overflow: hidden; border: 1px solid var(--line); }
|
|
496
|
-
.editorial-text-left-header { flex-shrink: 0; padding: 24px 26px 16px; border-bottom: 1px solid var(--line); }
|
|
497
|
-
.editorial-text-left-content { display: flex; flex: 1; min-height: 0; }
|
|
498
|
-
.editorial-text-left-copy { flex: 1.1; min-width: 0; padding: 20px 24px; display: flex; flex-direction: column; justify-content: flex-start; }
|
|
499
|
-
.editorial-text-left-visual { flex: 1; min-width: 0; min-height: 0; align-self: stretch; overflow: hidden; position: relative; background: var(--surface-strong); }
|
|
500
|
-
```
|
|
501
|
-
<!-- @component:editorial-text-left:end -->
|
|
502
|
-
|
|
503
542
|
<!-- @component:echart-panel:start -->
|
|
504
543
|
#### EChart Panel (.echart-panel)
|
|
505
544
|
|
|
@@ -509,7 +548,7 @@ Chart container with header, chart area, and caption.
|
|
|
509
548
|
<div class="echart-panel">
|
|
510
549
|
<div class="echart-panel-header"><p class="eyebrow">Chart</p><h3>Chart heading</h3><p class="chart-subtitle">Subtitle</p></div>
|
|
511
550
|
<div class="echart-container" id="chart-id"></div>
|
|
512
|
-
<p class="chart-caption">Source: dataset</p>
|
|
551
|
+
<p class="chart-caption source-note">Source: dataset</p>
|
|
513
552
|
</div>
|
|
514
553
|
```
|
|
515
554
|
|
|
@@ -518,53 +557,38 @@ Chart container with header, chart area, and caption.
|
|
|
518
557
|
.echart-panel-header { flex-shrink: 0; padding-bottom: 16px; border-bottom: 1px solid var(--line); margin-bottom: 20px; }
|
|
519
558
|
.chart-subtitle { margin-top: 4px; font-size: 13px; color: var(--text-muted); line-height: 1.4; }
|
|
520
559
|
.echart-container { flex: 1; min-height: 0; }
|
|
521
|
-
.chart-caption { flex-shrink: 0; margin-top: 12px;
|
|
560
|
+
.chart-caption { flex-shrink: 0; margin-top: 12px; }
|
|
522
561
|
```
|
|
523
562
|
<!-- @component:echart-panel:end -->
|
|
524
563
|
|
|
525
|
-
<!-- @component:
|
|
526
|
-
####
|
|
564
|
+
<!-- @component:steps:start -->
|
|
565
|
+
#### Steps (.steps)
|
|
527
566
|
|
|
528
|
-
|
|
567
|
+
Process or phase sequence. Use 3-5 steps. Use `.steps--horizontal` for wide slots and `.steps--vertical` for side panels or narrow slots.
|
|
529
568
|
|
|
530
569
|
```html
|
|
531
|
-
<div class="
|
|
532
|
-
<div class="
|
|
570
|
+
<div class="steps steps--horizontal">
|
|
571
|
+
<div class="step-item"><div class="step-number" data-n="01"></div><div class="step-body"><h4>Step</h4><p>Short text.</p></div></div>
|
|
533
572
|
</div>
|
|
534
573
|
```
|
|
535
574
|
|
|
536
575
|
```css
|
|
537
|
-
.flow-number { position: relative; width: 36px; height: 36px; flex-shrink: 0; border: 1px solid var(--line-strong); background: var(--surface); display: flex; align-items: center; justify-content: center; }
|
|
538
|
-
.flow-number::after { content: attr(data-n); font-size: 12px; font-weight: 800; color: var(--accent-primary); }
|
|
539
|
-
.flow-body h4 { font-size: 20px; font-weight: 700; line-height: 1.14; }
|
|
540
|
-
.flow-body p { margin-top: 8px; font-size: 17px; line-height: 1.6; color: var(--text-secondary); }
|
|
541
|
-
.flow-horizontal { position: relative; display: flex; align-items: flex-start; width: 100%; }
|
|
542
|
-
.flow-horizontal::before { content: ''; position: absolute; top: 17px; left: 0; right: 0; height: 1px; background: var(--line-strong); z-index: 0; }
|
|
543
|
-
.flow-horizontal .flow-item { flex: 1; display: flex; flex-direction: column; gap: 18px; padding-right: 40px; }
|
|
544
|
-
.flow-horizontal .flow-number { position: relative; z-index: 1; }
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
```html
|
|
554
|
-
<div class="flow-vertical">
|
|
555
|
-
<div class="flow-item"><div class="flow-marker"><div class="flow-number" data-n="01"></div><div class="flow-line"></div></div><div class="flow-body"><h4>Step</h4><p>Short text.</p></div></div>
|
|
556
|
-
</div>
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
```css
|
|
560
|
-
.flow-vertical { display: flex; flex-direction: column; width: 100%; }
|
|
561
|
-
.flow-vertical .flow-item { display: flex; gap: 28px; align-items: flex-start; }
|
|
562
|
-
.flow-vertical .flow-marker { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
|
563
|
-
.flow-vertical .flow-line { width: 1px; flex: 1; min-height: 28px; background: var(--line-strong); margin: 6px 0; }
|
|
564
|
-
.flow-vertical .flow-body { padding-bottom: 32px; }
|
|
565
|
-
.flow-vertical .flow-item.last .flow-body { padding-bottom: 0; }
|
|
566
|
-
```
|
|
567
|
-
<!-- @component:flow-vertical:end -->
|
|
576
|
+
.step-number, .flow-number { position: relative; width: 36px; height: 36px; flex-shrink: 0; border: 1px solid var(--line-strong); background: var(--surface); display: flex; align-items: center; justify-content: center; }
|
|
577
|
+
.step-number::after, .flow-number::after { content: attr(data-n); font-size: 12px; font-weight: 800; color: var(--accent-primary); }
|
|
578
|
+
.step-body h4, .flow-body h4 { font-size: 20px; font-weight: 700; line-height: 1.14; }
|
|
579
|
+
.step-body p, .flow-body p { margin-top: 8px; font-size: 17px; line-height: 1.6; color: var(--text-secondary); }
|
|
580
|
+
.steps--horizontal, .flow-horizontal { position: relative; display: flex; align-items: flex-start; width: 100%; }
|
|
581
|
+
.steps--horizontal::before, .flow-horizontal::before { content: ''; position: absolute; top: 17px; left: 0; right: 0; height: 1px; background: var(--line-strong); z-index: 0; }
|
|
582
|
+
.steps--horizontal .step-item, .flow-horizontal .flow-item { flex: 1; display: flex; flex-direction: column; gap: 18px; padding-right: 40px; }
|
|
583
|
+
.steps--horizontal .step-number, .flow-horizontal .flow-number { position: relative; z-index: 1; }
|
|
584
|
+
.steps--vertical, .flow-vertical { display: flex; flex-direction: column; width: 100%; }
|
|
585
|
+
.steps--vertical .step-item, .flow-vertical .flow-item { display: flex; gap: 28px; align-items: flex-start; }
|
|
586
|
+
.step-marker, .flow-marker { display: flex; flex-direction: column; align-items: center; flex-shrink: 0; }
|
|
587
|
+
.step-line, .flow-line { width: 1px; flex: 1; min-height: 28px; background: var(--line-strong); margin: 6px 0; }
|
|
588
|
+
.steps--vertical .step-body, .flow-vertical .flow-body { padding-bottom: 32px; }
|
|
589
|
+
.steps--vertical .step-item.last .step-body, .flow-vertical .flow-item.last .flow-body { padding-bottom: 0; }
|
|
590
|
+
```
|
|
591
|
+
<!-- @component:steps:end -->
|
|
568
592
|
|
|
569
593
|
<!-- @component:data-table:start -->
|
|
570
594
|
#### Data Table (.data-table)
|
|
@@ -575,7 +599,7 @@ Dense tabular data with optional highlights and deltas.
|
|
|
575
599
|
<div class="data-table-wrap">
|
|
576
600
|
<div class="data-table-label">Dataset</div>
|
|
577
601
|
<table class="data-table"><thead><tr><th>Item</th><th>Value</th></tr></thead><tbody><tr><td>Example</td><td>42</td></tr></tbody></table>
|
|
578
|
-
<p class="table-caption">Source note</p>
|
|
602
|
+
<p class="table-caption source-note">Source note</p>
|
|
579
603
|
</div>
|
|
580
604
|
```
|
|
581
605
|
|
|
@@ -590,17 +614,17 @@ Dense tabular data with optional highlights and deltas.
|
|
|
590
614
|
.data-table td { padding: 9px 12px 9px 0; line-height: 1.4; color: var(--text-secondary); }
|
|
591
615
|
.data-table .delta.positive { color: var(--accent-primary); }
|
|
592
616
|
.data-table .delta.negative { color: var(--accent-danger); }
|
|
593
|
-
.table-caption { margin-top: 12px;
|
|
617
|
+
.table-caption { margin-top: 12px; }
|
|
594
618
|
```
|
|
595
619
|
<!-- @component:data-table:end -->
|
|
596
620
|
|
|
597
|
-
<!-- @component:
|
|
598
|
-
####
|
|
621
|
+
<!-- @component:hero:start -->
|
|
622
|
+
#### Hero (.hero)
|
|
599
623
|
|
|
600
|
-
|
|
624
|
+
Full-bleed cover, section divider, closing, or strong visual statement with optional overlaid title/subtitle. Never use `hero` inside a `box`. Never use `hero` for screenshots, charts, tables, diagrams, or source evidence that must stay fully readable.
|
|
601
625
|
|
|
602
626
|
```html
|
|
603
|
-
<div class="image-title image-title--left">
|
|
627
|
+
<div class="hero hero--left image-title image-title--left">
|
|
604
628
|
<div class="image-title-media"></div>
|
|
605
629
|
<div class="image-title-overlay"></div>
|
|
606
630
|
<div class="image-title-fg"><div class="image-title-body"><p class="image-title-eyebrow">Label</p><h1>Title</h1><p class="image-title-subtitle">Subtitle</p></div></div>
|
|
@@ -618,8 +642,12 @@ Hero title component for image, surface, or abstract visual backgrounds.
|
|
|
618
642
|
.image-title-eyebrow { font-size: 12px; font-weight: 800; letter-spacing: 0.18em; text-transform: uppercase; color: rgba(248,250,252,0.62); margin-bottom: 20px; }
|
|
619
643
|
.image-title h1 { color: #f8fafc; font-size: 104px; line-height: 0.92; letter-spacing: -0.055em; }
|
|
620
644
|
.image-title-subtitle { margin-top: 24px; font-size: 18px; line-height: 1.56; color: rgba(248,250,252,0.78); max-width: 520px; }
|
|
645
|
+
.hero { position: relative; width: 100%; height: 100%; overflow: hidden; color: #f8fafc; background: #1f242b; }
|
|
646
|
+
.hero--left .image-title-body { max-width: 760px; }
|
|
647
|
+
.hero--right .image-title-fg { text-align: right; }
|
|
648
|
+
.hero--right .image-title-body { max-width: 860px; margin-left: auto; }
|
|
621
649
|
```
|
|
622
|
-
<!-- @component:
|
|
650
|
+
<!-- @component:hero:end -->
|
|
623
651
|
|
|
624
652
|
<!-- @component:toc:start -->
|
|
625
653
|
#### TOC (.toc-panel)
|
|
@@ -689,13 +717,13 @@ Small page number utility.
|
|
|
689
717
|
```
|
|
690
718
|
<!-- @component:page-number:end -->
|
|
691
719
|
|
|
692
|
-
<!-- @component:
|
|
693
|
-
####
|
|
720
|
+
<!-- @component:roadmap-horizontal:start -->
|
|
721
|
+
#### Roadmap Horizontal (.roadmap-horizontal)
|
|
694
722
|
|
|
695
723
|
Horizontal milestone journey with a central axis line. Nodes sit on the axis; a dashed vertical stem leads to a tip dot, with date, title, and description text alongside. Alternate nodes above and below the axis for rhythm. Suitable for 4-8 milestones across a chronological arc, transformation story, roadmap, or multi-year programme recap.
|
|
696
724
|
|
|
697
725
|
```html
|
|
698
|
-
<div class="timeline-journey-horizontal" data-preview-component="
|
|
726
|
+
<div class="roadmap-horizontal timeline-journey-horizontal" data-preview-component="roadmap-horizontal">
|
|
699
727
|
<div class="tjh-axis"></div>
|
|
700
728
|
|
|
701
729
|
<!-- Up node: label, tip-dot, stem, axis-dot. Content grows upward. -->
|
|
@@ -725,7 +753,7 @@ Horizontal milestone journey with a central axis line. Nodes sit on the axis; a
|
|
|
725
753
|
```
|
|
726
754
|
|
|
727
755
|
```css
|
|
728
|
-
.timeline-journey-horizontal {
|
|
756
|
+
.roadmap-horizontal, .timeline-journey-horizontal {
|
|
729
757
|
--tjh-node: 12px;
|
|
730
758
|
--tjh-stem-h: 76px;
|
|
731
759
|
--tjh-col: calc(100% / 6);
|
|
@@ -756,15 +784,15 @@ Rules:
|
|
|
756
784
|
- Keep `.tjh-text` short, usually 1-2 lines. The column width limits wrapping naturally.
|
|
757
785
|
- Alternate up/down nodes for visual rhythm unless clustering intentionally communicates a phase.
|
|
758
786
|
- Adjust `--tjh-col`, `--tjh-stem-h`, and component `height` for fewer or longer milestones.
|
|
759
|
-
<!-- @component:
|
|
787
|
+
<!-- @component:roadmap-horizontal:end -->
|
|
760
788
|
|
|
761
|
-
<!-- @component:
|
|
762
|
-
####
|
|
789
|
+
<!-- @component:roadmap-vertical:start -->
|
|
790
|
+
#### Roadmap Vertical (.roadmap-vertical)
|
|
763
791
|
|
|
764
792
|
Vertical milestone journey with a central axis line. Nodes sit on the axis; a horizontal dashed stem leads to a tip dot, with date, title, and description text alongside. Alternate nodes left and right of the axis for rhythm. Suitable for 3-8 milestones in a full-height slot.
|
|
765
793
|
|
|
766
794
|
```html
|
|
767
|
-
<div class="timeline-journey-vertical" data-preview-component="
|
|
795
|
+
<div class="roadmap-vertical timeline-journey-vertical" data-preview-component="roadmap-vertical">
|
|
768
796
|
<div class="tjv-axis"></div>
|
|
769
797
|
|
|
770
798
|
<!-- Left node: DOM order stays axis-dot, stem, tip-dot, label. CSS reverses the row. -->
|
|
@@ -794,7 +822,7 @@ Vertical milestone journey with a central axis line. Nodes sit on the axis; a ho
|
|
|
794
822
|
```
|
|
795
823
|
|
|
796
824
|
```css
|
|
797
|
-
.timeline-journey-vertical {
|
|
825
|
+
.roadmap-vertical, .timeline-journey-vertical {
|
|
798
826
|
--tjv-node: 12px;
|
|
799
827
|
--tjv-stem-w: 76px;
|
|
800
828
|
position: relative;
|
|
@@ -825,38 +853,7 @@ Rules:
|
|
|
825
853
|
- Alternate left and right nodes for rhythm. Avoid consecutive same-side nodes unless the story needs clustering.
|
|
826
854
|
- The parent container must have a defined height. Use `height: 100%` inside a layout slot, or set an explicit height when standalone.
|
|
827
855
|
- Keep `.tjv-text` to 2-3 lines. Longer labels shift the perceived center away from the axis dot.
|
|
828
|
-
<!-- @component:
|
|
829
|
-
|
|
830
|
-
<!-- @component:svg-motif:start -->
|
|
831
|
-
#### SVG Motif (.svg-motif)
|
|
832
|
-
|
|
833
|
-
Pattern for flat vector motifs, doodles, mascots, blob characters, line-art, and abstract geometric visuals. Keep drawing details inside the SVG; CSS only places and sizes the motif.
|
|
834
|
-
|
|
835
|
-
```html
|
|
836
|
-
<div class="svg-motif svg-motif--bottom" aria-hidden="true">
|
|
837
|
-
<svg viewBox="0 0 1600 420" role="img" aria-label="Decorative vector motif">
|
|
838
|
-
<rect x="0" y="350" width="1600" height="24" fill="var(--accent-soft)" />
|
|
839
|
-
<path d="M120 330 C160 240 260 220 330 290 C380 340 290 370 180 370 Z" fill="var(--accent-primary)" />
|
|
840
|
-
<circle cx="230" cy="310" r="8" fill="var(--text-primary)" />
|
|
841
|
-
</svg>
|
|
842
|
-
</div>
|
|
843
|
-
```
|
|
844
|
-
|
|
845
|
-
```css
|
|
846
|
-
.svg-motif { position: relative; pointer-events: none; color: var(--text-primary); }
|
|
847
|
-
.svg-motif svg { display: block; width: 100%; height: 100%; overflow: visible; }
|
|
848
|
-
.svg-motif--bottom { position: absolute; left: 0; right: 0; bottom: 0; height: 30%; }
|
|
849
|
-
.svg-motif--side { position: absolute; right: 0; top: 0; bottom: 0; width: 34%; }
|
|
850
|
-
.svg-motif--corner { position: absolute; right: 40px; bottom: 36px; width: 360px; height: 220px; }
|
|
851
|
-
.svg-motif--hero { width: 100%; height: 100%; }
|
|
852
|
-
```
|
|
853
|
-
|
|
854
|
-
Usage rules:
|
|
855
|
-
- Use fixed `viewBox` values such as `0 0 1600 420` for strips or `0 0 600 600` for emblems.
|
|
856
|
-
- For bottom strips, the wrapper should usually occupy `20%` to `35%` of slide height.
|
|
857
|
-
- Do not let a small reference motif become a full-slide mascot unless the user requests it.
|
|
858
|
-
- Do not create eyes, mouths, doodles, or character details as separate CSS-positioned HTML elements outside the SVG.
|
|
859
|
-
<!-- @component:svg-motif:end -->
|
|
856
|
+
<!-- @component:roadmap-vertical:end -->
|
|
860
857
|
|
|
861
858
|
<!-- @design:components:end -->
|
|
862
859
|
|
|
@@ -256,13 +256,13 @@
|
|
|
256
256
|
<div class="stacked-top text-panel reveal" style="padding:42px 56px 20px;"><div class="text-panel-body"><p class="eyebrow">Data and process</p><h2>Evidence components stay structural</h2><p>Charts, tables, and journey timelines inherit the active theme while keeping predictable geometry.</p></div></div>
|
|
257
257
|
<div class="stacked-bottom" style="display:grid;grid-template-columns:1fr 1fr;grid-template-rows:minmax(0,1fr) 250px;gap:26px;padding:0 56px 56px;">
|
|
258
258
|
<div class="echart-panel reveal"><div class="echart-panel-header"><p class="eyebrow">Example chart</p><h3>Signal distribution</h3><p class="chart-subtitle">Neutral chart defaults with restrained labels.</p></div><div class="echart-container" id="starter-chart"></div><p class="chart-caption">Source: demo data</p></div>
|
|
259
|
-
<div class="timeline-journey-vertical reveal" data-preview-component="
|
|
259
|
+
<div class="roadmap-vertical timeline-journey-vertical reveal" data-preview-component="roadmap-vertical">
|
|
260
260
|
<div class="tjv-axis"></div>
|
|
261
261
|
<div class="tjv-item tjv-item--left" style="top:18%; --tjv-item-color:var(--accent-primary);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Discover</span><span class="tjv-title">Signal scan</span><span class="tjv-text">Map inputs and identify the base pattern.</span></div></div>
|
|
262
262
|
<div class="tjv-item tjv-item--right" style="top:50%; --tjv-item-color:var(--accent-secondary);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Build</span><span class="tjv-title">Theme draft</span><span class="tjv-text">Apply visual schema without changing structure.</span></div></div>
|
|
263
263
|
<div class="tjv-item tjv-item--left" style="top:82%; --tjv-item-color:var(--accent-danger);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Verify</span><span class="tjv-title">Preview pass</span><span class="tjv-text">Check roles, components, and slide geometry.</span></div></div>
|
|
264
264
|
</div>
|
|
265
|
-
<div class="timeline-journey-horizontal reveal" data-preview-component="
|
|
265
|
+
<div class="roadmap-horizontal timeline-journey-horizontal reveal" data-preview-component="roadmap-horizontal" style="grid-column:1 / -1;">
|
|
266
266
|
<div class="tjh-axis"></div>
|
|
267
267
|
<div class="tjh-item tjh-item--up" style="left:14%; --tjh-item-color:var(--accent-primary);"><div class="tjh-label"><span class="tjh-date">01</span><span class="tjh-title">Brief</span><span class="tjh-text">Clarify source style.</span></div><div class="tjh-tip-dot"></div><div class="tjh-stem"></div><div class="tjh-axis-dot"></div></div>
|
|
268
268
|
<div class="tjh-item tjh-item--down" style="left:38%; --tjh-item-color:var(--accent-secondary);"><div class="tjh-axis-dot"></div><div class="tjh-stem"></div><div class="tjh-tip-dot"></div><div class="tjh-label"><span class="tjh-date">02</span><span class="tjh-title">Tokens</span><span class="tjh-text">Set color and type.</span></div></div>
|