@deckio/deck-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/BottomBar.jsx +9 -0
- package/components/BottomBar.module.css +17 -0
- package/components/Navigation.jsx +195 -0
- package/components/Navigation.module.css +210 -0
- package/components/Slide.jsx +43 -0
- package/components/exportDeckPdf.js +142 -0
- package/components/exportDeckPptx.js +127 -0
- package/context/SlideContext.jsx +190 -0
- package/index.js +5 -0
- package/instructions/AGENTS.md +26 -0
- package/instructions/deck-config.instructions.md +34 -0
- package/instructions/deck-project.instructions.md +34 -0
- package/instructions/slide-css.instructions.md +96 -0
- package/instructions/slide-jsx.instructions.md +34 -0
- package/package.json +59 -0
- package/scripts/capture-screen.mjs +127 -0
- package/scripts/export-pdf.mjs +287 -0
- package/scripts/generate-image.mjs +110 -0
- package/scripts/init-project.mjs +214 -0
- package/skills/deck-add-slide/SKILL.md +236 -0
- package/skills/deck-delete-slide/SKILL.md +51 -0
- package/skills/deck-generate-image/SKILL.md +85 -0
- package/skills/deck-inspect/SKILL.md +60 -0
- package/skills/deck-sketch/SKILL.md +91 -0
- package/skills/deck-validate-project/SKILL.md +81 -0
- package/slides/GenericThankYouSlide.jsx +31 -0
- package/styles/global.css +392 -0
- package/themes/dark.css +151 -0
- package/themes/light.css +152 -0
- package/themes/shadcn.css +212 -0
- package/themes/theme-loader.js +47 -0
- package/vite.js +67 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deck-sketch
|
|
3
|
+
description: Sketch a slide on Whiteboard, capture the sketch, and use it as inspiration to create a new slide. Use this when the user wants to draw, sketch, or wireframe a slide before building it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Sketch a Slide
|
|
7
|
+
|
|
8
|
+
Use Whiteboard to sketch a slide layout, capture the result, and translate it into a real slide component.
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
### Step 1 — Open Whiteboard
|
|
13
|
+
|
|
14
|
+
```powershell
|
|
15
|
+
Start-Process "ms-whiteboard-cmd:"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Tell the user:
|
|
19
|
+
|
|
20
|
+
> **Whiteboard is open. Sketch your slide layout. When you're done, use "Fit to screen" (Ctrl+Shift+F) so the entire sketch is visible, then tell me you're ready.**
|
|
21
|
+
|
|
22
|
+
**STOP here.** Do NOT proceed until the user explicitly says the sketch is ready.
|
|
23
|
+
|
|
24
|
+
### Step 2 — Capture the sketch
|
|
25
|
+
|
|
26
|
+
When the user says the sketch is ready:
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
Add-Type @"
|
|
30
|
+
using System;
|
|
31
|
+
using System.Runtime.InteropServices;
|
|
32
|
+
using System.Drawing;
|
|
33
|
+
public class WinCapture {
|
|
34
|
+
[DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
|
|
35
|
+
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
|
|
36
|
+
[DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
|
|
37
|
+
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int L, T, R, B; }
|
|
38
|
+
}
|
|
39
|
+
"@
|
|
40
|
+
[WinCapture]::SetProcessDPIAware() | Out-Null
|
|
41
|
+
Add-Type -AssemblyName System.Drawing
|
|
42
|
+
$h = (Get-Process | Where-Object { $_.MainWindowTitle -like '*Whiteboard*' } | Select-Object -First 1).MainWindowHandle
|
|
43
|
+
if (!$h -or $h -eq [IntPtr]::Zero) { Write-Error "Whiteboard window not found"; return }
|
|
44
|
+
[WinCapture]::SetForegroundWindow($h) | Out-Null
|
|
45
|
+
Start-Sleep -Milliseconds 500
|
|
46
|
+
$r = New-Object WinCapture+RECT
|
|
47
|
+
[WinCapture]::GetWindowRect($h, [ref]$r) | Out-Null
|
|
48
|
+
$w = $r.R - $r.L; $ht = $r.B - $r.T
|
|
49
|
+
$bmp = New-Object Drawing.Bitmap $w, $ht
|
|
50
|
+
$g = [Drawing.Graphics]::FromImage($bmp)
|
|
51
|
+
$g.CopyFromScreen($r.L, $r.T, 0, 0, (New-Object Drawing.Size $w, $ht))
|
|
52
|
+
$dir = ".github\eyes"
|
|
53
|
+
if (!(Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
|
54
|
+
$file = Join-Path $dir "sketch-$(Get-Date -Format 'yyyy-MM-ddTHH-mm-ss').png"
|
|
55
|
+
$bmp.Save($file)
|
|
56
|
+
$g.Dispose(); $bmp.Dispose()
|
|
57
|
+
Write-Host "Sketch saved: $file"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Step 3 — Analyze the sketch
|
|
61
|
+
|
|
62
|
+
Reference the saved screenshot image. Study it carefully and identify:
|
|
63
|
+
|
|
64
|
+
- **Layout structure** — columns/rows, content zones, header/footer areas.
|
|
65
|
+
- **Text elements** — headings, labels, bullet points, callouts.
|
|
66
|
+
- **Visual elements** — boxes, icons, images, dividers, backgrounds.
|
|
67
|
+
- **Data patterns** — tables, grids, lists, charts, metrics.
|
|
68
|
+
|
|
69
|
+
Describe what you see back to the user and confirm your interpretation.
|
|
70
|
+
|
|
71
|
+
### Step 4 — Create the slide
|
|
72
|
+
|
|
73
|
+
Use the **deck-add-slide** skill to build the slide, guided by the sketch:
|
|
74
|
+
|
|
75
|
+
1. Map sketch regions to CSS Grid or Flexbox layout.
|
|
76
|
+
2. Translate hand-drawn text into real content with proper typography.
|
|
77
|
+
3. Replace rough shapes with styled `<div>` containers using CSS Modules.
|
|
78
|
+
4. Follow all deck-add-slide conventions (accent-bar, content-frame, BottomBar, imports from `@deckio/deck-engine`).
|
|
79
|
+
5. Register the slide in `deck.config.js`.
|
|
80
|
+
|
|
81
|
+
### Step 5 — Visual verification
|
|
82
|
+
|
|
83
|
+
After creating the slide, use **deck-eyes** to capture a screenshot of the rendered result.
|
|
84
|
+
|
|
85
|
+
Compare the rendered slide against the original sketch. If the user is present, show both and ask if adjustments are needed.
|
|
86
|
+
|
|
87
|
+
## Notes
|
|
88
|
+
|
|
89
|
+
- Whiteboard sketches are rough — interpret intent, not exact pixels.
|
|
90
|
+
- If text is hard to read, ask the user to clarify.
|
|
91
|
+
- Screenshots are saved under `.github/eyes/` (gitignored) with a `sketch-` prefix.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: deck-validate-project
|
|
3
|
+
description: Validate and audit a deck project for correctness. Use this when asked to validate, audit, polish, review, check, or verify slides.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Validate & Audit a Deck Project
|
|
7
|
+
|
|
8
|
+
## Step 1: Audit deck.config.js
|
|
9
|
+
|
|
10
|
+
Open `deck.config.js` and verify:
|
|
11
|
+
|
|
12
|
+
### 1a. All imports resolve
|
|
13
|
+
|
|
14
|
+
For each slide import at the top of the file, verify the target file exists in `src/slides/`.
|
|
15
|
+
|
|
16
|
+
### 1b. slides array matches imports
|
|
17
|
+
|
|
18
|
+
- Every imported slide should appear in the `slides` array.
|
|
19
|
+
- No unused imports (imported but not in the array).
|
|
20
|
+
- No undefined entries in the array (in array but not imported).
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Step 2: Verify slide structure
|
|
25
|
+
|
|
26
|
+
For each slide `.jsx` file in `src/slides/`, verify:
|
|
27
|
+
|
|
28
|
+
- [ ] Imports `{ Slide }` and `{ BottomBar }` from `'@deckio/deck-engine'`
|
|
29
|
+
- [ ] Wrapped in `<Slide index={index} className={styles.xxx}>` (accepts `index` as prop)
|
|
30
|
+
- [ ] Contains `<div className="accent-bar" />` as first child
|
|
31
|
+
- [ ] Contains at least one decorative orb
|
|
32
|
+
- [ ] Content is inside `<div className="content-frame content-gutter">`
|
|
33
|
+
- [ ] `<BottomBar />` is the **last child** inside `<Slide>`
|
|
34
|
+
- [ ] `BottomBar text` is consistent across all slides in the project
|
|
35
|
+
|
|
36
|
+
For each `.module.css` file, verify the root class has:
|
|
37
|
+
- [ ] `background: var(--bg-deep)`
|
|
38
|
+
- [ ] `padding: 0 0 44px 0`
|
|
39
|
+
- [ ] Does NOT use `flex: 1` on the body wrapper (defeats vertical centering)
|
|
40
|
+
- [ ] Does NOT redundantly set `flex-direction: column` (inherited from engine `.slide` class)
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Step 3: Check companion files
|
|
45
|
+
|
|
46
|
+
- Every `.jsx` slide in `src/slides/` should have a matching `.module.css` file
|
|
47
|
+
- No orphaned `.module.css` files without a matching `.jsx`
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Step 4: Verify metadata
|
|
52
|
+
|
|
53
|
+
Check `deck.config.js` exports these fields:
|
|
54
|
+
- [ ] `id` — string, matches the project folder name convention
|
|
55
|
+
- [ ] `title` — display name
|
|
56
|
+
- [ ] `subtitle` — tagline
|
|
57
|
+
- [ ] `icon` — emoji
|
|
58
|
+
- [ ] `accent` — CSS color value
|
|
59
|
+
- [ ] `slides` — non-empty array
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Step 5: Report results
|
|
64
|
+
|
|
65
|
+
Summarize findings:
|
|
66
|
+
|
|
67
|
+
- Number of slides validated
|
|
68
|
+
- Any issues found and fixed (missing files, broken imports, structural issues)
|
|
69
|
+
- Overall project health: **pass** or **issues found**
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Quick checklist
|
|
74
|
+
|
|
75
|
+
- [ ] All imports in `deck.config.js` resolve to existing files
|
|
76
|
+
- [ ] `slides` array matches imports (no unused, no missing)
|
|
77
|
+
- [ ] Every `.jsx` slide has a companion `.module.css`
|
|
78
|
+
- [ ] All slides have accent-bar, content-frame, BottomBar
|
|
79
|
+
- [ ] BottomBar text is consistent across the project
|
|
80
|
+
- [ ] CSS root classes have required properties (`background`, `padding`) and no `flex: 1` on body wrapper
|
|
81
|
+
- [ ] Project metadata (id, title, subtitle, icon, accent) is present
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import Slide from '../components/Slide.jsx'
|
|
2
|
+
import BottomBar from '../components/BottomBar.jsx'
|
|
3
|
+
|
|
4
|
+
export default function GenericThankYouSlide({ index = 10, subtitle, tagline, footerText }) {
|
|
5
|
+
return (
|
|
6
|
+
<Slide index={index} className="deck-ty">
|
|
7
|
+
<div className="accent-bar" />
|
|
8
|
+
|
|
9
|
+
<div className="deck-ty-glow deck-ty-glow1" />
|
|
10
|
+
<div className="deck-ty-glow deck-ty-glow2" />
|
|
11
|
+
<div className="deck-ty-glow deck-ty-glow3" />
|
|
12
|
+
|
|
13
|
+
{[1, 2, 3, 4, 5, 6, 7, 8].map(i => (
|
|
14
|
+
<div key={i} className={`deck-ty-streak deck-ty-streak${i}`} />
|
|
15
|
+
))}
|
|
16
|
+
|
|
17
|
+
<div className="content-frame content-gutter">
|
|
18
|
+
<div className="deck-ty-content">
|
|
19
|
+
<h2 className="deck-ty-title">Thank You</h2>
|
|
20
|
+
<p className="deck-ty-subtitle">
|
|
21
|
+
{subtitle || <>Let’s build something great — together.</>}
|
|
22
|
+
</p>
|
|
23
|
+
<div className="deck-ty-divider" />
|
|
24
|
+
{tagline && <p className="deck-ty-tagline">{tagline}</p>}
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<BottomBar text={footerText} />
|
|
29
|
+
</Slide>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
|
|
2
|
+
|
|
3
|
+
/* ═══════════════════════════════════════════════════════════════════════════
|
|
4
|
+
DECKIO Design Token System
|
|
5
|
+
═══════════════════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
Token architecture aligned with shadcn/ui naming conventions for
|
|
8
|
+
multi-theme compatibility, extended with presentation-specific tokens.
|
|
9
|
+
|
|
10
|
+
LAYER STRATEGY (Tailwind v4 + shadcn/ui compatibility):
|
|
11
|
+
────────────────────────────────────────────────────────
|
|
12
|
+
Tailwind v4 wraps its output in @layer directives. In the CSS cascade,
|
|
13
|
+
unlayered styles ALWAYS beat layered styles — regardless of specificity.
|
|
14
|
+
Without layers, our `* { margin: 0 }` would override every Tailwind
|
|
15
|
+
utility (`p-4`, `m-2`, etc.), breaking shadcn/ui components entirely.
|
|
16
|
+
|
|
17
|
+
We declare the canonical layer order up front (global.css is imported
|
|
18
|
+
before theme CSS), then place engine styles in the appropriate layers:
|
|
19
|
+
@layer base — token defaults, reset, html/body
|
|
20
|
+
@layer components — engine component styles (.slide, .deck, etc.)
|
|
21
|
+
Theme CSS `:root` blocks remain unlayered (highest priority).
|
|
22
|
+
Tailwind utilities live in @layer utilities and override components.
|
|
23
|
+
|
|
24
|
+
CATEGORIES:
|
|
25
|
+
|
|
26
|
+
1. Core Semantic Colors (shadcn-aligned)
|
|
27
|
+
--background / --foreground Page-level background & text
|
|
28
|
+
--card / --card-foreground Card / panel surfaces
|
|
29
|
+
--primary / --primary-foreground Brand / action color
|
|
30
|
+
--secondary / --secondary-foreground Subtle surfaces (panels, kbd)
|
|
31
|
+
--muted / --muted-foreground Muted text & backgrounds
|
|
32
|
+
--accent / --accent-foreground Accent highlights (= primary in dark theme)
|
|
33
|
+
--destructive / --destructive-foreground Errors & warnings
|
|
34
|
+
--border Default border
|
|
35
|
+
--input Form input borders
|
|
36
|
+
--ring Focus ring color
|
|
37
|
+
--radius Default border radius
|
|
38
|
+
|
|
39
|
+
2. Decorative Palette
|
|
40
|
+
--purple, --purple-deep, --pink, --cyan, --green
|
|
41
|
+
--blue-glow Glow base for interactive elements
|
|
42
|
+
|
|
43
|
+
3. Derived Overlays & Glows
|
|
44
|
+
Translucent surfaces, glow effects, and shadows. Explicit tokens
|
|
45
|
+
(not computed) so each theme can override independently.
|
|
46
|
+
|
|
47
|
+
4. Presentation Layout
|
|
48
|
+
--slide-bg, --content-max-width, --content-gutter
|
|
49
|
+
|
|
50
|
+
5. Typography Scale
|
|
51
|
+
Font family, sizes (2xs → display), weights, letter-spacing, line-height
|
|
52
|
+
|
|
53
|
+
6. Spacing Scale (4 px base)
|
|
54
|
+
--space-0 through --space-14
|
|
55
|
+
|
|
56
|
+
7. Border Radius Scale
|
|
57
|
+
--radius-sm through --radius-full
|
|
58
|
+
|
|
59
|
+
8. Z-Index Scale
|
|
60
|
+
Named layers: content → bar → nav → progress → overlay
|
|
61
|
+
|
|
62
|
+
9. Transitions
|
|
63
|
+
Duration + easing presets
|
|
64
|
+
|
|
65
|
+
THEMING:
|
|
66
|
+
Override any token in :root for a global theme, or scope overrides to a
|
|
67
|
+
class (e.g. .theme-light, .theme-shadcn) for per-section theming.
|
|
68
|
+
Current values represent the "dark" theme (default).
|
|
69
|
+
═══════════════════════════════════════════════════════════════════════════ */
|
|
70
|
+
|
|
71
|
+
/* Establish canonical layer order — must come before any @layer blocks.
|
|
72
|
+
Tailwind v4 uses these exact names; declaring them here (global.css is
|
|
73
|
+
imported first) guarantees the ordering is: theme < base < components < utilities. */
|
|
74
|
+
@layer theme, base, components, utilities;
|
|
75
|
+
|
|
76
|
+
/* ── Base layer: token defaults + reset ─────────────────────────────────── */
|
|
77
|
+
@layer base {
|
|
78
|
+
|
|
79
|
+
:root {
|
|
80
|
+
/* ── 1. Core Semantic Colors (shadcn-aligned) ────────────────────────── */
|
|
81
|
+
--background: #080b10;
|
|
82
|
+
--foreground: #e6edf3;
|
|
83
|
+
--card: #0d1117;
|
|
84
|
+
--card-foreground: #e6edf3;
|
|
85
|
+
--primary: #58a6ff;
|
|
86
|
+
--primary-foreground: #ffffff;
|
|
87
|
+
--secondary: #161b22;
|
|
88
|
+
--secondary-foreground: #e6edf3;
|
|
89
|
+
--muted: #161b22;
|
|
90
|
+
--muted-foreground: #8b949e;
|
|
91
|
+
--accent: #58a6ff;
|
|
92
|
+
--accent-foreground: #ffffff;
|
|
93
|
+
--destructive: #f85149;
|
|
94
|
+
--destructive-foreground: #ffffff;
|
|
95
|
+
--border: #30363d;
|
|
96
|
+
--input: #30363d;
|
|
97
|
+
--ring: #58a6ff;
|
|
98
|
+
--radius: 10px;
|
|
99
|
+
|
|
100
|
+
/* ── 2. Decorative Palette ───────────────────────────────────────────── */
|
|
101
|
+
--blue-glow: #1f6feb;
|
|
102
|
+
--purple: #bc8cff;
|
|
103
|
+
--purple-deep: #6e40c9;
|
|
104
|
+
--pink: #f778ba;
|
|
105
|
+
--cyan: #56d4dd;
|
|
106
|
+
--green: #3fb950;
|
|
107
|
+
|
|
108
|
+
/* ── 3. Derived Overlays & Glows ─────────────────────────────────────── */
|
|
109
|
+
--surface-overlay: rgba(22, 27, 34, 0.8);
|
|
110
|
+
--surface-overlay-heavy: rgba(22, 27, 34, 0.95);
|
|
111
|
+
--background-overlay: rgba(13, 17, 23, 0.85);
|
|
112
|
+
--border-subtle: rgba(48, 54, 61, 0.6);
|
|
113
|
+
--glow-primary: rgba(31, 111, 235, 0.2);
|
|
114
|
+
--glow-primary-strong: rgba(31, 111, 235, 0.22);
|
|
115
|
+
--glow-primary-shadow: rgba(31, 111, 235, 0.18);
|
|
116
|
+
--glow-ring: rgba(121, 192, 255, 0.18);
|
|
117
|
+
--glow-accent: rgba(88, 166, 255, 0.10);
|
|
118
|
+
--glow-purple: rgba(188, 140, 255, 0.10);
|
|
119
|
+
--glow-cyan: rgba(86, 212, 221, 0.08);
|
|
120
|
+
--dot-color: rgba(139, 148, 158, 0.25);
|
|
121
|
+
--destructive-subtle: rgba(248, 81, 73, 0.04);
|
|
122
|
+
--shadow-elevated: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
123
|
+
|
|
124
|
+
/* ── 4. Presentation Layout ──────────────────────────────────────────── */
|
|
125
|
+
--slide-bg: var(--background);
|
|
126
|
+
--content-max-width: 1280px;
|
|
127
|
+
--content-gutter: 72px;
|
|
128
|
+
|
|
129
|
+
/* ── 5. Typography Scale ─────────────────────────────────────────────── */
|
|
130
|
+
--font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
131
|
+
--font-size-2xs: 10px;
|
|
132
|
+
--font-size-xs: 11px;
|
|
133
|
+
--font-size-sm: 12px;
|
|
134
|
+
--font-size-md: 13px;
|
|
135
|
+
--font-size-base: 16px;
|
|
136
|
+
--font-size-lg: 20px;
|
|
137
|
+
--font-size-xl: 24px;
|
|
138
|
+
--font-size-2xl: 32px;
|
|
139
|
+
--font-size-display: clamp(40px, 6vw, 64px);
|
|
140
|
+
|
|
141
|
+
--font-weight-light: 300;
|
|
142
|
+
--font-weight-regular: 400;
|
|
143
|
+
--font-weight-medium: 500;
|
|
144
|
+
--font-weight-semibold: 600;
|
|
145
|
+
--font-weight-bold: 700;
|
|
146
|
+
--font-weight-extrabold: 800;
|
|
147
|
+
|
|
148
|
+
--letter-spacing-tight: -2px;
|
|
149
|
+
--letter-spacing-normal: 0;
|
|
150
|
+
--letter-spacing-wide: 0.5px;
|
|
151
|
+
--letter-spacing-wider: 2.5px;
|
|
152
|
+
--letter-spacing-widest: 3px;
|
|
153
|
+
|
|
154
|
+
--line-height-tight: 1.2;
|
|
155
|
+
--line-height-normal: 1.5;
|
|
156
|
+
--line-height-relaxed: 1.75;
|
|
157
|
+
|
|
158
|
+
/* ── 6. Spacing Scale (4 px base) ────────────────────────────────────── */
|
|
159
|
+
--space-0: 0px;
|
|
160
|
+
--space-0-5: 2px;
|
|
161
|
+
--space-1: 4px;
|
|
162
|
+
--space-1-5: 6px;
|
|
163
|
+
--space-2: 8px;
|
|
164
|
+
--space-3: 12px;
|
|
165
|
+
--space-4: 16px;
|
|
166
|
+
--space-5: 20px;
|
|
167
|
+
--space-6: 24px;
|
|
168
|
+
--space-8: 32px;
|
|
169
|
+
--space-10: 40px;
|
|
170
|
+
--space-11: 44px;
|
|
171
|
+
--space-12: 48px;
|
|
172
|
+
--space-14: 56px;
|
|
173
|
+
|
|
174
|
+
/* ── 7. Border Radius Scale ──────────────────────────────────────────── */
|
|
175
|
+
--radius-sm: 4px;
|
|
176
|
+
--radius-md: 6px;
|
|
177
|
+
--radius-lg: 10px;
|
|
178
|
+
--radius-xl: 20px;
|
|
179
|
+
--radius-full: 50%;
|
|
180
|
+
|
|
181
|
+
/* ── 8. Z-Index Scale ────────────────────────────────────────────────── */
|
|
182
|
+
--z-content: 2;
|
|
183
|
+
--z-bar: 100;
|
|
184
|
+
--z-nav: 200;
|
|
185
|
+
--z-progress: 300;
|
|
186
|
+
--z-overlay: 9999;
|
|
187
|
+
|
|
188
|
+
/* ── 9. Transitions ──────────────────────────────────────────────────── */
|
|
189
|
+
--transition-fast: 0.15s ease;
|
|
190
|
+
--transition-base: 0.25s ease;
|
|
191
|
+
--transition-slow: 0.4s ease;
|
|
192
|
+
--ease-slide: cubic-bezier(0.4, 0, 0.2, 1);
|
|
193
|
+
--duration-slide: 0.6s;
|
|
194
|
+
--duration-progress: 0.5s;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
198
|
+
|
|
199
|
+
html, body, #root {
|
|
200
|
+
width: 100%; height: 100%;
|
|
201
|
+
overflow: hidden;
|
|
202
|
+
font-family: var(--font-family);
|
|
203
|
+
background: var(--background);
|
|
204
|
+
color: var(--foreground);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
} /* end @layer base */
|
|
208
|
+
|
|
209
|
+
/* ── Components layer: engine chrome + slide primitives ─────────────────── */
|
|
210
|
+
@layer components {
|
|
211
|
+
|
|
212
|
+
/* ── Slide Engine ── */
|
|
213
|
+
.deck {
|
|
214
|
+
width: 100%; height: 100%;
|
|
215
|
+
position: relative;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.slide {
|
|
219
|
+
position: absolute;
|
|
220
|
+
inset: 0;
|
|
221
|
+
display: flex;
|
|
222
|
+
flex-direction: column;
|
|
223
|
+
justify-content: center;
|
|
224
|
+
align-items: stretch;
|
|
225
|
+
opacity: 0;
|
|
226
|
+
pointer-events: none;
|
|
227
|
+
transition: opacity var(--duration-slide) var(--ease-slide),
|
|
228
|
+
transform var(--duration-slide) var(--ease-slide);
|
|
229
|
+
transform: translateX(60px);
|
|
230
|
+
overflow: hidden;
|
|
231
|
+
}
|
|
232
|
+
.slide > * {
|
|
233
|
+
flex-grow: 0;
|
|
234
|
+
}
|
|
235
|
+
.slide.active {
|
|
236
|
+
opacity: 1;
|
|
237
|
+
pointer-events: auto;
|
|
238
|
+
transform: translateX(0);
|
|
239
|
+
}
|
|
240
|
+
.slide.exit-left {
|
|
241
|
+
opacity: 0;
|
|
242
|
+
transform: translateX(-60px);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* ── Dev-mode overflow warning ── */
|
|
246
|
+
.slide-overflow-warn {
|
|
247
|
+
position: absolute;
|
|
248
|
+
inset: 0;
|
|
249
|
+
border: 3px dashed var(--destructive);
|
|
250
|
+
pointer-events: none;
|
|
251
|
+
z-index: var(--z-overlay);
|
|
252
|
+
display: flex;
|
|
253
|
+
align-items: flex-end;
|
|
254
|
+
justify-content: center;
|
|
255
|
+
padding-bottom: var(--space-14);
|
|
256
|
+
background: var(--destructive-subtle);
|
|
257
|
+
font-size: var(--font-size-md);
|
|
258
|
+
font-weight: var(--font-weight-semibold);
|
|
259
|
+
color: var(--destructive);
|
|
260
|
+
letter-spacing: 0.3px;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* ── Shared Decorations ── */
|
|
264
|
+
.orb {
|
|
265
|
+
position: absolute;
|
|
266
|
+
border-radius: var(--radius-full);
|
|
267
|
+
filter: blur(2px);
|
|
268
|
+
opacity: 0.7;
|
|
269
|
+
}
|
|
270
|
+
.grid-dots {
|
|
271
|
+
position: absolute;
|
|
272
|
+
width: 200px; height: 200px;
|
|
273
|
+
background-image: radial-gradient(circle, var(--dot-color) 1px, transparent 1px);
|
|
274
|
+
background-size: 18px 18px;
|
|
275
|
+
opacity: 0.5;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* Accent bar left */
|
|
279
|
+
.accent-bar {
|
|
280
|
+
position: absolute;
|
|
281
|
+
left: var(--space-12); top: 15%; bottom: 15%;
|
|
282
|
+
width: 4px;
|
|
283
|
+
border-radius: 2px;
|
|
284
|
+
background: linear-gradient(to bottom, var(--purple), var(--accent), var(--cyan));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* ── Shared Layout ── */
|
|
288
|
+
.content-frame {
|
|
289
|
+
width: min(100%, var(--content-max-width));
|
|
290
|
+
margin-left: auto;
|
|
291
|
+
margin-right: auto;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.content-gutter {
|
|
295
|
+
padding-left: var(--content-gutter);
|
|
296
|
+
padding-right: var(--content-gutter);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* ══════════════════════════════════════════════════
|
|
300
|
+
Generic Thank-You Slide (deck-ty-* namespace)
|
|
301
|
+
══════════════════════════════════════════════════ */
|
|
302
|
+
.deck-ty {
|
|
303
|
+
background: var(--background);
|
|
304
|
+
padding: 0 0 var(--space-11) 0;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/* Ambient glow orbs */
|
|
308
|
+
.deck-ty-glow {
|
|
309
|
+
position: absolute;
|
|
310
|
+
border-radius: var(--radius-full);
|
|
311
|
+
filter: blur(80px);
|
|
312
|
+
pointer-events: none;
|
|
313
|
+
animation: deck-ty-pulse 6s ease-in-out infinite;
|
|
314
|
+
}
|
|
315
|
+
.deck-ty-glow1 { width: 300px; height: 300px; background: var(--glow-accent); top: -80px; left: -60px; }
|
|
316
|
+
.deck-ty-glow2 { width: 250px; height: 250px; background: var(--glow-purple); bottom: -40px; right: -40px; animation-delay: -2s; }
|
|
317
|
+
.deck-ty-glow3 { width: 200px; height: 200px; background: var(--glow-cyan); top: 50%; left: 60%; transform: translate(-50%,-50%); animation-delay: -4s; }
|
|
318
|
+
|
|
319
|
+
@keyframes deck-ty-pulse {
|
|
320
|
+
0%, 100% { transform: scale(1); opacity: 0.7; }
|
|
321
|
+
50% { transform: scale(1.15); opacity: 1; }
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Speed streaks */
|
|
325
|
+
.deck-ty-streak {
|
|
326
|
+
position: absolute;
|
|
327
|
+
height: 1px;
|
|
328
|
+
border-radius: 1px;
|
|
329
|
+
opacity: 0;
|
|
330
|
+
animation: deck-ty-streak-move 4s ease-in-out infinite;
|
|
331
|
+
}
|
|
332
|
+
.deck-ty-streak1 { width: 120px; top: 15%; left: -120px; background: linear-gradient(90deg, transparent, var(--accent)); animation-delay: 0s; }
|
|
333
|
+
.deck-ty-streak2 { width: 80px; top: 30%; left: -80px; background: linear-gradient(90deg, transparent, var(--purple)); animation-delay: 0.6s; }
|
|
334
|
+
.deck-ty-streak3 { width: 100px; top: 45%; left: -100px; background: linear-gradient(90deg, transparent, var(--cyan)); animation-delay: 1.2s; }
|
|
335
|
+
.deck-ty-streak4 { width: 60px; top: 60%; left: -60px; background: linear-gradient(90deg, transparent, var(--green)); animation-delay: 1.8s; }
|
|
336
|
+
.deck-ty-streak5 { width: 90px; top: 75%; left: -90px; background: linear-gradient(90deg, transparent, var(--pink)); animation-delay: 2.4s; }
|
|
337
|
+
.deck-ty-streak6 { width: 70px; top: 20%; right: -70px; background: linear-gradient(270deg, transparent, var(--accent)); animation-delay: 0.3s; }
|
|
338
|
+
.deck-ty-streak7 { width: 110px; top: 50%; right: -110px; background: linear-gradient(270deg, transparent, var(--purple)); animation-delay: 1.5s; }
|
|
339
|
+
.deck-ty-streak8 { width: 85px; top: 80%; right: -85px; background: linear-gradient(270deg, transparent, var(--cyan)); animation-delay: 2.1s; }
|
|
340
|
+
|
|
341
|
+
@keyframes deck-ty-streak-move {
|
|
342
|
+
0% { transform: translateX(0); opacity: 0; }
|
|
343
|
+
10% { opacity: 0.6; }
|
|
344
|
+
50% { opacity: 0.3; }
|
|
345
|
+
100% { transform: translateX(calc(100vw + 200px)); opacity: 0; }
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/* Content */
|
|
349
|
+
.deck-ty-content {
|
|
350
|
+
text-align: left;
|
|
351
|
+
position: relative;
|
|
352
|
+
z-index: var(--z-content);
|
|
353
|
+
}
|
|
354
|
+
.deck-ty-title {
|
|
355
|
+
font-size: var(--font-size-display);
|
|
356
|
+
font-weight: var(--font-weight-extrabold);
|
|
357
|
+
letter-spacing: var(--letter-spacing-tight);
|
|
358
|
+
background: linear-gradient(135deg, var(--accent), var(--purple), var(--cyan), var(--accent));
|
|
359
|
+
background-size: 300% 300%;
|
|
360
|
+
-webkit-background-clip: text;
|
|
361
|
+
-webkit-text-fill-color: transparent;
|
|
362
|
+
background-clip: text;
|
|
363
|
+
animation: deck-ty-grad-shift 6s ease infinite;
|
|
364
|
+
margin-bottom: var(--space-4);
|
|
365
|
+
}
|
|
366
|
+
@keyframes deck-ty-grad-shift {
|
|
367
|
+
0% { background-position: 0% 50%; }
|
|
368
|
+
50% { background-position: 100% 50%; }
|
|
369
|
+
100% { background-position: 0% 50%; }
|
|
370
|
+
}
|
|
371
|
+
.deck-ty-subtitle {
|
|
372
|
+
font-size: var(--font-size-lg);
|
|
373
|
+
font-weight: var(--font-weight-regular);
|
|
374
|
+
color: var(--muted-foreground);
|
|
375
|
+
letter-spacing: var(--letter-spacing-wide);
|
|
376
|
+
}
|
|
377
|
+
.deck-ty-divider {
|
|
378
|
+
width: 60px;
|
|
379
|
+
height: 2px;
|
|
380
|
+
background: linear-gradient(90deg, var(--accent), var(--purple));
|
|
381
|
+
margin: var(--space-6) 0;
|
|
382
|
+
border-radius: 1px;
|
|
383
|
+
}
|
|
384
|
+
.deck-ty-tagline {
|
|
385
|
+
font-size: var(--font-size-md);
|
|
386
|
+
text-transform: uppercase;
|
|
387
|
+
letter-spacing: var(--letter-spacing-widest);
|
|
388
|
+
color: var(--muted-foreground);
|
|
389
|
+
opacity: 0.5;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
} /* end @layer components */
|