onboarding-kit 0.1.0 → 0.2.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/README.md +14 -1
- package/dist/brand.d.ts +38 -0
- package/dist/brand.js +319 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -5
- package/dist/render/assets.d.ts +2 -2
- package/dist/render/assets.js +167 -36
- package/dist/render/copy.d.ts +8 -0
- package/dist/render/copy.js +60 -7
- package/dist/render/index.d.ts +7 -3
- package/dist/render/index.js +88 -25
- package/dist/template.d.ts +7 -2
- package/dist/template.js +10 -2
- package/dist/types.d.ts +13 -0
- package/dist/validate.js +13 -1
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ Depois, envie isto para a sua IA:
|
|
|
27
27
|
|
|
28
28
|
Para ver o resultado, abra `/onboarding` com o app rodando em dev, ou rode `npx onboarding-kit serve`.
|
|
29
29
|
|
|
30
|
+
Se você abrir `/onboarding` antes da IA terminar, a página mostra o prompt pronto para copiar, acompanha as seções conforme a IA preenche o arquivo e abre a apresentação sozinha quando ela termina. Sem `onboarding.json`, o prompt já pede para a IA rodar o `init` antes.
|
|
31
|
+
|
|
30
32
|
## Comandos
|
|
31
33
|
|
|
32
34
|
| Comando | O que faz |
|
|
@@ -40,11 +42,22 @@ Para ver o resultado, abra `/onboarding` com o app rodando em dev, ou rode `npx
|
|
|
40
42
|
|
|
41
43
|
A página `/onboarding` é um tour em slides, contado como uma história: boas-vindas → o porquê → o negócio → o produto → vocabulário (com cartões que viram e um quiz) → regras do jogo → stack → arquitetura → rodando na máquina → jeito da casa → tour pelo código → cuidados → decisões → primeira missão → final.
|
|
42
44
|
|
|
45
|
+
Os capítulos entram com uma cortina animada, os elementos aparecem em cascata, o fundo muda de cor junto com o capítulo e os cartões inclinam com o mouse. Tudo isso é desligado quando o sistema pede movimento reduzido.
|
|
46
|
+
|
|
43
47
|
Navegação por ← →, espaço, swipe no celular ou pelos segmentos coloridos no topo. `O` abre o índice. O progresso e as tarefas marcadas ficam salvos no navegador. Tem tema claro e escuro. Capítulos sem conteúdo são pulados e listas longas viram vários slides.
|
|
44
48
|
|
|
49
|
+
## Cara da marca
|
|
50
|
+
|
|
51
|
+
A apresentação usa as cores e o logo do projeto. A IA preenche `brand` (`primaryColor`, `palette`, `logo`, `favicon`) e o que ficar vazio é detectado automaticamente:
|
|
52
|
+
|
|
53
|
+
- **Cores:** `tailwind.config` (`brand`, `primary`, `accent`, inclusive `colors.indigo`), `@theme` do Tailwind v4, variáveis CSS como `--primary` e `--brand` (hex, rgb, hsl, o formato do shadcn/ui e oklch), variáveis SCSS/LESS, temas JS (`palette.primary.main`) e o `theme_color` do manifest.
|
|
54
|
+
- **Logo e favicon:** `public/`, `assets/`, `src/assets/` e `app/` (`logo.*`, `icon.*`, `favicon.*`). Os arquivos de exemplo do framework (`next.svg`, `vercel.svg`, `vite.svg`…) são ignorados.
|
|
55
|
+
|
|
56
|
+
Com uma cor, os capítulos variam em torno dela. Com várias, eles se revezam entre elas. Marcas em preto e branco viram um tema monocromático.
|
|
57
|
+
|
|
45
58
|
## O que vai no JSON
|
|
46
59
|
|
|
47
|
-
`project`, `business` (modelo de negócio, valor entregue, perfis e jornadas), `gettingStarted`, `stack`, `architecture` (com diagrama Mermaid), `conventions`, `domain` (glossário e regras de negócio), `features`, `tours` pelo código, `gotchas`, `decisions` e `
|
|
60
|
+
`project`, `business` (modelo de negócio, valor entregue, perfis e jornadas), `gettingStarted`, `stack`, `architecture` (com diagrama Mermaid), `conventions`, `domain` (glossário e regras de negócio), `features`, `tours` pelo código, `gotchas`, `decisions`, `firstTasks` e `brand` (cores e logo).
|
|
48
61
|
|
|
49
62
|
Toda afirmação aponta para arquivos reais (`evidence: ["src/orders/orders.service.ts:42"]`). Quando `project.repoUrl` está preenchido, essas referências viram links para o código.
|
|
50
63
|
|
package/dist/brand.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { OnboardingData } from "./types";
|
|
2
|
+
/** Cor em HSL: h 0–360, s e l 0–100. */
|
|
3
|
+
export interface Hsl {
|
|
4
|
+
h: number;
|
|
5
|
+
s: number;
|
|
6
|
+
l: number;
|
|
7
|
+
}
|
|
8
|
+
export interface ResolvedBrand {
|
|
9
|
+
/** Cores da marca, a principal primeiro. */
|
|
10
|
+
colors: Hsl[];
|
|
11
|
+
/** Logo e favicon como data URI, prontos para <img>/<link>. */
|
|
12
|
+
logo?: string;
|
|
13
|
+
favicon?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Lê uma cor CSS: #hex, rgb(), hsl(), oklch(), o trio "222 47% 11%" do shadcn/ui
|
|
17
|
+
* ou um nome da paleta do Tailwind ("indigo", "indigo-600").
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseColor(input: string): Hsl | undefined;
|
|
20
|
+
export declare function toHex({ h, s, l }: Hsl): string;
|
|
21
|
+
/** Cor sem matiz perceptível (preto, branco, cinzas). */
|
|
22
|
+
export declare function isAchromatic(c: Hsl): boolean;
|
|
23
|
+
/** Procura cores nomeadas como brand/primary/accent em CSS, SCSS, configs JS/TS e manifestos. */
|
|
24
|
+
export declare function extractColors(source: string): {
|
|
25
|
+
role: string;
|
|
26
|
+
value: string;
|
|
27
|
+
}[];
|
|
28
|
+
export declare function detectColors(root: string): Hsl[];
|
|
29
|
+
export declare function detectImage(root: string, kind: "logo" | "favicon"): string | undefined;
|
|
30
|
+
/** Lê uma imagem do repositório como data URI, só se estiver dentro da raiz e for uma imagem pequena. */
|
|
31
|
+
export declare function imageDataUri(root: string, path: string): string | undefined;
|
|
32
|
+
/**
|
|
33
|
+
* Junta o que a IA preencheu em `brand` com o que dá para detectar no repositório.
|
|
34
|
+
* O JSON tem prioridade; a detecção cobre o que faltar. Sem `root`, usa só o JSON.
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolveBrand(data: Partial<OnboardingData> | undefined, root?: string): ResolvedBrand;
|
|
37
|
+
/** Nome do package.json da raiz, para identificar o projeto antes da IA preencher o onboarding. */
|
|
38
|
+
export declare function packageName(root?: string): string | undefined;
|
package/dist/brand.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseColor = parseColor;
|
|
4
|
+
exports.toHex = toHex;
|
|
5
|
+
exports.isAchromatic = isAchromatic;
|
|
6
|
+
exports.extractColors = extractColors;
|
|
7
|
+
exports.detectColors = detectColors;
|
|
8
|
+
exports.detectImage = detectImage;
|
|
9
|
+
exports.imageDataUri = imageDataUri;
|
|
10
|
+
exports.resolveBrand = resolveBrand;
|
|
11
|
+
exports.packageName = packageName;
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const load_1 = require("./load");
|
|
15
|
+
/* ───────────────────────── cores ───────────────────────── */
|
|
16
|
+
/** Tons 500 da paleta padrão do Tailwind, para configs como `primary: colors.indigo`. */
|
|
17
|
+
const TAILWIND_500 = {
|
|
18
|
+
slate: "#64748b", gray: "#6b7280", zinc: "#71717a", neutral: "#737373", stone: "#78716c",
|
|
19
|
+
red: "#ef4444", orange: "#f97316", amber: "#f59e0b", yellow: "#eab308", lime: "#84cc16",
|
|
20
|
+
green: "#22c55e", emerald: "#10b981", teal: "#14b8a6", cyan: "#06b6d4", sky: "#0ea5e9",
|
|
21
|
+
blue: "#3b82f6", indigo: "#6366f1", violet: "#8b5cf6", purple: "#a855f7", fuchsia: "#d946ef",
|
|
22
|
+
pink: "#ec4899", rose: "#f43f5e",
|
|
23
|
+
};
|
|
24
|
+
const clamp01 = (n) => Math.min(1, Math.max(0, n));
|
|
25
|
+
function num(value, scale = 1) {
|
|
26
|
+
return value.endsWith("%") ? (parseFloat(value) / 100) * scale : parseFloat(value);
|
|
27
|
+
}
|
|
28
|
+
function hslToRgb(h, s, l) {
|
|
29
|
+
s = clamp01(s / 100);
|
|
30
|
+
l = clamp01(l / 100);
|
|
31
|
+
const k = (n) => (n + h / 30) % 12;
|
|
32
|
+
const a = s * Math.min(l, 1 - l);
|
|
33
|
+
const f = (n) => l - a * Math.max(-1, Math.min(k(n) - 3, 9 - k(n), 1));
|
|
34
|
+
return [f(0) * 255, f(8) * 255, f(4) * 255];
|
|
35
|
+
}
|
|
36
|
+
function oklchToRgb(L, C, H) {
|
|
37
|
+
const a = C * Math.cos((H * Math.PI) / 180);
|
|
38
|
+
const b = C * Math.sin((H * Math.PI) / 180);
|
|
39
|
+
const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
|
|
40
|
+
const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
|
|
41
|
+
const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
|
|
42
|
+
const linear = [
|
|
43
|
+
4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,
|
|
44
|
+
-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,
|
|
45
|
+
-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,
|
|
46
|
+
];
|
|
47
|
+
return linear.map((x) => {
|
|
48
|
+
const v = x <= 0.0031308 ? 12.92 * x : 1.055 * Math.abs(x) ** (1 / 2.4) - 0.055;
|
|
49
|
+
return clamp01(v) * 255;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function rgbToHsl([r, g, b]) {
|
|
53
|
+
r /= 255;
|
|
54
|
+
g /= 255;
|
|
55
|
+
b /= 255;
|
|
56
|
+
const max = Math.max(r, g, b);
|
|
57
|
+
const min = Math.min(r, g, b);
|
|
58
|
+
const l = (max + min) / 2;
|
|
59
|
+
const d = max - min;
|
|
60
|
+
if (d === 0)
|
|
61
|
+
return { h: 0, s: 0, l: l * 100 };
|
|
62
|
+
const s = d / (1 - Math.abs(2 * l - 1));
|
|
63
|
+
const h = max === r ? ((g - b) / d) % 6 : max === g ? (b - r) / d + 2 : (r - g) / d + 4;
|
|
64
|
+
return { h: (h * 60 + 360) % 360, s: s * 100, l: l * 100 };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Lê uma cor CSS: #hex, rgb(), hsl(), oklch(), o trio "222 47% 11%" do shadcn/ui
|
|
68
|
+
* ou um nome da paleta do Tailwind ("indigo", "indigo-600").
|
|
69
|
+
*/
|
|
70
|
+
function parseColor(input) {
|
|
71
|
+
const value = input.trim().toLowerCase().replace(/\s*!important$/, "");
|
|
72
|
+
const hex = /^#([0-9a-f]{3,8})$/.exec(value);
|
|
73
|
+
if (hex) {
|
|
74
|
+
let digits = hex[1];
|
|
75
|
+
if (digits.length === 3 || digits.length === 4)
|
|
76
|
+
digits = [...digits.slice(0, 3)].map((d) => d + d).join("");
|
|
77
|
+
if (digits.length !== 6 && digits.length !== 8)
|
|
78
|
+
return undefined;
|
|
79
|
+
return rgbToHsl([0, 2, 4].map((i) => parseInt(digits.slice(i, i + 2), 16)));
|
|
80
|
+
}
|
|
81
|
+
const rgb = /^rgba?\(\s*([\d.]+%?)[\s,]+([\d.]+%?)[\s,]+([\d.]+%?)/.exec(value);
|
|
82
|
+
if (rgb)
|
|
83
|
+
return rgbToHsl([num(rgb[1], 255), num(rgb[2], 255), num(rgb[3], 255)]);
|
|
84
|
+
const hsl = /^(?:hsla?\(\s*)?([\d.]+)(?:deg)?[\s,]+([\d.]+)%[\s,]+([\d.]+)%/.exec(value);
|
|
85
|
+
if (hsl)
|
|
86
|
+
return rgbToHsl(hslToRgb(parseFloat(hsl[1]), parseFloat(hsl[2]), parseFloat(hsl[3])));
|
|
87
|
+
const oklch = /^oklch\(\s*([\d.]+%?)\s+([\d.]+%?)\s+([\d.]+)(?:deg)?/.exec(value);
|
|
88
|
+
if (oklch)
|
|
89
|
+
return rgbToHsl(oklchToRgb(num(oklch[1]), num(oklch[2], 0.4), parseFloat(oklch[3])));
|
|
90
|
+
const named = /^([a-z]+)(?:-\d{2,3})?$/.exec(value);
|
|
91
|
+
if (named && TAILWIND_500[named[1]])
|
|
92
|
+
return parseColor(TAILWIND_500[named[1]]);
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
function toHex({ h, s, l }) {
|
|
96
|
+
return `#${hslToRgb(h, s, l)
|
|
97
|
+
.map((c) => Math.round(c).toString(16).padStart(2, "0"))
|
|
98
|
+
.join("")}`;
|
|
99
|
+
}
|
|
100
|
+
/** Cor sem matiz perceptível (preto, branco, cinzas). */
|
|
101
|
+
function isAchromatic(c) {
|
|
102
|
+
return c.s < 12 || c.l < 6 || c.l > 96;
|
|
103
|
+
}
|
|
104
|
+
/** Remove cores praticamente iguais, mantendo a ordem. */
|
|
105
|
+
function dedupe(colors) {
|
|
106
|
+
const out = [];
|
|
107
|
+
for (const c of colors) {
|
|
108
|
+
const same = out.some((o) => {
|
|
109
|
+
if (isAchromatic(o) && isAchromatic(c))
|
|
110
|
+
return true;
|
|
111
|
+
const dh = Math.min(Math.abs(o.h - c.h), 360 - Math.abs(o.h - c.h));
|
|
112
|
+
return dh < 14 && Math.abs(o.s - c.s) < 30;
|
|
113
|
+
});
|
|
114
|
+
if (!same)
|
|
115
|
+
out.push(c);
|
|
116
|
+
}
|
|
117
|
+
return out;
|
|
118
|
+
}
|
|
119
|
+
/* ───────────────────────── detecção ───────────────────────── */
|
|
120
|
+
const SKIP_DIRS = new Set(["node_modules", ".git", "dist", "build", "out", ".next", ".nuxt", ".output", ".svelte-kit", "coverage", ".turbo", ".vercel", ".cache", "vendor"]);
|
|
121
|
+
const STYLE_FILE = /(^tailwind\.config\.[cm]?[jt]s$)|(\.(css|scss|sass|less)$)|(^(theme|colors|tokens|palette|brand)\.[cm]?[jt]sx?$)|(^(manifest\.json|site\.webmanifest|manifest\.webmanifest)$)/i;
|
|
122
|
+
const MAX_FILES = 40;
|
|
123
|
+
const MAX_STYLE_BYTES = 300_000;
|
|
124
|
+
/** Peso do nome da variável: quanto menor, mais "cara da marca". */
|
|
125
|
+
const ROLE_WEIGHT = { brand: 0, primary: 1, theme_color: 1.5, themecolor: 1.5, accent: 2, secondary: 3 };
|
|
126
|
+
function listStyleFiles(root) {
|
|
127
|
+
const found = [];
|
|
128
|
+
const walk = (dir, depth) => {
|
|
129
|
+
if (depth > 4 || found.length >= MAX_FILES)
|
|
130
|
+
return;
|
|
131
|
+
let entries;
|
|
132
|
+
try {
|
|
133
|
+
entries = (0, node_fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
for (const entry of entries) {
|
|
139
|
+
if (found.length >= MAX_FILES)
|
|
140
|
+
return;
|
|
141
|
+
if (entry.isDirectory()) {
|
|
142
|
+
if (!SKIP_DIRS.has(entry.name) && !entry.name.startsWith("."))
|
|
143
|
+
walk((0, node_path_1.join)(dir, entry.name), depth + 1);
|
|
144
|
+
}
|
|
145
|
+
else if (STYLE_FILE.test(entry.name) && !entry.name.endsWith(".min.css")) {
|
|
146
|
+
found.push((0, node_path_1.join)(dir, entry.name));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
walk(root, 0);
|
|
151
|
+
// configs do Tailwind e manifestos primeiro: são as fontes mais confiáveis
|
|
152
|
+
return found.sort((a, b) => Number(!/tailwind\.config|manifest/i.test(a)) - Number(!/tailwind\.config|manifest/i.test(b)));
|
|
153
|
+
}
|
|
154
|
+
/** Procura cores nomeadas como brand/primary/accent em CSS, SCSS, configs JS/TS e manifestos. */
|
|
155
|
+
function extractColors(source) {
|
|
156
|
+
const found = [];
|
|
157
|
+
const add = (role, value, index) => found.push({ role: role.toLowerCase(), value: value.trim(), index });
|
|
158
|
+
const ROLE = "(brand|primary|accent|secondary)";
|
|
159
|
+
const SHADE = "(?:[-_](?:color|default|main|base|500|600))?";
|
|
160
|
+
// CSS: --primary, --color-brand-500 (Tailwind v4 @theme), --brand-color
|
|
161
|
+
for (const m of source.matchAll(new RegExp(`--(?:color-)?${ROLE}${SHADE}\\s*:\\s*([^;}{]+)`, "gi")))
|
|
162
|
+
add(m[1], m[2], m.index ?? 0);
|
|
163
|
+
// SCSS / LESS: $primary, @brand-color
|
|
164
|
+
for (const m of source.matchAll(new RegExp(`[$@]${ROLE}${SHADE}\\s*:\\s*([^;\\n]+)`, "gi")))
|
|
165
|
+
add(m[1], m[2], m.index ?? 0);
|
|
166
|
+
// JS/TS/JSON: primary: "#..." / "brand": "#..." / themeColor: "#..."
|
|
167
|
+
for (const m of source.matchAll(/["']?(brand|primary|accent|secondary|theme_color|themeColor)["']?\s*:\s*(["'`])([^"'`\n]+)\2/gi))
|
|
168
|
+
add(m[1], m[3], m.index ?? 0);
|
|
169
|
+
// JS/TS: primary: { DEFAULT: "#...", 500: "#..." } e MUI primary: { main: "#..." }
|
|
170
|
+
for (const m of source.matchAll(new RegExp(`["']?${ROLE}["']?\\s*:\\s*\\{([^{}]*)\\}`, "gi"))) {
|
|
171
|
+
const inner = /["']?(?:DEFAULT|main|500|600)["']?\s*:\s*(["'`])([^"'`\n]+)\1/i.exec(m[2]);
|
|
172
|
+
if (inner)
|
|
173
|
+
add(m[1], inner[2], m.index ?? 0);
|
|
174
|
+
}
|
|
175
|
+
// Tailwind: primary: colors.indigo
|
|
176
|
+
for (const m of source.matchAll(new RegExp(`["']?${ROLE}["']?\\s*:\\s*colors\\.(\\w+)`, "gi")))
|
|
177
|
+
add(m[1], m[2], m.index ?? 0);
|
|
178
|
+
return found.sort((a, b) => a.index - b.index).map(({ role, value }) => ({ role, value }));
|
|
179
|
+
}
|
|
180
|
+
function detectColors(root) {
|
|
181
|
+
const candidates = [];
|
|
182
|
+
let order = 0;
|
|
183
|
+
for (const file of listStyleFiles(root)) {
|
|
184
|
+
let source;
|
|
185
|
+
try {
|
|
186
|
+
if ((0, node_fs_1.statSync)(file).size > MAX_STYLE_BYTES)
|
|
187
|
+
continue;
|
|
188
|
+
source = (0, node_fs_1.readFileSync)(file, "utf8");
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
for (const { role, value } of extractColors(source)) {
|
|
194
|
+
const color = parseColor(value);
|
|
195
|
+
if (!color || color.l > 96)
|
|
196
|
+
continue; // branco não serve como cor de destaque
|
|
197
|
+
const weight = (ROLE_WEIGHT[role] ?? 4) + (isAchromatic(color) ? 2.5 : 0);
|
|
198
|
+
candidates.push({ color, weight, order: order++ });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
candidates.sort((a, b) => a.weight - b.weight || a.order - b.order);
|
|
202
|
+
return dedupe(candidates.map((c) => c.color)).slice(0, 5);
|
|
203
|
+
}
|
|
204
|
+
const IMAGE_TYPES = {
|
|
205
|
+
".svg": "image/svg+xml",
|
|
206
|
+
".png": "image/png",
|
|
207
|
+
".webp": "image/webp",
|
|
208
|
+
".avif": "image/avif",
|
|
209
|
+
".jpg": "image/jpeg",
|
|
210
|
+
".jpeg": "image/jpeg",
|
|
211
|
+
".gif": "image/gif",
|
|
212
|
+
".ico": "image/x-icon",
|
|
213
|
+
};
|
|
214
|
+
const IMAGE_DIRS = ["public", "public/images", "public/img", "public/assets", "public/static", "static", "assets", "src/assets", "src/assets/images", "app", "src/app"];
|
|
215
|
+
/** Arquivos que vêm nos templates do create-next-app, Vite etc. e não são a marca do projeto. */
|
|
216
|
+
const BOILERPLATE = /^(next|vercel|vite|react|file|globe|window|nuxt|svelte|angular|placeholder)\.(svg|png)$/i;
|
|
217
|
+
const MAX_IMAGE_BYTES = 400_000;
|
|
218
|
+
function imageScore(name, kind) {
|
|
219
|
+
const base = name.toLowerCase();
|
|
220
|
+
if (BOILERPLATE.test(base))
|
|
221
|
+
return undefined;
|
|
222
|
+
const ext = (0, node_path_1.extname)(base);
|
|
223
|
+
if (!IMAGE_TYPES[ext])
|
|
224
|
+
return undefined;
|
|
225
|
+
const extRank = [".svg", ".png", ".webp", ".avif", ".ico", ".jpg", ".jpeg", ".gif"].indexOf(ext) / 10;
|
|
226
|
+
const variant = /(white|light|inverse|negative|mono)/.test(base) ? 0.5 : 0;
|
|
227
|
+
const rank = kind === "logo"
|
|
228
|
+
? /logo/.test(base) ? 0 : /brand|wordmark/.test(base) ? 0.5 : /mark|symbol/.test(base) ? 1 : /^(icon|apple-icon|apple-touch-icon)/.test(base) ? 2 : /^favicon/.test(base) ? 3 : undefined
|
|
229
|
+
: /^favicon/.test(base) ? 0 : /^icon\./.test(base) ? 0.5 : /apple-(touch-)?icon/.test(base) ? 1 : /logo/.test(base) ? 2 : undefined;
|
|
230
|
+
return rank === undefined ? undefined : rank + variant + extRank;
|
|
231
|
+
}
|
|
232
|
+
function detectImage(root, kind) {
|
|
233
|
+
let best;
|
|
234
|
+
for (const dir of IMAGE_DIRS) {
|
|
235
|
+
let names;
|
|
236
|
+
try {
|
|
237
|
+
names = (0, node_fs_1.readdirSync)((0, node_path_1.join)(root, dir));
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
for (const name of names) {
|
|
243
|
+
const score = imageScore(name, kind);
|
|
244
|
+
if (score === undefined || (best && best.score <= score))
|
|
245
|
+
continue;
|
|
246
|
+
const path = `${dir}/${name}`;
|
|
247
|
+
try {
|
|
248
|
+
if ((0, node_fs_1.statSync)((0, node_path_1.join)(root, path)).isFile())
|
|
249
|
+
best = { path, score };
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
// ignora
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return best?.path;
|
|
257
|
+
}
|
|
258
|
+
/** Lê uma imagem do repositório como data URI, só se estiver dentro da raiz e for uma imagem pequena. */
|
|
259
|
+
function imageDataUri(root, path) {
|
|
260
|
+
const full = (0, node_path_1.resolve)(root, path);
|
|
261
|
+
const rel = (0, node_path_1.relative)(root, full);
|
|
262
|
+
if (!rel || rel.startsWith("..") || rel.split(node_path_1.sep).includes(".."))
|
|
263
|
+
return undefined;
|
|
264
|
+
const type = IMAGE_TYPES[(0, node_path_1.extname)(full).toLowerCase()];
|
|
265
|
+
if (!type || !(0, node_fs_1.existsSync)(full))
|
|
266
|
+
return undefined;
|
|
267
|
+
try {
|
|
268
|
+
if ((0, node_fs_1.statSync)(full).size > MAX_IMAGE_BYTES)
|
|
269
|
+
return undefined;
|
|
270
|
+
return `data:${type};base64,${(0, node_fs_1.readFileSync)(full).toString("base64")}`;
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
return undefined;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/* ───────────────────────── resolução ───────────────────────── */
|
|
277
|
+
const cache = new Map();
|
|
278
|
+
const CACHE_MS = 5_000;
|
|
279
|
+
function detect(root) {
|
|
280
|
+
const hit = cache.get(root);
|
|
281
|
+
if (hit && Date.now() - hit.at < CACHE_MS)
|
|
282
|
+
return hit;
|
|
283
|
+
const value = { at: Date.now(), colors: detectColors(root), logo: detectImage(root, "logo"), favicon: detectImage(root, "favicon") };
|
|
284
|
+
cache.set(root, value);
|
|
285
|
+
return value;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Junta o que a IA preencheu em `brand` com o que dá para detectar no repositório.
|
|
289
|
+
* O JSON tem prioridade; a detecção cobre o que faltar. Sem `root`, usa só o JSON.
|
|
290
|
+
*/
|
|
291
|
+
function resolveBrand(data, root) {
|
|
292
|
+
const b = data?.brand;
|
|
293
|
+
const declared = dedupe([b?.primaryColor, ...(Array.isArray(b?.palette) ? b.palette : [])]
|
|
294
|
+
.filter((v) => typeof v === "string" && !(0, load_1.isBlank)(v))
|
|
295
|
+
.map(parseColor)
|
|
296
|
+
.filter((c) => !!c));
|
|
297
|
+
const found = root ? detect(root) : undefined;
|
|
298
|
+
const colors = declared.length ? dedupe([...declared, ...(declared.length < 2 ? found?.colors ?? [] : [])]).slice(0, 5) : found?.colors ?? [];
|
|
299
|
+
const image = (declaredPath, detected) => {
|
|
300
|
+
if (!root)
|
|
301
|
+
return undefined;
|
|
302
|
+
return (declaredPath && !(0, load_1.isBlank)(declaredPath) ? imageDataUri(root, declaredPath) : undefined) ?? (detected ? imageDataUri(root, detected) : undefined);
|
|
303
|
+
};
|
|
304
|
+
const logo = image(b?.logo, found?.logo);
|
|
305
|
+
const favicon = image(b?.favicon, found?.favicon) ?? logo;
|
|
306
|
+
return { colors, logo, favicon };
|
|
307
|
+
}
|
|
308
|
+
/** Nome do package.json da raiz, para identificar o projeto antes da IA preencher o onboarding. */
|
|
309
|
+
function packageName(root) {
|
|
310
|
+
if (!root)
|
|
311
|
+
return undefined;
|
|
312
|
+
try {
|
|
313
|
+
const name = JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(root, "package.json"), "utf8")).name;
|
|
314
|
+
return typeof name === "string" && name.trim() ? name.trim() : undefined;
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
return undefined;
|
|
318
|
+
}
|
|
319
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export * from "./types";
|
|
|
2
2
|
export { createTemplate, aiPrompt, SCHEMA_VERSION } from "./template";
|
|
3
3
|
export { loadOnboarding, resolveEnabled, resolveFile, isBlank, DEFAULT_FILE } from "./load";
|
|
4
4
|
export { validateOnboarding, parseEvidence } from "./validate";
|
|
5
|
+
export { resolveBrand, parseColor, toHex } from "./brand";
|
|
6
|
+
export type { Hsl, ResolvedBrand } from "./brand";
|
|
5
7
|
export type { Issue, ValidateOptions } from "./validate";
|
|
6
8
|
export { renderOnboarding, escapeHtml } from "./render";
|
|
7
9
|
export interface RenderedPage {
|
package/dist/index.js
CHANGED
|
@@ -14,8 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.HTML_HEADERS = exports.escapeHtml = exports.renderOnboarding = exports.parseEvidence = exports.validateOnboarding = exports.DEFAULT_FILE = exports.isBlank = exports.resolveFile = exports.resolveEnabled = exports.loadOnboarding = exports.SCHEMA_VERSION = exports.aiPrompt = exports.createTemplate = void 0;
|
|
17
|
+
exports.HTML_HEADERS = exports.escapeHtml = exports.renderOnboarding = exports.toHex = exports.parseColor = exports.resolveBrand = exports.parseEvidence = exports.validateOnboarding = exports.DEFAULT_FILE = exports.isBlank = exports.resolveFile = exports.resolveEnabled = exports.loadOnboarding = exports.SCHEMA_VERSION = exports.aiPrompt = exports.createTemplate = void 0;
|
|
18
18
|
exports.renderOnboardingPage = renderOnboardingPage;
|
|
19
|
+
const node_path_1 = require("node:path");
|
|
19
20
|
const load_1 = require("./load");
|
|
20
21
|
const render_1 = require("./render");
|
|
21
22
|
__exportStar(require("./types"), exports);
|
|
@@ -32,22 +33,27 @@ Object.defineProperty(exports, "DEFAULT_FILE", { enumerable: true, get: function
|
|
|
32
33
|
var validate_1 = require("./validate");
|
|
33
34
|
Object.defineProperty(exports, "validateOnboarding", { enumerable: true, get: function () { return validate_1.validateOnboarding; } });
|
|
34
35
|
Object.defineProperty(exports, "parseEvidence", { enumerable: true, get: function () { return validate_1.parseEvidence; } });
|
|
36
|
+
var brand_1 = require("./brand");
|
|
37
|
+
Object.defineProperty(exports, "resolveBrand", { enumerable: true, get: function () { return brand_1.resolveBrand; } });
|
|
38
|
+
Object.defineProperty(exports, "parseColor", { enumerable: true, get: function () { return brand_1.parseColor; } });
|
|
39
|
+
Object.defineProperty(exports, "toHex", { enumerable: true, get: function () { return brand_1.toHex; } });
|
|
35
40
|
var render_2 = require("./render");
|
|
36
41
|
Object.defineProperty(exports, "renderOnboarding", { enumerable: true, get: function () { return render_2.renderOnboarding; } });
|
|
37
42
|
Object.defineProperty(exports, "escapeHtml", { enumerable: true, get: function () { return render_2.escapeHtml; } });
|
|
38
43
|
/** Lê o onboarding.json a cada chamada e devolve a página pronta (usado pelos adapters). */
|
|
39
44
|
async function renderOnboardingPage(file) {
|
|
40
45
|
const result = await (0, load_1.loadOnboarding)(file);
|
|
46
|
+
const root = (0, node_path_1.dirname)(result.file);
|
|
41
47
|
if (!result.ok) {
|
|
42
48
|
return result.reason === "missing"
|
|
43
|
-
? { status: 200, html: (0, render_1.renderMissingPage)() }
|
|
44
|
-
: { status: 500, html: (0, render_1.renderErrorPage)(result.message) };
|
|
49
|
+
? { status: 200, html: (0, render_1.renderMissingPage)(root) }
|
|
50
|
+
: { status: 500, html: (0, render_1.renderErrorPage)(result.message, root) };
|
|
45
51
|
}
|
|
46
52
|
try {
|
|
47
|
-
return { status: 200, html: (0, render_1.renderOnboarding)(result.data) };
|
|
53
|
+
return { status: 200, html: (0, render_1.renderOnboarding)(result.data, { root }) };
|
|
48
54
|
}
|
|
49
55
|
catch (err) {
|
|
50
|
-
return { status: 500, html: (0, render_1.renderErrorPage)(err.message) };
|
|
56
|
+
return { status: 500, html: (0, render_1.renderErrorPage)(err.message, root) };
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
exports.HTML_HEADERS = {
|
package/dist/render/assets.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const MERMAID_URL = "https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js";
|
|
2
2
|
export declare const FONTS = "<link rel=\"preconnect\" href=\"https://fonts.googleapis.com\"><link rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin><link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap\">";
|
|
3
|
-
export declare const CSS = "\n:root{--bg:#faf9f6;--surface:#fff;--surface-2:#f3f1ec;--text:#1b1a18;--muted:#68645c;--border:#e6e3dc;--track:#e8e5de;--shadow:0 1px 2px rgb(30 25 15/.04),0 10px 30px rgb(30 25 15/.07);--al:47%;--as:72%;--on-accent:#fff;--code-bg:#f1efe9;--term-bg:#161514;--term-text:#efece5;color-scheme:light}\n@media (prefers-color-scheme:dark){:root:not([data-theme=\"light\"]){--bg:#111110;--surface:#1a1918;--surface-2:#232220;--text:#f2f0eb;--muted:#a19d94;--border:#2c2a28;--track:#2a2826;--shadow:0 1px 2px rgb(0 0 0/.3),0 10px 30px rgb(0 0 0/.35);--al:70%;--as:78%;--on-accent:#111110;--code-bg:#262422;color-scheme:dark}}\n:root[data-theme=\"dark\"]{--bg:#111110;--surface:#1a1918;--surface-2:#232220;--text:#f2f0eb;--muted:#a19d94;--border:#2c2a28;--track:#2a2826;--shadow:0 1px 2px rgb(0 0 0/.3),0 10px 30px rgb(0 0 0/.35);--al:70%;--as:78%;--on-accent:#111110;--code-bg:#262422;color-scheme:dark}\n*{box-sizing:border-box}\nhtml,body{height:100%;margin:0}\nbody{background:var(--bg);color:var(--text);font:16px/1.6 \"Plus Jakarta Sans\",system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden}\nbody.solo{overflow:auto}\nbutton{font:inherit;color:inherit}\ncode,pre{font-family:\"JetBrains Mono\",ui-monospace,SFMono-Regular,Menlo,monospace}\ncode{font-size:.85em;background:var(--code-bg);padding:.12em .42em;border-radius:6px}\npre{margin:12px 0 0;background:var(--code-bg);border-radius:12px;padding:14px 16px;overflow-x:auto;font-size:.82rem;line-height:1.6}\npre code{background:none;padding:0;font-size:inherit}\n:focus-visible{outline:2px solid hsl(var(--h,255) var(--as) var(--al));outline-offset:2px}\n\n/* \u2500\u2500 estrutura \u2500\u2500 */\n.deck{position:fixed;inset:0;display:grid;grid-template-rows:auto minmax(0,1fr) auto}\n.topbar{display:flex;align-items:center;gap:18px;padding:16px 24px;z-index:3}\n.brand{font-weight:800;letter-spacing:-.01em;white-space:nowrap;max-width:20ch;overflow:hidden;text-overflow:ellipsis}\n.segments{flex:1;display:flex;gap:5px;align-items:center;min-width:0;height:20px}\n.seg{flex:var(--w) 1 0;min-width:6px;height:6px;border:0;padding:0;border-radius:99px;background:var(--track);cursor:pointer;overflow:hidden;position:relative;transition:height .2s}\n.seg:hover,.seg.is-current{height:9px}\n.seg>span{position:absolute;inset:0 auto 0 0;width:0;border-radius:inherit;background:hsl(var(--h) var(--as) var(--al));transition:width .5s cubic-bezier(.2,.7,.2,1)}\n.icon-btn{flex:none;width:40px;height:40px;display:grid;place-items:center;border-radius:12px;border:1px solid var(--border);background:var(--surface);cursor:pointer;color:var(--muted);transition:color .2s,transform .2s}\n.icon-btn:hover{color:var(--text);transform:translateY(-1px)}\n.icon-btn svg{width:18px;height:18px}\n.stage{position:relative;overflow:hidden}\n\n/* \u2500\u2500 slides \u2500\u2500 */\n.slide{--accent:hsl(var(--h) var(--as) var(--al));--accent-soft:hsl(var(--h) 85% 55% / .13);position:absolute;inset:0;display:flex;opacity:0;visibility:hidden;transform:translateX(56px);transition:opacity .45s ease,transform .6s cubic-bezier(.2,.7,.2,1),visibility .45s}\n.slide.is-before{transform:translateX(-56px)}\n.slide.is-active{opacity:1;visibility:visible;transform:none}\n.slide::before,.slide::after{content:\"\";position:absolute;border-radius:50%;pointer-events:none}\n.slide::before{width:72vmax;height:72vmax;right:-30vmax;top:-38vmax;background:radial-gradient(circle,hsl(var(--h) 90% 62% / .17),transparent 62%)}\n.slide::after{width:50vmax;height:50vmax;left:-24vmax;bottom:-30vmax;background:radial-gradient(circle,hsl(calc(var(--h) + 50) 90% 62% / .10),transparent 62%)}\n.slide-inner{position:relative;z-index:1;margin:auto;width:100%;max-width:1080px;max-height:100%;overflow-y:auto;padding:24px 40px 32px;scrollbar-width:thin;scrollbar-color:transparent transparent}\n.slide-inner:hover{scrollbar-color:var(--border) transparent}\n.slide-inner::-webkit-scrollbar{width:8px}.slide-inner::-webkit-scrollbar-thumb{background:transparent;border-radius:8px}.slide-inner:hover::-webkit-scrollbar-thumb{background:var(--border)}.slide-inner::-webkit-scrollbar-track{background:transparent}\n.kicker{display:inline-flex;align-items:center;gap:10px;margin:0 0 16px;font-size:.76rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}\n.kicker .num{display:grid;place-items:center;min-width:26px;height:26px;padding:0 6px;border-radius:9px;background:var(--accent-soft);letter-spacing:0;font-size:.8rem}\n.title{font-size:clamp(2rem,1.2rem + 2.8vw,3.4rem);line-height:1.06;letter-spacing:-.035em;font-weight:800;margin:0 0 14px;max-width:20ch;text-wrap:balance}\n.title .cont{font-size:.4em;font-weight:700;letter-spacing:0;color:var(--muted);vertical-align:middle;margin-left:6px}\n.lede{font-size:clamp(1.05rem,.95rem + .5vw,1.3rem);color:var(--muted);max-width:58ch;margin:0 0 30px;text-wrap:pretty}\n.statement{font-size:clamp(1.35rem,1rem + 1.4vw,2.1rem);line-height:1.32;font-weight:600;letter-spacing:-.02em;max-width:34ch;margin:0 0 32px;text-wrap:pretty}\n.statement.small{font-size:clamp(1.15rem,.95rem + .9vw,1.6rem);max-width:40ch;margin:22px 0 0}\n.mini-label,.label{display:block;font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);margin:0 0 10px}\n\n/* entrada dos elementos */\n.slide.is-active .reveal>*{animation:rise .6s cubic-bezier(.2,.7,.2,1) both}\n.reveal>*:nth-child(2){animation-delay:.06s!important}.reveal>*:nth-child(3){animation-delay:.12s!important}.reveal>*:nth-child(4){animation-delay:.18s!important}.reveal>*:nth-child(5){animation-delay:.24s!important}.reveal>*:nth-child(6){animation-delay:.3s!important}.reveal>*:nth-child(7){animation-delay:.36s!important}.reveal>*:nth-child(8){animation-delay:.42s!important}\n@keyframes rise{from{opacity:0;transform:translateY(16px)}}\n\n/* \u2500\u2500 blocos \u2500\u2500 */\n.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr))}\n.grid-2{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr))}\n.stack-list,.rules,.tasks,.modules,.quiz{display:grid;gap:14px}\n.card{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:22px;box-shadow:var(--shadow)}\n.card h3{margin:0 0 6px;font-size:1.12rem;letter-spacing:-.015em;line-height:1.3}\n.card p{margin:0;color:var(--muted)}\n.card p.strong{color:var(--text);font-size:1.08rem;font-weight:600}\n.card-top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:6px}\n.card-top h3{margin:0}\n.badge{flex:none;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:99px;background:var(--accent-soft);color:var(--accent);white-space:nowrap}\n.badge-strong{background:var(--accent);color:var(--on-accent)}\n.big-card{padding:28px}\n.big-card p{color:var(--text);font-size:1.12rem;line-height:1.55}\n.emoji{display:block;font-size:1.9rem;line-height:1;margin-bottom:14px}\n.evidence{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px}\n.ev{display:inline-flex;align-items:center;gap:6px;max-width:100%;font:500 .72rem/1.4 \"JetBrains Mono\",ui-monospace,monospace;padding:4px 9px;border-radius:8px;background:var(--surface-2);color:var(--muted);text-decoration:none;border:1px solid var(--border)}\n.ev span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\na.ev:hover{color:var(--accent);border-color:var(--accent)}\n.ev-lg{font-size:.92rem;padding:9px 14px;border-radius:12px;background:var(--surface);box-shadow:var(--shadow)}\n\n/* pessoas e jornadas */\n.actor{display:flex;gap:16px;align-items:flex-start}\n.avatar,.logo{flex:none;display:grid;place-items:center;font-weight:800;color:#fff;letter-spacing:-.02em}\n.avatar{width:50px;height:50px;border-radius:16px;background:linear-gradient(135deg,hsl(var(--ah) 72% 60%),hsl(calc(var(--ah) + 45) 72% 48%))}\n.flow{margin-bottom:28px}\n.flow h3{font-size:1.15rem;margin:0 0 14px}\n.chain{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px}\n.chain li{display:flex;align-items:center;gap:10px}\n.chain li:not(:last-child)::after{content:\"\u2192\";color:var(--accent);font-weight:800;font-size:1.1rem}\n.step{display:inline-flex;align-items:center;gap:10px;padding:10px 16px 10px 10px;border-radius:14px;background:var(--surface);border:1px solid var(--border);box-shadow:var(--shadow);font-weight:600;font-size:.95rem;line-height:1.35}\n.step b{display:grid;place-items:center;flex:none;width:26px;height:26px;border-radius:8px;background:var(--accent);color:var(--on-accent);font-size:.8rem}\n\n/* vocabul\u00E1rio */\n.flips{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(min(100%,220px),1fr))}\n.flip{perspective:1000px;border:0;padding:0;background:none;cursor:pointer;text-align:left;min-height:170px}\n.flip-inner{position:relative;display:block;width:100%;height:100%;min-height:170px;transition:transform .7s cubic-bezier(.2,.7,.2,1);transform-style:preserve-3d}\n.flip.is-flipped .flip-inner{transform:rotateY(180deg)}\n.face{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:space-between;gap:10px;padding:20px;border-radius:20px;border:1px solid var(--border);box-shadow:var(--shadow);backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:auto}\n.front{background:var(--surface)}\n.front strong{font-size:1.3rem;letter-spacing:-.02em;line-height:1.2}\n.front small{color:var(--muted);font-size:.76rem;font-weight:600}\n.back{background:var(--accent);color:var(--on-accent);border-color:transparent;transform:rotateY(180deg);font-size:.95rem;line-height:1.5;justify-content:center}\n.back code{background:rgb(255 255 255/.2);color:inherit}\n.flip:hover .front{border-color:var(--accent)}\n.quiz{gap:12px}\n.quiz-q{background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:16px 20px;box-shadow:var(--shadow)}\n.quiz-q .q{font-weight:700;margin:0 0 10px;font-size:1.04rem}\n.opts{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}\n.opt{text-align:left;padding:12px 14px;border-radius:12px;border:1.5px solid var(--border);background:var(--surface-2);cursor:pointer;line-height:1.4;font-size:.92rem;transition:border-color .2s,background .2s}\n.opt:hover:not(:disabled){border-color:var(--accent)}\n.opt:disabled{cursor:default}\n.opt.is-right{border-color:hsl(150 60% 42%);background:hsl(150 60% 42% / .14)}\n.opt.is-wrong{border-color:hsl(0 72% 56%);background:hsl(0 72% 56% / .12)}\n.feedback{margin:0;font-weight:700;font-size:.92rem}\n.feedback:not(:empty){margin-top:10px}\n.score{font-weight:800;color:var(--accent);font-size:1.1rem;min-height:1.6em;margin:18px 0 0}\n\n/* regras, stack, m\u00F3dulos */\n.rule{display:grid;grid-template-columns:auto 1fr;gap:22px;align-items:start}\n.rule-num{font-size:2.6rem;font-weight:800;letter-spacing:-.05em;line-height:1;color:var(--accent)}\n.tech-head{display:flex;align-items:center;gap:14px;margin-bottom:12px}\n.tech-head strong{display:block;font-size:1.06rem;line-height:1.25}\n.tech-head small{color:var(--muted);font-size:.78rem}\n.logo{width:46px;height:46px;border-radius:14px;font-size:.95rem;background:linear-gradient(135deg,hsl(var(--th) 68% 56%),hsl(calc(var(--th) + 35) 68% 44%))}\n.diagram{background:var(--surface);border:1px solid var(--border);border-radius:22px;padding:22px;box-shadow:var(--shadow);overflow:auto;max-height:58vh}\n.diagram pre.mermaid{width:100%;background:none;padding:0;margin:0;font-family:inherit;text-align:center;white-space:pre-wrap}\n.diagram svg{display:block;margin:0 auto;width:100%;height:auto;max-height:calc(58vh - 44px)}\n.module{display:grid;grid-template-columns:minmax(0,260px) 1fr;gap:18px;align-items:center;padding:16px 20px;border-radius:16px;background:var(--surface);border:1px solid var(--border)}\n.module strong{display:block;margin-bottom:4px}\n.module code{background:var(--accent-soft);color:var(--accent);font-size:.78rem}\n.module p{margin:0;color:var(--muted)}\n\n/* m\u00E3os \u00E0 obra */\n.pills{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 26px;padding:0;list-style:none}\n.pills li{padding:8px 16px;border-radius:99px;background:var(--surface);border:1px solid var(--border);font-weight:600;font-size:.92rem}\n.pills li::before{content:\"\u2713\";color:var(--accent);margin-right:8px;font-weight:800}\n.steps{list-style:none;counter-reset:s;padding:0;margin:0;display:grid;gap:10px}\n.steps li{counter-increment:s;display:flex;gap:16px;align-items:center;padding:14px 18px;background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:var(--shadow)}\n.steps li::before{content:counter(s);flex:none;width:32px;height:32px;border-radius:10px;display:grid;place-items:center;background:var(--accent);color:var(--on-accent);font-weight:800;font-size:.9rem}\n.terminal{background:var(--term-bg);color:var(--term-text);border-radius:20px;padding:6px 6px 10px;box-shadow:var(--shadow);border:1px solid var(--border)}\n.term-bar{display:flex;gap:7px;padding:10px 14px}\n.term-bar i{width:11px;height:11px;border-radius:50%;background:#ff5f57}.term-bar i:nth-child(2){background:#febc2e}.term-bar i:nth-child(3){background:#28c840}\n.cmd{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;padding:12px 16px;border-top:1px solid rgb(255 255 255/.07)}\n.cmd code{background:none;color:inherit;font-size:.92rem;padding:0;word-break:break-all}\n.cmd code::before{content:\"$ \";color:hsl(var(--h) 75% 66%)}\n.cmd p{margin:4px 0 0;color:rgb(255 255 255/.55);font-size:.86rem}\n.cmd p code{background:rgb(255 255 255/.08);padding:.1em .4em}.cmd p code::before{content:none}\n.copy{border:1px solid rgb(255 255 255/.16);background:transparent;color:inherit;border-radius:9px;padding:6px 12px;font-size:.78rem;font-weight:600;cursor:pointer}\n.copy:hover{background:rgb(255 255 255/.08)}\n.env code{font-size:.84rem;background:var(--accent-soft);color:var(--accent)}\n\n/* tour */\n.route{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:8px;counter-reset:r}\n.route li{counter-increment:r;display:flex;align-items:center;gap:8px}\n.route li::before{content:counter(r);display:grid;place-items:center;width:24px;height:24px;border-radius:50%;background:var(--accent);color:var(--on-accent);font-size:.75rem;font-weight:800}\n.route code{background:var(--surface);border:1px solid var(--border)}\n.tour-step{display:grid;grid-template-columns:auto 1fr;gap:36px;align-items:start;margin-top:8px}\n.bignum{font-size:clamp(5rem,3rem + 7vw,10rem);font-weight:800;line-height:.82;letter-spacing:-.06em;color:var(--accent);opacity:.22}\n.stops{display:flex;gap:6px;margin-top:32px}\n.stops i{width:28px;height:6px;border-radius:99px;background:var(--track);transition:background .3s}\n.stops i.on{background:var(--accent)}\n\n/* cuidados, decis\u00F5es, miss\u00E3o */\n.gotcha{display:grid;grid-template-columns:auto 1fr;gap:16px;border-left:4px solid var(--accent)}\n.gotcha .emoji{margin:0}\n.split{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));margin-top:14px}\n.split p{color:var(--text)}\n.task{display:flex;gap:16px;align-items:flex-start;padding:18px 20px;border-radius:18px;background:var(--surface);border:1px solid var(--border);cursor:pointer;box-shadow:var(--shadow);transition:opacity .25s,border-color .25s}\n.task:hover{border-color:var(--accent)}\n.task input{appearance:none;-webkit-appearance:none;flex:none;width:26px;height:26px;margin:1px 0 0;border-radius:9px;border:2px solid var(--border);display:grid;place-items:center;cursor:pointer;transition:background .2s,border-color .2s}\n.task input:checked{background:var(--accent);border-color:var(--accent)}\n.task input:checked::after{content:\"\u2713\";color:var(--on-accent);font-weight:800;font-size:.9rem}\n.task strong{display:block;font-size:1.05rem}\n.task-desc{display:block;color:var(--muted);margin-top:2px}\n.task:has(input:checked){opacity:.6}\n.task:has(input:checked) strong{text-decoration:line-through}\n\n/* boas-vindas e final */\n.welcome .hi{font-size:clamp(1.05rem,.95rem + .4vw,1.25rem);font-weight:700;color:var(--muted);margin:0 0 10px;display:flex;align-items:center;gap:10px}\n.wave{display:inline-block;font-size:1.6em;transform-origin:70% 70%}\n.slide.is-active .wave{animation:wave 2s ease-in-out .4s 1}\n@keyframes wave{0%,60%,100%{transform:rotate(0)}10%,30%{transform:rotate(14deg)}20%,40%{transform:rotate(-8deg)}50%{transform:rotate(10deg)}}\n.welcome .title{font-size:clamp(2.4rem,min(1.4rem + 4.6vw,9vh),5.2rem);max-width:16ch}\n.welcome .lede{margin-bottom:24px}\n.grad{background:linear-gradient(110deg,hsl(var(--h) 85% var(--al)),hsl(calc(var(--h) + 70) 85% var(--al)));-webkit-background-clip:text;background-clip:text;color:transparent}\n.tagline{font-size:clamp(1.15rem,1rem + .7vw,1.5rem);font-weight:600;margin:0 0 14px;max-width:44ch;text-wrap:balance}\n.cta{display:inline-flex;align-items:center;gap:10px;padding:15px 24px;border-radius:16px;border:0;background:var(--accent);color:var(--on-accent);font-weight:800;font-size:1.02rem;cursor:pointer;box-shadow:0 10px 28px hsl(var(--h) 80% 50% / .35);transition:transform .2s,box-shadow .2s}\n.cta:hover{transform:translateY(-2px);box-shadow:0 14px 34px hsl(var(--h) 80% 50% / .42)}\n.cta .arrow{transition:transform .2s}.cta:hover .arrow{transform:translateX(3px)}\n.journey{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:8px}\n.journey button{display:inline-flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:99px;background:var(--surface);border:1px solid var(--border);cursor:pointer;font-size:.86rem;font-weight:600;transition:border-color .2s,transform .2s}\n.journey button:hover{border-color:hsl(var(--ch) var(--as) var(--al));transform:translateY(-1px)}\n.journey .n{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;font-size:.72rem;font-weight:800;background:hsl(var(--ch) 85% 55% / .15);color:hsl(var(--ch) var(--as) var(--al))}\n.journey-wrap{margin-top:clamp(20px,4vh,44px)}\n.meta{margin-top:20px}\n.meta{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:26px;color:var(--muted);font-size:.84rem}\n.meta a{color:inherit}\n.finale{text-align:center}\n.finale .title,.finale .lede{margin-left:auto;margin-right:auto}\n.party{display:block;font-size:clamp(3.5rem,2.5rem + 4vw,6rem);line-height:1;margin-bottom:16px}\n.slide.is-active .party{animation:pop .8s cubic-bezier(.2,1.6,.4,1) both}\n@keyframes pop{from{transform:scale(.3) rotate(-20deg);opacity:0}}\n.recap{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;list-style:none;padding:0;margin:0 auto 22px;max-width:760px}\n.recap li{padding:6px 14px;border-radius:99px;background:var(--surface);border:1px solid var(--border);font-size:.86rem;font-weight:600}\n.recap li::before{content:\"\u2713 \";color:hsl(var(--ch) var(--as) var(--al));font-weight:800}\n.task-count{color:var(--muted);font-weight:600;margin:0 0 26px}\n.actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}\n.ghost{padding:15px 22px;border-radius:16px;border:1px solid var(--border);background:var(--surface);font-weight:700;cursor:pointer}\n.ghost:hover{border-color:var(--accent)}\n\n/* \u2500\u2500 controles \u2500\u2500 */\n.controls{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:12px;padding:12px 24px 20px;z-index:3}\n.controls [data-prev]{justify-self:start}\n.controls [data-next]{justify-self:end}\n.nav-btn{display:inline-flex;align-items:center;gap:8px;padding:12px 20px;border-radius:14px;border:1px solid var(--border);background:var(--surface);font-weight:700;cursor:pointer;box-shadow:var(--shadow);transition:transform .2s,opacity .2s}\n.nav-btn:hover:not(:disabled){transform:translateY(-1px)}\n.nav-btn.primary{background:var(--text);color:var(--bg);border-color:var(--text)}\n.nav-btn:disabled{opacity:0;visibility:hidden}\n.where{display:flex;flex-direction:column;align-items:center;text-align:center;font-size:.8rem;color:var(--muted);line-height:1.4}\n.where strong{color:var(--text);font-size:.9rem}\n.hint.is-hidden{display:none}\n\n/* \u00EDndice */\n.overview{position:fixed;inset:0;z-index:20;background:color-mix(in srgb,var(--bg) 90%,transparent);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);overflow-y:auto;padding:28px 24px 56px;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .25s,visibility .25s}\n.overview.is-open{opacity:1;visibility:visible;pointer-events:auto}\n.overview-inner{max-width:1040px;margin:0 auto}\n.overview-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}\n.overview-head h2{margin:0;font-size:1.6rem;letter-spacing:-.02em}\n.ov-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(min(100%,290px),1fr))}\n.ov-chapter{background:var(--surface);border:1px solid var(--border);border-radius:18px;padding:16px;box-shadow:var(--shadow)}\n.ov-chapter h3{display:flex;gap:10px;align-items:center;margin:0 0 8px;font-size:1rem}\n.ov-chapter h3 .n{display:grid;place-items:center;width:26px;height:26px;border-radius:9px;font-size:.78rem;background:hsl(var(--ch) 85% 55% / .15);color:hsl(var(--ch) var(--as) var(--al))}\n.ov-chapter button{display:block;width:100%;text-align:left;padding:7px 10px;border-radius:10px;border:0;background:none;cursor:pointer;color:var(--muted);font-size:.9rem;line-height:1.35}\n.ov-chapter button:hover,.ov-chapter button.is-current{background:var(--surface-2);color:var(--text)}\n.ov-chapter button.is-current{font-weight:700}\n\n/* aviso de retomada */\n.toast{position:fixed;left:50%;bottom:96px;z-index:15;display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:center;max-width:calc(100% - 32px);padding:12px 14px 12px 18px;border-radius:16px;background:var(--text);color:var(--bg);box-shadow:0 12px 40px rgb(0 0 0/.25);font-weight:600;font-size:.92rem;transform:translate(-50%,20px);opacity:0;visibility:hidden;transition:.35s cubic-bezier(.2,.7,.2,1)}\n.toast.is-open{transform:translate(-50%,0);opacity:1;visibility:visible}\n.toast button{border:0;border-radius:10px;padding:8px 12px;font-weight:700;cursor:pointer;background:rgb(127 127 127/.25);color:inherit}\n.toast button.yes{background:var(--bg);color:var(--text)}\n\n/* confete */\n.confetti{position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:30}\n.confetti i{position:absolute;top:-16px;width:9px;height:15px;border-radius:2px;animation:fall linear forwards}\n@keyframes fall{to{transform:translate3d(var(--dx),110vh,0) rotate(var(--r))}}\n\n/* p\u00E1ginas de aviso */\n.solo-wrap{min-height:100%;display:grid;place-items:center;padding:32px 16px;--h:255;--accent:hsl(var(--h) var(--as) var(--al));--accent-soft:hsl(var(--h) 85% 55% / .13)}\n.solo-card{max-width:640px;width:100%;background:var(--surface);border:1px solid var(--border);border-radius:24px;padding:36px;box-shadow:var(--shadow)}\n.solo-card h1{font-size:clamp(1.6rem,1.2rem + 1.4vw,2.2rem);letter-spacing:-.03em;line-height:1.15;margin:0 0 12px}\n.solo-card p{color:var(--muted);margin:0 0 20px}\n.prompt{display:flex;gap:10px;align-items:flex-start}\n.prompt pre{flex:1;white-space:pre-wrap;margin:0}\n.prompt .copy{color:var(--text);border-color:var(--border)}\n\n/* \u2500\u2500 telas pequenas \u2500\u2500 */\n@media (max-width:760px){\n .topbar{padding:12px 16px;gap:10px}\n .brand{display:none}\n .slide-inner{padding:12px 16px 28px}\n .controls{padding:10px 16px 14px;gap:8px}\n .nav-btn{padding:11px 14px}\n .nav-btn .txt,.hint{display:none}\n .rule,.tour-step{grid-template-columns:1fr;gap:6px}\n .module{grid-template-columns:1fr;gap:6px}\n .bignum{font-size:4rem}\n .journey-wrap{margin-top:32px}\n .solo-card{padding:24px}\n}\n@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}\n";
|
|
4
|
-
export declare const JS = "\n(function(){\n var root=document.documentElement;\n var KEY='onboarding-kit:'+location.pathname+':';\n function sget(k){try{return localStorage.getItem(KEY+k)}catch(e){return null}}\n function sset(k,v){try{localStorage.setItem(KEY+k,v)}catch(e){}}\n function fill(t,o){return t.replace(/\\{(\\w+)\\}/g,function(_,k){return o[k]})}\n\n var theme=sget('theme'); if(theme) root.setAttribute('data-theme',theme);\n function isDark(){var t=root.getAttribute('data-theme');return t?t==='dark':matchMedia('(prefers-color-scheme: dark)').matches}\n\n var slides=[].slice.call(document.querySelectorAll('.slide'));\n var n=slides.length,cur=-1,celebrated=false;\n var segs=[].slice.call(document.querySelectorAll('.seg'));\n var $=function(id){return document.getElementById(id)};\n var prevBtn=document.querySelector('[data-prev]'),nextBtn=document.querySelector('[data-next]');\n var overview=$('ok-overview'),toast=$('ok-toast'),hint=$('ok-hint');\n\n function go(i){\n if(!n) return;\n i=Math.max(0,Math.min(n-1,i|0)); if(i===cur) return;\n slides.forEach(function(s,j){var on=j===i;s.classList.toggle('is-active',on);s.classList.toggle('is-before',j<i);s.setAttribute('aria-hidden',on?'false':'true');if('inert' in s)s.inert=!on});\n cur=i;\n var s=slides[i],inner=s.querySelector('.slide-inner'); if(inner) inner.scrollTop=0;\n segs.forEach(function(g){var st=+g.dataset.start,c=+g.dataset.count,p=i<st?0:i>=st+c?1:(i-st+1)/c;g.firstElementChild.style.width=(p*100)+'%';g.classList.toggle('is-current',i>=st&&i<st+c)});\n $('ok-chapter').textContent=s.dataset.chapterName;\n $('ok-count').textContent=(i+1)+' / '+n;\n prevBtn.disabled=i===0; nextBtn.disabled=i===n-1;\n [].forEach.call(document.querySelectorAll('.ov-chapter [data-go]'),function(b){b.classList.toggle('is-current',+b.dataset.go===i)});\n try{history.replaceState(null,'','#/'+(i+1))}catch(e){}\n sset('slide',String(i));\n if(s.dataset.kind==='finale'&&!celebrated){celebrated=true;confetti()}\n }\n function step(d){go(cur+d);if(hint)hint.classList.add('is-hidden');closeToast()}\n function openOverview(open){if(!overview)return;overview.classList.toggle('is-open',open);overview.setAttribute('aria-hidden',open?'false':'true');if(open){var c=overview.querySelector('.is-current')||overview.querySelector('button');c&&c.focus()}}\n function closeToast(){if(toast)toast.classList.remove('is-open')}\n\n document.addEventListener('click',function(e){\n var el=e.target.closest('button,[data-go]'); if(!el) return;\n if(el.hasAttribute('data-next')) return step(1);\n if(el.hasAttribute('data-prev')) return step(-1);\n if(el.hasAttribute('data-go')){openOverview(false);closeToast();return go(+el.dataset.go)}\n if(el.hasAttribute('data-overview')) return openOverview(true);\n if(el.hasAttribute('data-close')) return openOverview(false);\n if(el.hasAttribute('data-theme-toggle')){var nt=isDark()?'light':'dark';root.setAttribute('data-theme',nt);sset('theme',nt);return}\n if(el.hasAttribute('data-resume')){closeToast();return go(+el.dataset.resume)}\n if(el.hasAttribute('data-dismiss')) return closeToast();\n if(el.hasAttribute('data-copy')){\n var txt=el.dataset.copy,orig=el.textContent;\n if(navigator.clipboard) navigator.clipboard.writeText(txt).then(function(){el.textContent=el.dataset.done||'\u2713';setTimeout(function(){el.textContent=orig},1600)});\n return;\n }\n if(el.classList.contains('flip')){var f=el.classList.toggle('is-flipped');el.setAttribute('aria-pressed',f?'true':'false');return}\n if(el.classList.contains('opt')){\n var q=el.closest('[data-quiz]'); if(!q||q.dataset.done) return;\n var right=el.dataset.correct==='1'; q.dataset.done=right?'right':'wrong';\n [].forEach.call(q.querySelectorAll('.opt'),function(o){o.disabled=true;if(o.dataset.correct==='1')o.classList.add('is-right')});\n if(!right) el.classList.add('is-wrong');\n q.querySelector('.feedback').textContent=right?q.dataset.right:q.dataset.wrong;\n var slide=q.closest('.slide'),all=slide.querySelectorAll('[data-quiz]'),done=slide.querySelectorAll('[data-quiz][data-done]'),ok=slide.querySelectorAll('[data-quiz][data-done=\"right\"]');\n var score=slide.querySelector('[data-quiz-score]');\n if(score&&done.length===all.length) score.textContent=fill(score.dataset.template,{right:ok.length,total:all.length});\n }\n });\n\n document.addEventListener('keydown',function(e){\n if(e.metaKey||e.ctrlKey||e.altKey||e.target.closest('input,textarea,select')) return;\n var k=e.key;\n if(overview&&overview.classList.contains('is-open')){if(k==='Escape'||k==='o'){e.preventDefault();openOverview(false)}return}\n if(k===' '&&e.target.closest('button,a,label')) return;\n if(k==='ArrowRight'||k==='PageDown'||(k===' '&&!e.shiftKey)){e.preventDefault();step(1)}\n else if(k==='ArrowLeft'||k==='PageUp'||(k===' '&&e.shiftKey)){e.preventDefault();step(-1)}\n else if(k==='Home'){e.preventDefault();go(0)}\n else if(k==='End'){e.preventDefault();go(n-1)}\n else if(k==='o'){e.preventDefault();openOverview(true)}\n });\n\n var stage=$('ok-stage'),sx=0,sy=0;\n if(stage){\n stage.addEventListener('touchstart',function(e){sx=e.touches[0].clientX;sy=e.touches[0].clientY},{passive:true});\n stage.addEventListener('touchend',function(e){var dx=e.changedTouches[0].clientX-sx,dy=e.changedTouches[0].clientY-sy;if(Math.abs(dx)>60&&Math.abs(dx)>Math.abs(dy)*1.5)step(dx<0?1:-1)},{passive:true});\n }\n\n // tarefas da primeira miss\u00E3o\n var tasks={};try{tasks=JSON.parse(sget('tasks')||'{}')}catch(e){}\n var boxes=[].slice.call(document.querySelectorAll('[data-task]'));\n function countTasks(){var el=document.querySelector('[data-task-count]');if(!el)return;var d=boxes.filter(function(b){return b.checked}).length;el.textContent=fill(el.dataset.template,{done:d,total:boxes.length})}\n boxes.forEach(function(b){b.checked=!!tasks[b.dataset.task];b.addEventListener('change',function(){tasks[b.dataset.task]=b.checked;sset('tasks',JSON.stringify(tasks));countTasks()})});\n countTasks();\n\n function confetti(){\n if(matchMedia('(prefers-reduced-motion: reduce)').matches) return;\n var box=document.createElement('div');box.className='confetti';box.setAttribute('aria-hidden','true');\n for(var i=0;i<120;i++){var p=document.createElement('i');p.style.left=(Math.random()*100)+'%';p.style.background='hsl('+Math.floor(Math.random()*360)+' 85% 60%)';p.style.setProperty('--dx',(Math.random()*240-120)+'px');p.style.setProperty('--r',(Math.random()*900-450)+'deg');p.style.animationDuration=(2.4+Math.random()*2.2)+'s';p.style.animationDelay=(Math.random()*.7)+'s';box.appendChild(p)}\n document.body.appendChild(box);setTimeout(function(){box.remove()},6000);\n }\n\n if(n){\n var m=/^#\\/(\\d+)$/.exec(location.hash),saved=parseInt(sget('slide')||'0',10)||0;\n if(m){go(+m[1]-1)}else{go(0);if(saved>0&&saved<n&&toast){toast.querySelector('span').textContent=fill(toast.dataset.template,{n:saved+1});toast.querySelector('[data-resume]').dataset.resume=saved;toast.classList.add('is-open');setTimeout(closeToast,9000)}}\n window.addEventListener('hashchange',function(){var h=/^#\\/(\\d+)$/.exec(location.hash);if(h)go(+h[1]-1)});\n }\n\n window.__okMermaid=function(){\n if(!window.mermaid) return;\n mermaid.initialize({startOnLoad:false,theme:isDark()?'dark':'neutral',securityLevel:'strict',fontFamily:'Plus Jakarta Sans, system-ui, sans-serif'});\n mermaid.run({querySelector:'pre.mermaid'});\n };\n})();\n";
|
|
3
|
+
export declare const CSS = "\n:root{--bg:#faf9f6;--surface:#fff;--surface-2:#f3f1ec;--text:#1b1a18;--muted:#68645c;--border:#e6e3dc;--track:#e8e5de;--shadow:0 1px 2px rgb(30 25 15/.04),0 10px 30px rgb(30 25 15/.07);--al:47%;--as:72%;--on-accent:#fff;--code-bg:#f1efe9;--term-bg:#161514;--term-text:#efece5;color-scheme:light}\n@media (prefers-color-scheme:dark){:root:not([data-theme=\"light\"]){--bg:#111110;--surface:#1a1918;--surface-2:#232220;--text:#f2f0eb;--muted:#a19d94;--border:#2c2a28;--track:#2a2826;--shadow:0 1px 2px rgb(0 0 0/.3),0 10px 30px rgb(0 0 0/.35);--al:70%;--as:78%;--on-accent:#111110;--code-bg:#262422;color-scheme:dark}}\n:root[data-theme=\"dark\"]{--bg:#111110;--surface:#1a1918;--surface-2:#232220;--text:#f2f0eb;--muted:#a19d94;--border:#2c2a28;--track:#2a2826;--shadow:0 1px 2px rgb(0 0 0/.3),0 10px 30px rgb(0 0 0/.35);--al:70%;--as:78%;--on-accent:#111110;--code-bg:#262422;color-scheme:dark}\n/* marcas sem cor (preto/cinza): destaque escuro no claro e claro no escuro */\n:root[data-mono]{--al:26%;--wl:16%}\n@media (prefers-color-scheme:dark){:root[data-mono]:not([data-theme=\"light\"]){--al:84%;--wl:24%}}\n:root[data-mono][data-theme=\"dark\"]{--al:84%;--wl:24%}\n@property --bh{syntax:\"<number>\";inherits:true;initial-value:255}\n*{box-sizing:border-box}\nhtml,body{height:100%;margin:0}\nbody{background:var(--bg);color:var(--text);font:16px/1.6 \"Plus Jakarta Sans\",system-ui,-apple-system,\"Segoe UI\",Roboto,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden}\nbody.solo{overflow:auto}\nbutton{font:inherit;color:inherit}\ncode,pre{font-family:\"JetBrains Mono\",ui-monospace,SFMono-Regular,Menlo,monospace}\ncode{font-size:.85em;background:var(--code-bg);padding:.12em .42em;border-radius:6px}\npre{margin:12px 0 0;background:var(--code-bg);border-radius:12px;padding:14px 16px;overflow-x:auto;font-size:.82rem;line-height:1.6}\npre code{background:none;padding:0;font-size:inherit}\n:focus-visible{outline:2px solid hsl(var(--h,255) calc(var(--as) * var(--k,1)) var(--al));outline-offset:2px}\n\n/* \u2500\u2500 estrutura \u2500\u2500 */\n.deck{position:fixed;inset:0;z-index:1;display:grid;grid-template-rows:auto minmax(0,1fr) auto}\n.topbar{display:flex;align-items:center;gap:18px;padding:16px 24px;z-index:3}\n.brand{display:flex;align-items:center;gap:10px;font-weight:800;letter-spacing:-.01em;white-space:nowrap;min-width:0}\n.brand-name{max-width:20ch;overflow:hidden;text-overflow:ellipsis}\n.brand-mark,.brand-logo,.solo-logo{display:inline-grid;place-items:center;flex:none;background:#fff;border-radius:12px;box-shadow:0 1px 2px rgb(0 0 0/.08),0 0 0 1px rgb(0 0 0/.05)}\n.brand-mark{height:34px;padding:5px 8px;border-radius:10px}\n.brand-mark img{height:100%;width:auto;max-width:90px;object-fit:contain}\n.segments{flex:1;display:flex;gap:5px;align-items:center;min-width:0;height:20px}\n.seg{flex:var(--w) 1 0;min-width:6px;height:6px;border:0;padding:0;border-radius:99px;background:var(--track);cursor:pointer;overflow:hidden;position:relative;transition:height .2s}\n.seg:hover,.seg.is-current{height:9px}\n.seg>span{position:absolute;inset:0 auto 0 0;width:0;border-radius:inherit;background:hsl(var(--h) calc(var(--as) * var(--k,1)) var(--al));transition:width .5s cubic-bezier(.2,.7,.2,1)}\n.icon-btn{flex:none;width:40px;height:40px;display:grid;place-items:center;border-radius:12px;border:1px solid var(--border);background:var(--surface);cursor:pointer;color:var(--muted);transition:color .2s,transform .2s}\n.icon-btn:hover{color:var(--text);transform:translateY(-1px)}\n.icon-btn svg{width:18px;height:18px}\n.stage{position:relative;overflow:hidden}\n\n/* \u2500\u2500 slides \u2500\u2500 */\n.slide{--accent:hsl(var(--h) calc(var(--as) * var(--k,1)) var(--al));--accent-soft:hsl(var(--h) calc(85% * var(--k,1)) 55% / .13);position:absolute;inset:0;display:flex;opacity:0;visibility:hidden;transform:translateX(72px) scale(.97);filter:blur(6px);transition:opacity .5s ease,transform .75s cubic-bezier(.16,1,.3,1),filter .5s ease,visibility .5s}\n.slide.is-before{transform:translateX(-72px) scale(.97)}\n.slide.is-active{opacity:1;visibility:visible;transform:none;filter:none}\n.slide-inner{position:relative;z-index:1;margin:auto;width:100%;max-width:1080px;max-height:100%;overflow-y:auto;padding:24px 40px 32px;scrollbar-width:thin;scrollbar-color:transparent transparent}\n.slide-inner:hover{scrollbar-color:var(--border) transparent}\n.slide-inner::-webkit-scrollbar{width:8px}.slide-inner::-webkit-scrollbar-thumb{background:transparent;border-radius:8px}.slide-inner:hover::-webkit-scrollbar-thumb{background:var(--border)}.slide-inner::-webkit-scrollbar-track{background:transparent}\n.kicker{display:inline-flex;align-items:center;gap:10px;margin:0 0 16px;font-size:.76rem;font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}\n.kicker .num{display:grid;place-items:center;min-width:26px;height:26px;padding:0 6px;border-radius:9px;background:var(--accent-soft);letter-spacing:0;font-size:.8rem}\n.title{font-size:clamp(2rem,1.2rem + 2.8vw,3.4rem);line-height:1.06;letter-spacing:-.035em;font-weight:800;margin:0 0 14px;max-width:20ch;text-wrap:balance}\n.title .cont{font-size:.4em;font-weight:700;letter-spacing:0;color:var(--muted);vertical-align:middle;margin-left:6px}\n.lede{font-size:clamp(1.05rem,.95rem + .5vw,1.3rem);color:var(--muted);max-width:58ch;margin:0 0 30px;text-wrap:pretty}\n.statement{font-size:clamp(1.35rem,1rem + 1.4vw,2.1rem);line-height:1.32;font-weight:600;letter-spacing:-.02em;max-width:34ch;margin:0 0 32px;text-wrap:pretty}\n.statement.small{font-size:clamp(1.15rem,.95rem + .9vw,1.6rem);max-width:40ch;margin:22px 0 0}\n.mini-label,.label{display:block;font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;color:var(--accent);margin:0 0 10px}\n\n/* entrada dos elementos: cabe\u00E7alho primeiro, depois os blocos em cascata (--i vem do JS) */\n.slide.is-active .slide-inner>.kicker{animation:kick-in .6s cubic-bezier(.16,1,.3,1) .08s both}\n.slide.is-active .slide-inner>.title,.slide.is-active .welcome>.title,.slide.is-active .finale>.title{animation:title-in .9s cubic-bezier(.16,1,.3,1) .12s both}\n.slide.is-active .slide-inner>.lede,.slide.is-active .slide-inner>.statement,.slide.is-active .slide-inner>.mini-label{animation:rise .7s cubic-bezier(.16,1,.3,1) .22s both}\n.slide.is-active .reveal>*{animation:rise .75s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(.28s + var(--i,0) * 70ms)}\n.slide.is-active .welcome>*:not(.title):not(.brand-logo),.slide.is-active .finale>*:not(.title):not(.party){animation:rise .8s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(.1s + var(--i,0) * 80ms)}\n.slide.is-active .tour-step>*{animation:rise .75s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(.15s + var(--i,0) * 120ms)}\n.slide.is-active .bignum{animation:num-in 1.1s cubic-bezier(.16,1,.3,1) .1s both}\n@keyframes rise{from{opacity:0;translate:0 22px;scale:.97}}\n@keyframes kick-in{from{opacity:0;translate:-22px 0}}\n@keyframes title-in{from{opacity:0;translate:0 28px;filter:blur(12px);letter-spacing:-.01em}}\n@keyframes num-in{from{opacity:0;scale:1.6;filter:blur(10px)}}\n\n/* fundo vivo: manchas de cor que derivam devagar e mudam de tom junto com o cap\u00EDtulo */\n.backdrop{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none;transition:--bh 1.2s ease}\n.backdrop i{position:absolute;border-radius:50%;width:74vmax;height:74vmax;right:-30vmax;top:-38vmax;background:radial-gradient(circle,hsl(var(--bh) calc(90% * var(--k,1)) 62% / .2),transparent 62%);animation:drift 24s ease-in-out infinite alternate}\n.backdrop i:nth-child(2){right:auto;top:auto;left:-26vmax;bottom:-34vmax;width:56vmax;height:56vmax;background:radial-gradient(circle,hsl(var(--h2,calc(var(--bh) + 50)) calc(90% * var(--k,1)) 62% / .13),transparent 62%);animation-duration:30s;animation-direction:alternate-reverse}\n.backdrop i:nth-child(3){right:auto;top:38%;left:34%;width:40vmax;height:40vmax;background:radial-gradient(circle,hsl(calc(var(--bh) - 40) calc(90% * var(--k,1)) 64% / .08),transparent 62%);animation-duration:36s}\n@keyframes drift{0%{transform:translate(0,0) scale(1)}50%{transform:translate(-7vmax,5vmax) scale(1.1)}100%{transform:translate(5vmax,-4vmax) scale(.94)}}\n\n/* cortina entre cap\u00EDtulos */\n.wipe{position:absolute;inset:0;z-index:6;display:grid;place-content:center;justify-items:center;gap:4px;padding:24px;text-align:center;color:#fff;pointer-events:none;visibility:hidden;clip-path:inset(0 100% 0 0);background:linear-gradient(125deg,hsl(var(--h,255) calc(78% * var(--k,1)) var(--wl,46%)),hsl(calc(var(--h,255) + 24) calc(82% * var(--k,1)) calc(var(--wl,46%) - 10%)))}\n.wipe span{font-size:clamp(4.5rem,3rem + 8vw,10rem);font-weight:800;line-height:.9;letter-spacing:-.06em;opacity:.35}\n.wipe strong{font-size:clamp(1.6rem,1.2rem + 2vw,3rem);font-weight:800;letter-spacing:-.03em}\n.wipe.run{visibility:visible;animation:wipe 1s cubic-bezier(.77,0,.18,1) both}\n.wipe.run.back{animation-name:wipe-back}\n.wipe.run>*{animation:wipe-text 1s cubic-bezier(.16,1,.3,1) both}\n.wipe.run>strong{animation-delay:.04s}\n@keyframes wipe{0%{clip-path:inset(0 100% 0 0)}40%,58%{clip-path:inset(0 0 0 0)}100%{clip-path:inset(0 0 0 100%)}}\n@keyframes wipe-back{0%{clip-path:inset(0 0 0 100%)}40%,58%{clip-path:inset(0 0 0 0)}100%{clip-path:inset(0 100% 0 0)}}\n@keyframes wipe-text{0%,22%{opacity:0;translate:0 18px;scale:.94}42%,60%{opacity:1;translate:0 0;scale:1}88%,100%{opacity:0;translate:0 -14px}}\n\n/* \u2500\u2500 blocos \u2500\u2500 */\n.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(min(100%,280px),1fr))}\n.grid-2{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(min(100%,360px),1fr))}\n.stack-list,.rules,.tasks,.modules,.quiz{display:grid;gap:14px}\n.card{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:22px;box-shadow:var(--shadow)}\n/* cart\u00F5es inclinam na dire\u00E7\u00E3o do mouse e ganham um brilho que segue o cursor */\n.card,.module,.task{transform:perspective(900px) rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg));transition:transform .35s cubic-bezier(.16,1,.3,1),box-shadow .3s,border-color .25s,opacity .25s}\n.card:hover,.module:hover,.task:hover{box-shadow:0 2px 4px rgb(0 0 0/.05),0 18px 40px hsl(var(--h,255) calc(60% * var(--k,1)) 30% / .16)}\n.card::after{content:\"\";position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:0;transition:opacity .3s;background:radial-gradient(420px circle at var(--mx,50%) var(--my,50%),hsl(var(--h,255) calc(90% * var(--k,1)) 60% / .12),transparent 45%)}\n.card:hover::after{opacity:1}\n.card h3{margin:0 0 6px;font-size:1.12rem;letter-spacing:-.015em;line-height:1.3}\n.card p{margin:0;color:var(--muted)}\n.card p.strong{color:var(--text);font-size:1.08rem;font-weight:600}\n.card-top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px;margin-bottom:6px}\n.card-top h3{margin:0}\n.badge{flex:none;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:99px;background:var(--accent-soft);color:var(--accent);white-space:nowrap}\n.badge-strong{background:var(--accent);color:var(--on-accent)}\n.big-card{padding:28px}\n.big-card p{color:var(--text);font-size:1.12rem;line-height:1.55}\n.emoji{display:block;font-size:1.9rem;line-height:1;margin-bottom:14px}\n.evidence{display:flex;flex-wrap:wrap;gap:6px;margin-top:14px}\n.ev{display:inline-flex;align-items:center;gap:6px;max-width:100%;font:500 .72rem/1.4 \"JetBrains Mono\",ui-monospace,monospace;padding:4px 9px;border-radius:8px;background:var(--surface-2);color:var(--muted);text-decoration:none;border:1px solid var(--border)}\n.ev span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\na.ev:hover{color:var(--accent);border-color:var(--accent)}\n.ev-lg{font-size:.92rem;padding:9px 14px;border-radius:12px;background:var(--surface);box-shadow:var(--shadow)}\n\n/* pessoas e jornadas */\n.actor{display:flex;gap:16px;align-items:flex-start}\n.avatar,.logo{flex:none;display:grid;place-items:center;font-weight:800;color:#fff;letter-spacing:-.02em}\n.avatar{width:50px;height:50px;border-radius:16px;background:linear-gradient(135deg,hsl(var(--ah) 72% 60%),hsl(calc(var(--ah) + 45) 72% 48%))}\n.flow{margin-bottom:28px}\n.flow h3{font-size:1.15rem;margin:0 0 14px}\n.chain{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;align-items:center;gap:10px}\n.chain li{display:flex;align-items:center;gap:10px}\n.chain li:not(:last-child)::after{content:\"\u2192\";color:var(--accent);font-weight:800;font-size:1.1rem}\n.step{display:inline-flex;align-items:center;gap:10px;padding:10px 16px 10px 10px;border-radius:14px;background:var(--surface);border:1px solid var(--border);box-shadow:var(--shadow);font-weight:600;font-size:.95rem;line-height:1.35}\n.step b{display:grid;place-items:center;flex:none;width:26px;height:26px;border-radius:8px;background:var(--accent);color:var(--on-accent);font-size:.8rem}\n\n/* vocabul\u00E1rio */\n.flips{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(min(100%,220px),1fr))}\n.flip{perspective:1000px;border:0;padding:0;background:none;cursor:pointer;text-align:left;min-height:170px}\n.flip-inner{position:relative;display:block;width:100%;height:100%;min-height:170px;transition:transform .7s cubic-bezier(.2,.7,.2,1);transform-style:preserve-3d}\n.flip.is-flipped .flip-inner{transform:rotateY(180deg)}\n.face{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:space-between;gap:10px;padding:20px;border-radius:20px;border:1px solid var(--border);box-shadow:var(--shadow);backface-visibility:hidden;-webkit-backface-visibility:hidden;overflow:auto}\n.front{background:var(--surface)}\n.front strong{font-size:1.3rem;letter-spacing:-.02em;line-height:1.2}\n.front small{color:var(--muted);font-size:.76rem;font-weight:600}\n.back{background:var(--accent);color:var(--on-accent);border-color:transparent;transform:rotateY(180deg);font-size:.95rem;line-height:1.5;justify-content:center}\n.back code{background:rgb(255 255 255/.2);color:inherit}\n.flip:hover .front{border-color:var(--accent)}\n.quiz{gap:12px}\n.quiz-q{background:var(--surface);border:1px solid var(--border);border-radius:20px;padding:16px 20px;box-shadow:var(--shadow)}\n.quiz-q .q{font-weight:700;margin:0 0 10px;font-size:1.04rem}\n.opts{display:grid;gap:8px;grid-template-columns:repeat(auto-fit,minmax(min(100%,240px),1fr))}\n.opt{text-align:left;padding:12px 14px;border-radius:12px;border:1.5px solid var(--border);background:var(--surface-2);cursor:pointer;line-height:1.4;font-size:.92rem;transition:border-color .2s,background .2s}\n.opt:hover:not(:disabled){border-color:var(--accent)}\n.opt:disabled{cursor:default}\n.opt.is-right{border-color:hsl(150 60% 42%);background:hsl(150 60% 42% / .14)}\n.opt.is-wrong{border-color:hsl(0 72% 56%);background:hsl(0 72% 56% / .12)}\n.feedback{margin:0;font-weight:700;font-size:.92rem}\n.feedback:not(:empty){margin-top:10px}\n.score{font-weight:800;color:var(--accent);font-size:1.1rem;min-height:1.6em;margin:18px 0 0}\n\n/* regras, stack, m\u00F3dulos */\n.rule{display:grid;grid-template-columns:auto 1fr;gap:22px;align-items:start}\n.rule-num{font-size:2.6rem;font-weight:800;letter-spacing:-.05em;line-height:1;color:var(--accent)}\n.tech-head{display:flex;align-items:center;gap:14px;margin-bottom:12px}\n.tech-head strong{display:block;font-size:1.06rem;line-height:1.25}\n.tech-head small{color:var(--muted);font-size:.78rem}\n.logo{width:46px;height:46px;border-radius:14px;font-size:.95rem;background:linear-gradient(135deg,hsl(var(--th) 68% 56%),hsl(calc(var(--th) + 35) 68% 44%))}\n.diagram{background:var(--surface);border:1px solid var(--border);border-radius:22px;padding:22px;box-shadow:var(--shadow);overflow:auto;max-height:58vh}\n.diagram pre.mermaid{width:100%;background:none;padding:0;margin:0;font-family:inherit;text-align:center;white-space:pre-wrap}\n.diagram svg{display:block;margin:0 auto;width:100%;height:auto;max-height:calc(58vh - 44px)}\n.module{display:grid;grid-template-columns:minmax(0,260px) 1fr;gap:18px;align-items:center;padding:16px 20px;border-radius:16px;background:var(--surface);border:1px solid var(--border)}\n.module strong{display:block;margin-bottom:4px}\n.module code{background:var(--accent-soft);color:var(--accent);font-size:.78rem}\n.module p{margin:0;color:var(--muted)}\n\n/* m\u00E3os \u00E0 obra */\n.pills{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 26px;padding:0;list-style:none}\n.pills li{padding:8px 16px;border-radius:99px;background:var(--surface);border:1px solid var(--border);font-weight:600;font-size:.92rem}\n.pills li::before{content:\"\u2713\";color:var(--accent);margin-right:8px;font-weight:800}\n.steps{list-style:none;counter-reset:s;padding:0;margin:0;display:grid;gap:10px}\n.steps li{counter-increment:s;display:flex;gap:16px;align-items:center;padding:14px 18px;background:var(--surface);border:1px solid var(--border);border-radius:16px;box-shadow:var(--shadow)}\n.steps li::before{content:counter(s);flex:none;width:32px;height:32px;border-radius:10px;display:grid;place-items:center;background:var(--accent);color:var(--on-accent);font-weight:800;font-size:.9rem}\n.terminal{background:var(--term-bg);color:var(--term-text);border-radius:20px;padding:6px 6px 10px;box-shadow:var(--shadow);border:1px solid var(--border)}\n.term-bar{display:flex;gap:7px;padding:10px 14px}\n.term-bar i{width:11px;height:11px;border-radius:50%;background:#ff5f57}.term-bar i:nth-child(2){background:#febc2e}.term-bar i:nth-child(3){background:#28c840}\n.cmd{display:grid;grid-template-columns:1fr auto;gap:14px;align-items:center;padding:12px 16px;border-top:1px solid rgb(255 255 255/.07)}\n.cmd code{background:none;color:inherit;font-size:.92rem;padding:0;word-break:break-all}\n.cmd code::before{content:\"$ \";color:hsl(var(--h) calc(75% * var(--k,1)) 66%)}\n.cmd p{margin:4px 0 0;color:rgb(255 255 255/.55);font-size:.86rem}\n.cmd p code{background:rgb(255 255 255/.08);padding:.1em .4em}.cmd p code::before{content:none}\n.copy{border:1px solid rgb(255 255 255/.16);background:transparent;color:inherit;border-radius:9px;padding:6px 12px;font-size:.78rem;font-weight:600;cursor:pointer}\n.copy:hover{background:rgb(255 255 255/.08)}\n.env code{font-size:.84rem;background:var(--accent-soft);color:var(--accent)}\n\n/* tour */\n.route{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:8px;counter-reset:r}\n.route li{counter-increment:r;display:flex;align-items:center;gap:8px}\n.route li::before{content:counter(r);display:grid;place-items:center;width:24px;height:24px;border-radius:50%;background:var(--accent);color:var(--on-accent);font-size:.75rem;font-weight:800}\n.route code{background:var(--surface);border:1px solid var(--border)}\n.tour-step{display:grid;grid-template-columns:auto 1fr;gap:36px;align-items:start;margin-top:8px}\n.bignum{font-size:clamp(5rem,3rem + 7vw,10rem);font-weight:800;line-height:.82;letter-spacing:-.06em;color:var(--accent);opacity:.22}\n.stops{display:flex;gap:6px;margin-top:32px}\n.stops i{width:28px;height:6px;border-radius:99px;background:var(--track);transition:background .3s}\n.stops i.on{background:var(--accent)}\n\n/* cuidados, decis\u00F5es, miss\u00E3o */\n.gotcha{display:grid;grid-template-columns:auto 1fr;gap:16px;border-left:4px solid var(--accent)}\n.gotcha .emoji{margin:0}\n.split{display:grid;gap:18px;grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr));margin-top:14px}\n.split p{color:var(--text)}\n.task{display:flex;gap:16px;align-items:flex-start;padding:18px 20px;border-radius:18px;background:var(--surface);border:1px solid var(--border);cursor:pointer;box-shadow:var(--shadow)}\n.task:hover{border-color:var(--accent)}\n.task input{appearance:none;-webkit-appearance:none;flex:none;width:26px;height:26px;margin:1px 0 0;border-radius:9px;border:2px solid var(--border);display:grid;place-items:center;cursor:pointer;transition:background .2s,border-color .2s}\n.task input:checked{background:var(--accent);border-color:var(--accent);animation:check .45s cubic-bezier(.2,1.6,.4,1)}\n@keyframes check{50%{scale:1.25}}\n.task input:checked::after{content:\"\u2713\";color:var(--on-accent);font-weight:800;font-size:.9rem}\n.task strong{display:block;font-size:1.05rem}\n.task-desc{display:block;color:var(--muted);margin-top:2px}\n.task:has(input:checked){opacity:.6}\n.task:has(input:checked) strong{text-decoration:line-through}\n\n/* boas-vindas e final */\n.welcome .hi{font-size:clamp(1.05rem,.95rem + .4vw,1.25rem);font-weight:700;color:var(--muted);margin:0 0 10px;display:flex;align-items:center;gap:10px}\n.wave{display:inline-block;font-size:1.6em;transform-origin:70% 70%}\n.slide.is-active .wave{animation:wave 2s ease-in-out .4s 1}\n@keyframes wave{0%,60%,100%{transform:rotate(0)}10%,30%{transform:rotate(14deg)}20%,40%{transform:rotate(-8deg)}50%{transform:rotate(10deg)}}\n.welcome .title{font-size:clamp(2.4rem,min(1.4rem + 4.6vw,9vh),5.2rem);max-width:16ch}\n.welcome .lede{margin-bottom:24px}\n.grad{background:linear-gradient(110deg,hsl(var(--h) calc(85% * var(--k,1)) var(--al)),hsl(var(--h2,calc(var(--h) + 70)) calc(85% * var(--k,1)) var(--al)),hsl(var(--h) calc(85% * var(--k,1)) var(--al)));background-size:200% auto;-webkit-background-clip:text;background-clip:text;color:transparent;animation:shimmer 7s linear infinite}\n@keyframes shimmer{to{background-position:-200% center}}\n.brand-logo{height:clamp(56px,10vh,84px);padding:10px 14px;border-radius:18px;margin-bottom:22px}\n.brand-logo img{height:100%;width:auto;max-width:260px;object-fit:contain}\n.slide.is-active .brand-logo{animation:logo-in .9s cubic-bezier(.2,1.5,.4,1) both,float 6s ease-in-out 1s infinite}\n@keyframes logo-in{from{opacity:0;scale:.6;rotate:-8deg}}\n@keyframes float{50%{translate:0 -6px}}\n.tagline{font-size:clamp(1.15rem,1rem + .7vw,1.5rem);font-weight:600;margin:0 0 14px;max-width:44ch;text-wrap:balance}\n.cta{display:inline-flex;align-items:center;gap:10px;padding:15px 24px;border-radius:16px;border:0;background:var(--accent);color:var(--on-accent);font-weight:800;font-size:1.02rem;cursor:pointer;box-shadow:0 10px 28px hsl(var(--h) calc(80% * var(--k,1)) 50% / .35);transition:transform .2s,box-shadow .2s}\n.cta:hover{transform:translateY(-2px);box-shadow:0 14px 34px hsl(var(--h) calc(80% * var(--k,1)) 50% / .42)}\n.cta .arrow{transition:transform .2s}.cta:hover .arrow{transform:translateX(3px)}\n.journey{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:8px}\n.journey button{display:inline-flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:99px;background:var(--surface);border:1px solid var(--border);cursor:pointer;font-size:.86rem;font-weight:600;transition:border-color .2s,transform .2s}\n.journey button:hover{border-color:hsl(var(--ch) calc(var(--as) * var(--k,1)) var(--al));transform:translateY(-1px)}\n.journey .n{display:grid;place-items:center;width:24px;height:24px;border-radius:50%;font-size:.72rem;font-weight:800;background:hsl(var(--ch) calc(85% * var(--k,1)) 55% / .15);color:hsl(var(--ch) calc(var(--as) * var(--k,1)) var(--al))}\n.journey-wrap{margin-top:clamp(20px,4vh,44px)}\n.meta{margin-top:20px}\n.meta{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center;margin-top:26px;color:var(--muted);font-size:.84rem}\n.meta a{color:inherit}\n.finale{text-align:center}\n.finale .title,.finale .lede{margin-left:auto;margin-right:auto}\n.party{display:block;font-size:clamp(3.5rem,2.5rem + 4vw,6rem);line-height:1;margin-bottom:16px}\n.slide.is-active .party{animation:pop .8s cubic-bezier(.2,1.6,.4,1) both}\n@keyframes pop{from{transform:scale(.3) rotate(-20deg);opacity:0}}\n.recap{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;list-style:none;padding:0;margin:0 auto 22px;max-width:760px}\n.recap li{padding:6px 14px;border-radius:99px;background:var(--surface);border:1px solid var(--border);font-size:.86rem;font-weight:600}\n.recap li::before{content:\"\u2713 \";color:hsl(var(--ch) calc(var(--as) * var(--k,1)) var(--al));font-weight:800}\n.task-count{color:var(--muted);font-weight:600;margin:0 0 26px}\n.actions{display:flex;gap:10px;flex-wrap:wrap;justify-content:center}\n.ghost{padding:15px 22px;border-radius:16px;border:1px solid var(--border);background:var(--surface);font-weight:700;cursor:pointer}\n.ghost:hover{border-color:var(--accent)}\n\n/* \u2500\u2500 controles \u2500\u2500 */\n.controls{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:12px;padding:12px 24px 20px;z-index:3}\n.controls [data-prev]{justify-self:start}\n.controls [data-next]{justify-self:end}\n.nav-btn{display:inline-flex;align-items:center;gap:8px;padding:12px 20px;border-radius:14px;border:1px solid var(--border);background:var(--surface);font-weight:700;cursor:pointer;box-shadow:var(--shadow);transition:transform .2s,opacity .2s}\n.nav-btn:hover:not(:disabled){transform:translateY(-1px)}\n.nav-btn.primary{background:var(--brand-c,var(--text));color:var(--brand-on,var(--bg));border-color:var(--brand-c,var(--text))}\n.nav-btn:disabled{opacity:0;visibility:hidden}\n.where{display:flex;flex-direction:column;align-items:center;text-align:center;font-size:.8rem;color:var(--muted);line-height:1.4}\n.where strong{color:var(--text);font-size:.9rem}\n.hint.is-hidden{display:none}\n\n/* \u00EDndice */\n.overview{position:fixed;inset:0;z-index:20;background:color-mix(in srgb,var(--bg) 90%,transparent);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);overflow-y:auto;padding:28px 24px 56px;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .25s,visibility .25s}\n.overview.is-open{opacity:1;visibility:visible;pointer-events:auto}\n.overview-inner{max-width:1040px;margin:0 auto}\n.overview-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}\n.overview-head h2{margin:0;font-size:1.6rem;letter-spacing:-.02em}\n.ov-grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(min(100%,290px),1fr))}\n.ov-chapter{background:var(--surface);border:1px solid var(--border);border-radius:18px;padding:16px;box-shadow:var(--shadow)}\n.ov-chapter h3{display:flex;gap:10px;align-items:center;margin:0 0 8px;font-size:1rem}\n.ov-chapter h3 .n{display:grid;place-items:center;width:26px;height:26px;border-radius:9px;font-size:.78rem;background:hsl(var(--ch) calc(85% * var(--k,1)) 55% / .15);color:hsl(var(--ch) calc(var(--as) * var(--k,1)) var(--al))}\n.ov-chapter button{display:block;width:100%;text-align:left;padding:7px 10px;border-radius:10px;border:0;background:none;cursor:pointer;color:var(--muted);font-size:.9rem;line-height:1.35}\n.ov-chapter button:hover,.ov-chapter button.is-current{background:var(--surface-2);color:var(--text)}\n.ov-chapter button.is-current{font-weight:700}\n\n/* aviso de retomada */\n.toast{position:fixed;left:50%;bottom:96px;z-index:15;display:flex;align-items:center;gap:12px;flex-wrap:wrap;justify-content:center;max-width:calc(100% - 32px);padding:12px 14px 12px 18px;border-radius:16px;background:var(--text);color:var(--bg);box-shadow:0 12px 40px rgb(0 0 0/.25);font-weight:600;font-size:.92rem;transform:translate(-50%,20px);opacity:0;visibility:hidden;transition:.35s cubic-bezier(.2,.7,.2,1)}\n.toast.is-open{transform:translate(-50%,0);opacity:1;visibility:visible}\n.toast button{border:0;border-radius:10px;padding:8px 12px;font-weight:700;cursor:pointer;background:rgb(127 127 127/.25);color:inherit}\n.toast button.yes{background:var(--bg);color:var(--text)}\n\n/* confete */\n.confetti{position:fixed;inset:0;pointer-events:none;overflow:hidden;z-index:30}\n.confetti i{position:absolute;top:-16px;width:9px;height:15px;border-radius:2px;animation:fall linear forwards}\n@keyframes fall{to{transform:translate3d(var(--dx),110vh,0) rotate(var(--r))}}\n\n/* p\u00E1ginas de aviso */\n.solo-wrap{position:relative;z-index:1;min-height:100%;display:grid;place-items:center;padding:32px 16px;--accent:hsl(var(--h) calc(var(--as) * var(--k,1)) var(--al));--accent-soft:hsl(var(--h) calc(85% * var(--k,1)) 55% / .13)}\n.solo-card{max-width:680px;width:100%;background:color-mix(in srgb,var(--surface) 88%,transparent);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);border:1px solid var(--border);border-radius:28px;padding:36px;box-shadow:var(--shadow)}\n.solo-card>*{animation:rise .8s cubic-bezier(.16,1,.3,1) both;animation-delay:calc(var(--i,0) * 80ms)}\n.solo-logo{display:grid;width:fit-content;height:56px;padding:8px 12px;border-radius:16px;margin-bottom:18px}\n.solo-logo img{height:100%;width:auto;max-width:200px;object-fit:contain}\n.solo-steps{list-style:none;padding:0;margin:0 0 18px;display:grid;gap:10px}\n.solo-steps li{display:flex;gap:12px;align-items:center;font-weight:600}\n.solo-steps b{display:grid;place-items:center;flex:none;width:28px;height:28px;border-radius:9px;background:var(--accent-soft);color:var(--accent);font-size:.82rem}\n.prompt-box{position:relative;border-radius:18px;padding:3px;background:linear-gradient(120deg,var(--accent),hsl(var(--h2,calc(var(--h) + 60)) calc(85% * var(--k,1)) 60%),var(--accent));background-size:200% auto;animation:shimmer 6s linear infinite}\n.prompt-text{margin:0;border-radius:15px;background:var(--surface);padding:18px 18px 70px;white-space:pre-wrap;font-size:.86rem;line-height:1.65;user-select:all;-webkit-user-select:all;cursor:text}\n.copy-cta{position:absolute;right:14px;bottom:14px;padding:11px 18px;font-size:.92rem;border-radius:12px}\n.solo-card .waiting{display:flex;align-items:center;gap:10px;margin:20px 0 0;font-weight:600;color:var(--muted)}\n.pulse{position:relative;width:10px;height:10px;border-radius:50%;background:var(--accent)}\n.pulse::after{content:\"\";position:absolute;inset:0;border-radius:50%;background:var(--accent);animation:ping 1.6s cubic-bezier(0,0,.2,1) infinite}\n@keyframes ping{75%,100%{transform:scale(2.6);opacity:0}}\n.solo-card .progress .mini-label{margin-bottom:10px}\n.progress{margin-top:22px;padding-top:20px;border-top:1px solid var(--border)}\n.progress-bar{height:6px;border-radius:99px;background:var(--track);overflow:hidden;margin-bottom:14px}\n.progress-bar span{display:block;height:100%;border-radius:inherit;background:var(--accent);transition:width .8s cubic-bezier(.16,1,.3,1)}\n.progress-list{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:6px}\n.progress-list li{padding:5px 12px;border-radius:99px;border:1px solid var(--border);font-size:.8rem;font-weight:600;color:var(--muted);transition:background .4s,color .4s,border-color .4s}\n.progress-list li.is-done{background:var(--accent-soft);border-color:transparent;color:var(--accent)}\n.progress-list li.is-done::before{content:\"\u2713 \"}\n.progress-list li.pop{animation:check .5s cubic-bezier(.2,1.6,.4,1)}\n.manual{margin:18px 0 0!important;font-size:.88rem}\n.error-text{white-space:pre-wrap}\n.solo-card h1{font-size:clamp(1.6rem,1.2rem + 1.4vw,2.2rem);letter-spacing:-.03em;line-height:1.15;margin:0 0 12px}\n.solo-card p{color:var(--muted);margin:0 0 20px}\n.prompt{display:flex;gap:10px;align-items:flex-start}\n.prompt pre{flex:1;white-space:pre-wrap;margin:0}\n.prompt .copy{color:var(--text);border-color:var(--border)}\n\n/* \u2500\u2500 telas pequenas \u2500\u2500 */\n@media (max-width:760px){\n .topbar{padding:12px 16px;gap:10px}\n .brand-name{display:none}\n .slide-inner{padding:12px 16px 28px}\n .controls{padding:10px 16px 14px;gap:8px}\n .nav-btn{padding:11px 14px}\n .nav-btn .txt,.hint{display:none}\n .rule,.tour-step{grid-template-columns:1fr;gap:6px}\n .module{grid-template-columns:1fr;gap:6px}\n .bignum{font-size:4rem}\n .journey-wrap{margin-top:32px}\n .solo-card{padding:24px}\n .prompt-text{padding-bottom:64px}\n}\n@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important}}\n";
|
|
4
|
+
export declare const JS = "\n(function(){\n var root=document.documentElement;\n var KEY='onboarding-kit:'+location.pathname+':';\n function sget(k){try{return localStorage.getItem(KEY+k)}catch(e){return null}}\n function sset(k,v){try{localStorage.setItem(KEY+k,v)}catch(e){}}\n function fill(t,o){return t.replace(/\\{(\\w+)\\}/g,function(_,k){return o[k]})}\n\n var theme=sget('theme'); if(theme) root.setAttribute('data-theme',theme);\n function isDark(){var t=root.getAttribute('data-theme');return t?t==='dark':matchMedia('(prefers-color-scheme: dark)').matches}\n\n var slides=[].slice.call(document.querySelectorAll('.slide'));\n var n=slides.length,cur=-1,celebrated=false;\n var segs=[].slice.call(document.querySelectorAll('.seg'));\n var $=function(id){return document.getElementById(id)};\n var prevBtn=document.querySelector('[data-prev]'),nextBtn=document.querySelector('[data-next]');\n var overview=$('ok-overview'),toast=$('ok-toast'),hint=$('ok-hint'),wipe=$('ok-wipe'),backdrop=$('ok-backdrop'),timer=0;\n function reduced(){return matchMedia('(prefers-reduced-motion: reduce)').matches}\n\n // \u00EDndice de cada filho, para a entrada em cascata\n [].forEach.call(document.querySelectorAll('.reveal,.welcome,.finale,.tour-step,.solo-card'),function(box){[].forEach.call(box.children,function(c,j){c.style.setProperty('--i',j)})});\n\n function show(i){\n slides.forEach(function(s,j){var on=j===i;s.classList.toggle('is-active',on);s.classList.toggle('is-before',j<i);s.setAttribute('aria-hidden',on?'false':'true');if('inert' in s)s.inert=!on});\n var s=slides[i],inner=s.querySelector('.slide-inner'); if(inner) inner.scrollTop=0;\n if(backdrop) backdrop.style.setProperty('--bh',s.style.getPropertyValue('--h'));\n if(s.dataset.kind==='finale'&&!celebrated){celebrated=true;confetti()}\n }\n // cortina com o n\u00FAmero e o nome do cap\u00EDtulo; o slide troca por baixo quando ela cobre a tela\n function runWipe(s,back){\n wipe.style.setProperty('--h',s.style.getPropertyValue('--h'));\n wipe.firstElementChild.textContent=s.dataset.chapterNum||'';\n wipe.lastElementChild.textContent=s.dataset.chapterName||'';\n wipe.classList.remove('run','back'); void wipe.offsetWidth;\n wipe.classList.add('run'); if(back) wipe.classList.add('back');\n }\n if(wipe) wipe.addEventListener('animationend',function(e){if(e.target===wipe)wipe.classList.remove('run','back')});\n\n function go(i){\n if(!n) return;\n i=Math.max(0,Math.min(n-1,i|0)); if(i===cur) return;\n var prev=cur,s=slides[i];\n if(timer){clearTimeout(timer);timer=0}\n cur=i;\n if(prev>=0&&wipe&&!reduced()&&slides[prev].dataset.chapter!==s.dataset.chapter){\n runWipe(s,i<prev);\n timer=setTimeout(function(){timer=0;show(i)},400);\n }else show(i);\n segs.forEach(function(g){var st=+g.dataset.start,c=+g.dataset.count,p=i<st?0:i>=st+c?1:(i-st+1)/c;g.firstElementChild.style.width=(p*100)+'%';g.classList.toggle('is-current',i>=st&&i<st+c)});\n $('ok-chapter').textContent=s.dataset.chapterName;\n $('ok-count').textContent=(i+1)+' / '+n;\n prevBtn.disabled=i===0; nextBtn.disabled=i===n-1;\n [].forEach.call(document.querySelectorAll('.ov-chapter [data-go]'),function(b){b.classList.toggle('is-current',+b.dataset.go===i)});\n try{history.replaceState(null,'','#/'+(i+1))}catch(e){}\n sset('slide',String(i));\n }\n function step(d){go(cur+d);if(hint)hint.classList.add('is-hidden');closeToast()}\n function openOverview(open){if(!overview)return;overview.classList.toggle('is-open',open);overview.setAttribute('aria-hidden',open?'false':'true');if(open){var c=overview.querySelector('.is-current')||overview.querySelector('button');c&&c.focus()}}\n function closeToast(){if(toast)toast.classList.remove('is-open')}\n\n document.addEventListener('click',function(e){\n var el=e.target.closest('button,[data-go]'); if(!el) return;\n if(el.hasAttribute('data-next')) return step(1);\n if(el.hasAttribute('data-prev')) return step(-1);\n if(el.hasAttribute('data-go')){openOverview(false);closeToast();return go(+el.dataset.go)}\n if(el.hasAttribute('data-overview')) return openOverview(true);\n if(el.hasAttribute('data-close')) return openOverview(false);\n if(el.hasAttribute('data-theme-toggle')){var nt=isDark()?'light':'dark';root.setAttribute('data-theme',nt);sset('theme',nt);return}\n if(el.hasAttribute('data-resume')){closeToast();return go(+el.dataset.resume)}\n if(el.hasAttribute('data-dismiss')) return closeToast();\n if(el.hasAttribute('data-copy')){\n var txt=el.dataset.copy,orig=el.textContent;\n var done=function(){el.textContent=el.dataset.done||'\u2713';el.classList.add('is-copied');setTimeout(function(){el.textContent=orig;el.classList.remove('is-copied')},1800)};\n // fora de HTTPS/localhost n\u00E3o h\u00E1 navigator.clipboard: cai no execCommand\n var fallback=function(){var ta=document.createElement('textarea');ta.value=txt;ta.style.position='fixed';ta.style.opacity='0';document.body.appendChild(ta);ta.select();try{document.execCommand('copy');done()}catch(e){}ta.remove()};\n if(navigator.clipboard&&window.isSecureContext) navigator.clipboard.writeText(txt).then(done,fallback); else fallback();\n return;\n }\n if(el.classList.contains('flip')){var f=el.classList.toggle('is-flipped');el.setAttribute('aria-pressed',f?'true':'false');return}\n if(el.classList.contains('opt')){\n var q=el.closest('[data-quiz]'); if(!q||q.dataset.done) return;\n var right=el.dataset.correct==='1'; q.dataset.done=right?'right':'wrong';\n [].forEach.call(q.querySelectorAll('.opt'),function(o){o.disabled=true;if(o.dataset.correct==='1')o.classList.add('is-right')});\n if(!right) el.classList.add('is-wrong');\n q.querySelector('.feedback').textContent=right?q.dataset.right:q.dataset.wrong;\n var slide=q.closest('.slide'),all=slide.querySelectorAll('[data-quiz]'),done=slide.querySelectorAll('[data-quiz][data-done]'),ok=slide.querySelectorAll('[data-quiz][data-done=\"right\"]');\n var score=slide.querySelector('[data-quiz-score]');\n if(score&&done.length===all.length) score.textContent=fill(score.dataset.template,{right:ok.length,total:all.length});\n }\n });\n\n document.addEventListener('keydown',function(e){\n if(e.metaKey||e.ctrlKey||e.altKey||e.target.closest('input,textarea,select')) return;\n var k=e.key;\n if(overview&&overview.classList.contains('is-open')){if(k==='Escape'||k==='o'){e.preventDefault();openOverview(false)}return}\n if(k===' '&&e.target.closest('button,a,label')) return;\n if(k==='ArrowRight'||k==='PageDown'||(k===' '&&!e.shiftKey)){e.preventDefault();step(1)}\n else if(k==='ArrowLeft'||k==='PageUp'||(k===' '&&e.shiftKey)){e.preventDefault();step(-1)}\n else if(k==='Home'){e.preventDefault();go(0)}\n else if(k==='End'){e.preventDefault();go(n-1)}\n else if(k==='o'){e.preventDefault();openOverview(true)}\n });\n\n var stage=$('ok-stage'),sx=0,sy=0;\n if(stage){\n stage.addEventListener('touchstart',function(e){sx=e.touches[0].clientX;sy=e.touches[0].clientY},{passive:true});\n stage.addEventListener('touchend',function(e){var dx=e.changedTouches[0].clientX-sx,dy=e.changedTouches[0].clientY-sy;if(Math.abs(dx)>60&&Math.abs(dx)>Math.abs(dy)*1.5)step(dx<0?1:-1)},{passive:true});\n }\n\n // tarefas da primeira miss\u00E3o\n var tasks={};try{tasks=JSON.parse(sget('tasks')||'{}')}catch(e){}\n var boxes=[].slice.call(document.querySelectorAll('[data-task]'));\n function countTasks(){var el=document.querySelector('[data-task-count]');if(!el)return;var d=boxes.filter(function(b){return b.checked}).length;el.textContent=fill(el.dataset.template,{done:d,total:boxes.length})}\n boxes.forEach(function(b){b.checked=!!tasks[b.dataset.task];b.addEventListener('change',function(){tasks[b.dataset.task]=b.checked;sset('tasks',JSON.stringify(tasks));countTasks()})});\n countTasks();\n\n // cart\u00F5es inclinam na dire\u00E7\u00E3o do mouse\n var tilted=null;\n document.addEventListener('pointermove',function(e){\n if(e.pointerType!=='mouse'||reduced()) return;\n var el=e.target.closest&&e.target.closest('.slide .card,.slide .module,.slide .task');\n if(tilted&&tilted!==el){tilted.style.removeProperty('--rx');tilted.style.removeProperty('--ry')}\n tilted=el; if(!el) return;\n var r=el.getBoundingClientRect(),x=(e.clientX-r.left)/r.width,y=(e.clientY-r.top)/r.height;\n el.style.setProperty('--rx',((.5-y)*5).toFixed(2)+'deg');el.style.setProperty('--ry',((x-.5)*6).toFixed(2)+'deg');\n el.style.setProperty('--mx',(x*100).toFixed(1)+'%');el.style.setProperty('--my',(y*100).toFixed(1)+'%');\n },{passive:true});\n\n // p\u00E1ginas de espera: consultam a rota e recarregam quando o onboarding muda de estado\n var state=document.body.dataset.okState;\n if(state){\n var poll=function(){\n fetch(location.href,{cache:'no-store'}).then(function(r){return r.text()}).then(function(html){\n var m=/data-ok-state=\"(w+)\"/.exec(html);\n if(!m||m[1]!==state) return location.reload();\n var box=$('ok-progress'); if(!box) return;\n var next=new DOMParser().parseFromString(html,'text/html').getElementById('ok-progress');\n if(!next||next.innerHTML===box.innerHTML) return;\n var before={};[].forEach.call(box.querySelectorAll('.is-done'),function(li){before[li.dataset.key]=1});\n box.innerHTML=next.innerHTML;\n [].forEach.call(box.querySelectorAll('.is-done'),function(li){if(!before[li.dataset.key])li.classList.add('pop')});\n }).catch(function(){}).then(function(){setTimeout(poll,2500)});\n };\n setTimeout(poll,2500);\n }\n\n function confetti(){\n if(reduced()) return;\n var pal=(root.dataset.palette||'').split(' ').filter(Boolean);\n var box=document.createElement('div');box.className='confetti';box.setAttribute('aria-hidden','true');\n for(var i=0;i<140;i++){var p=document.createElement('i');p.style.left=(Math.random()*100)+'%';p.style.background=pal.length&&Math.random()<.75?pal[i%pal.length]:'hsl('+Math.floor(Math.random()*360)+' 85% 60%)';p.style.setProperty('--dx',(Math.random()*240-120)+'px');p.style.setProperty('--r',(Math.random()*900-450)+'deg');p.style.animationDuration=(2.4+Math.random()*2.2)+'s';p.style.animationDelay=(Math.random()*.7)+'s';box.appendChild(p)}\n document.body.appendChild(box);setTimeout(function(){box.remove()},6000);\n }\n\n if(n){\n var m=/^#\\/(\\d+)$/.exec(location.hash),saved=parseInt(sget('slide')||'0',10)||0;\n if(m){go(+m[1]-1)}else{go(0);if(saved>0&&saved<n&&toast){toast.querySelector('span').textContent=fill(toast.dataset.template,{n:saved+1});toast.querySelector('[data-resume]').dataset.resume=saved;toast.classList.add('is-open');setTimeout(closeToast,9000)}}\n window.addEventListener('hashchange',function(){var h=/^#\\/(\\d+)$/.exec(location.hash);if(h)go(+h[1]-1)});\n }\n\n window.__okMermaid=function(){\n if(!window.mermaid) return;\n var brand=(root.dataset.palette||'').split(' ')[0],dark=isDark();\n // mistura a cor da marca com o fundo para pintar os n\u00F3s sem perder a leitura do texto\n function mix(hex,base,a){var c=function(h,i){return parseInt(h.substr(1+i*2,2),16)};var o='#';for(var i=0;i<3;i++)o+=('0'+Math.round(c(hex,i)*a+c(base,i)*(1-a)).toString(16)).slice(-2);return o}\n var vars=brand?{primaryColor:mix(brand,dark?'#1a1918':'#ffffff',.16),primaryBorderColor:brand,lineColor:brand,primaryTextColor:dark?'#f2f0eb':'#1b1a18',secondaryColor:mix(brand,dark?'#1a1918':'#ffffff',.08),tertiaryColor:dark?'#232220':'#f3f1ec',darkMode:dark,fontFamily:'Plus Jakarta Sans, system-ui, sans-serif'}:undefined;\n mermaid.initialize({startOnLoad:false,theme:brand?'base':dark?'dark':'neutral',themeVariables:vars,securityLevel:'strict',fontFamily:'Plus Jakarta Sans, system-ui, sans-serif'});\n mermaid.run({querySelector:'pre.mermaid'});\n };\n})();\n";
|