onboarding-kit 0.0.0-stage → 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.
@@ -0,0 +1,272 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.detectFramework = detectFramework;
5
+ exports.patchNestAppModule = patchNestAppModule;
6
+ const node_child_process_1 = require("node:child_process");
7
+ const node_fs_1 = require("node:fs");
8
+ const node_http_1 = require("node:http");
9
+ const node_path_1 = require("node:path");
10
+ const node_1 = require("../adapters/node");
11
+ const load_1 = require("../load");
12
+ const template_1 = require("../template");
13
+ const validate_1 = require("../validate");
14
+ const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
15
+ const paint = (open, close) => (s) => (useColor ? `\x1b[${open}m${s}\x1b[${close}m` : s);
16
+ const c = {
17
+ bold: paint(1, 22),
18
+ dim: paint(2, 22),
19
+ green: paint(32, 39),
20
+ yellow: paint(33, 39),
21
+ red: paint(31, 39),
22
+ cyan: paint(36, 39),
23
+ };
24
+ const HELP = `
25
+ ${c.bold("onboarding-kit")} — onboarding do projeto gerado pela sua IA local
26
+
27
+ ${c.bold("Uso")}
28
+ npx onboarding-kit init Cria o onboarding.json em branco e a rota /onboarding
29
+ npx onboarding-kit prompt Mostra o texto para enviar à sua IA
30
+ npx onboarding-kit validate Confere o JSON preenchido (campos, evidências, segredos)
31
+ npx onboarding-kit serve Abre a apresentação em http://localhost:4321
32
+
33
+ ${c.bold("Opções")}
34
+ --file <caminho> Arquivo de onboarding (padrão: onboarding.json)
35
+ --framework <next|nest|node> Força o framework em vez de detectar (init)
36
+ --lang <idioma> Idioma do conteúdo gerado (init, padrão: pt-BR)
37
+ --no-route Não cria/edita a rota no projeto (init)
38
+ --force Sobrescreve o onboarding.json existente (init)
39
+ --port <porta> Porta do serve (padrão: 4321)
40
+ `;
41
+ function parseArgs(argv) {
42
+ const flags = {};
43
+ let command;
44
+ for (let i = 0; i < argv.length; i++) {
45
+ const arg = argv[i];
46
+ if (arg.startsWith("--")) {
47
+ const [key, inline] = arg.slice(2).split("=", 2);
48
+ if (inline !== undefined)
49
+ flags[key] = inline;
50
+ else if (argv[i + 1] && !argv[i + 1].startsWith("--"))
51
+ flags[key] = argv[++i];
52
+ else
53
+ flags[key] = true;
54
+ }
55
+ else if (arg === "-h") {
56
+ flags.help = true;
57
+ }
58
+ else if (!command) {
59
+ command = arg;
60
+ }
61
+ }
62
+ return { command, flags };
63
+ }
64
+ function readPackageJson(root) {
65
+ const path = (0, node_path_1.join)(root, "package.json");
66
+ if (!(0, node_fs_1.existsSync)(path))
67
+ return undefined;
68
+ try {
69
+ return JSON.parse((0, node_fs_1.readFileSync)(path, "utf8"));
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ function detectFramework(pkg) {
76
+ const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) };
77
+ if (deps.next)
78
+ return "next";
79
+ if (deps["@nestjs/core"])
80
+ return "nest";
81
+ return "node";
82
+ }
83
+ function gitHead(cwd) {
84
+ try {
85
+ return (0, node_child_process_1.execFileSync)("git", ["rev-parse", "HEAD"], { cwd, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
86
+ }
87
+ catch {
88
+ return undefined;
89
+ }
90
+ }
91
+ const NEXT_ROUTE = `import { createOnboardingRoute } from "onboarding-kit/next";
92
+
93
+ // Criado pelo onboarding-kit. Mostra a apresentação do projeto em /onboarding.
94
+ // Fica desligada em produção; para ligar: createOnboardingRoute({ enabled: true }).
95
+ export const runtime = "nodejs";
96
+ export const dynamic = "force-dynamic";
97
+ export const GET = createOnboardingRoute();
98
+ `;
99
+ const NEXT_PAGES_SNIPPET = `// pages/api/onboarding.ts
100
+ import { createOnboardingApiHandler } from "onboarding-kit/next";
101
+ export default createOnboardingApiHandler();
102
+
103
+ // next.config: para servir em /onboarding
104
+ async rewrites() { return [{ source: "/onboarding", destination: "/api/onboarding" }]; }`;
105
+ const NEST_SNIPPET = `// src/app.module.ts
106
+ import { OnboardingModule } from "onboarding-kit/nest";
107
+
108
+ @Module({
109
+ imports: [OnboardingModule.register(), /* ...seus módulos */],
110
+ })`;
111
+ const NODE_SNIPPET = `// Express
112
+ import { createOnboardingHandler } from "onboarding-kit/node";
113
+ app.get("/onboarding", createOnboardingHandler());
114
+
115
+ // http nativo
116
+ const onboarding = createOnboardingHandler();
117
+ if (req.url === "/onboarding") return onboarding(req, res);`;
118
+ function setupNext(root) {
119
+ const appDir = ["src/app", "app"].find((dir) => (0, node_fs_1.existsSync)((0, node_path_1.join)(root, dir)));
120
+ if (!appDir) {
121
+ return [`${c.yellow("!")} Não encontrei a pasta app/ (App Router). Para o Pages Router, adicione:`, "", c.dim(NEXT_PAGES_SNIPPET)];
122
+ }
123
+ const ext = (0, node_fs_1.existsSync)((0, node_path_1.join)(root, "tsconfig.json")) ? "ts" : "js";
124
+ const routeFile = (0, node_path_1.join)(root, appDir, "onboarding", `route.${ext}`);
125
+ const rel = (0, node_path_1.relative)(root, routeFile);
126
+ if ((0, node_fs_1.existsSync)(routeFile))
127
+ return [`${c.dim("•")} ${rel} já existe, mantive como está`];
128
+ (0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(routeFile), { recursive: true });
129
+ (0, node_fs_1.writeFileSync)(routeFile, NEXT_ROUTE);
130
+ return [`${c.green("✓")} Criei ${c.bold(rel)} (rota /onboarding)`];
131
+ }
132
+ /** Adiciona o OnboardingModule ao app.module.ts quando dá para fazer isso com segurança. */
133
+ function patchNestAppModule(source) {
134
+ if (source.includes("OnboardingModule"))
135
+ return source;
136
+ const matches = source.match(/imports\s*:\s*\[/g);
137
+ if (!matches || matches.length !== 1)
138
+ return undefined;
139
+ const withImport = source.replace(/imports\s*:\s*\[(\s*\])?/, (m, empty) => empty ? m.replace(/\[\s*\]$/, "[OnboardingModule.register()]") : `${m}OnboardingModule.register(), `);
140
+ return `import { OnboardingModule } from "onboarding-kit/nest";\n${withImport}`;
141
+ }
142
+ function setupNest(root) {
143
+ const file = (0, node_path_1.join)(root, "src", "app.module.ts");
144
+ if ((0, node_fs_1.existsSync)(file)) {
145
+ const source = (0, node_fs_1.readFileSync)(file, "utf8");
146
+ const patched = patchNestAppModule(source);
147
+ if (patched === source)
148
+ return [`${c.dim("•")} src/app.module.ts já importa o OnboardingModule`];
149
+ if (patched) {
150
+ (0, node_fs_1.writeFileSync)(file, patched);
151
+ return [`${c.green("✓")} Adicionei ${c.bold("OnboardingModule.register()")} em src/app.module.ts (rota /onboarding)`];
152
+ }
153
+ }
154
+ return [`${c.yellow("!")} Não consegui editar o app.module.ts sozinho. Adicione:`, "", c.dim(NEST_SNIPPET)];
155
+ }
156
+ function cmdInit(flags) {
157
+ const root = process.cwd();
158
+ const pkg = readPackageJson(root);
159
+ if (!pkg) {
160
+ console.error(c.red("✗ Não encontrei package.json. Rode o comando na raiz do projeto."));
161
+ return 1;
162
+ }
163
+ const forced = typeof flags.framework === "string" ? flags.framework : undefined;
164
+ if (forced && !["next", "nest", "node"].includes(forced)) {
165
+ console.error(c.red(`✗ Framework inválido: ${forced}. Use next, nest ou node.`));
166
+ return 1;
167
+ }
168
+ const framework = forced ?? detectFramework(pkg);
169
+ const language = typeof flags.lang === "string" ? flags.lang : "pt-BR";
170
+ const file = (0, load_1.resolveFile)(typeof flags.file === "string" ? flags.file : undefined);
171
+ const relFile = (0, node_path_1.relative)(root, file);
172
+ const lines = [`Framework: ${c.bold(framework)}${forced ? "" : c.dim(" (detectado)")}`];
173
+ if ((0, node_fs_1.existsSync)(file) && !flags.force) {
174
+ lines.push(`${c.dim("•")} ${relFile} já existe, mantive como está ${c.dim("(use --force para recriar)")}`);
175
+ }
176
+ else {
177
+ (0, node_fs_1.writeFileSync)(file, JSON.stringify((0, template_1.createTemplate)({ framework, language }), null, 2) + "\n");
178
+ lines.push(`${c.green("✓")} Criei ${c.bold(relFile)} com os campos em branco e as instruções para a IA`);
179
+ }
180
+ if (flags.route !== false && !flags["no-route"]) {
181
+ if (framework === "next")
182
+ lines.push(...setupNext(root));
183
+ else if (framework === "nest")
184
+ lines.push(...setupNest(root));
185
+ else
186
+ lines.push(`${c.dim("•")} Para servir em /onboarding no seu servidor:`, "", c.dim(NODE_SNIPPET));
187
+ }
188
+ const prompt = (0, template_1.aiPrompt)(relFile);
189
+ console.log(`
190
+ ${lines.join("\n")}
191
+
192
+ ${c.bold("Próximo passo:")} envie para a IA que você usa neste projeto (Claude Code, Cursor, Copilot…):
193
+
194
+ ${c.cyan(prompt)}
195
+
196
+ Depois rode ${c.bold("npx onboarding-kit validate")} e acesse ${c.bold("/onboarding")} no app em dev (ou ${c.bold("npx onboarding-kit serve")}).
197
+ `);
198
+ return 0;
199
+ }
200
+ async function cmdValidate(flags) {
201
+ const result = await (0, load_1.loadOnboarding)(typeof flags.file === "string" ? flags.file : undefined);
202
+ if (!result.ok) {
203
+ console.error(c.red(`✗ ${result.message}`));
204
+ if (result.reason === "missing")
205
+ console.error(` Rode ${c.bold("npx onboarding-kit init")} primeiro.`);
206
+ return 1;
207
+ }
208
+ const root = (0, node_path_1.dirname)(result.file);
209
+ const issues = (0, validate_1.validateOnboarding)(result.data, { root, headCommit: gitHead(root) });
210
+ const errors = issues.filter((i) => i.level === "error");
211
+ const warnings = issues.filter((i) => i.level === "warning");
212
+ for (const issue of [...errors, ...warnings]) {
213
+ const mark = issue.level === "error" ? c.red("✗") : c.yellow("!");
214
+ console.log(`${mark} ${c.bold(issue.path || "(raiz)")} ${issue.message}`);
215
+ }
216
+ if (errors.length) {
217
+ console.log(`\n${c.red(`${errors.length} erro(s)`)}, ${warnings.length} aviso(s). Peça à IA para corrigir e rode de novo.`);
218
+ return 1;
219
+ }
220
+ console.log(`${issues.length ? "\n" : ""}${c.green("✓")} ${(0, node_path_1.relative)(process.cwd(), result.file)} válido${warnings.length ? ` com ${warnings.length} aviso(s)` : ""}.`);
221
+ return 0;
222
+ }
223
+ function cmdServe(flags) {
224
+ const port = Number(flags.port ?? 4321);
225
+ const handler = (0, node_1.createOnboardingHandler)({ file: typeof flags.file === "string" ? flags.file : undefined, enabled: true });
226
+ const server = (0, node_http_1.createServer)((req, res) => {
227
+ const path = (req.url ?? "/").split("?")[0];
228
+ if (path === "/" || path === "/onboarding")
229
+ return void handler(req, res);
230
+ res.writeHead(302, { Location: "/" });
231
+ res.end();
232
+ });
233
+ return new Promise((resolvePromise) => {
234
+ server.on("error", (err) => {
235
+ console.error(c.red(`✗ ${err.code === "EADDRINUSE" ? `A porta ${port} está em uso. Use --port.` : err.message}`));
236
+ resolvePromise(1);
237
+ });
238
+ server.listen(port, "127.0.0.1", () => {
239
+ console.log(`${c.green("✓")} Onboarding em ${c.bold(`http://localhost:${port}`)} ${c.dim("(Ctrl+C para sair)")}`);
240
+ });
241
+ });
242
+ }
243
+ async function main() {
244
+ const { command, flags } = parseArgs(process.argv.slice(2));
245
+ if (flags["no-route"])
246
+ flags.route = false;
247
+ if (!command || flags.help || command === "help") {
248
+ console.log(HELP);
249
+ return 0;
250
+ }
251
+ switch (command) {
252
+ case "init":
253
+ return cmdInit(flags);
254
+ case "validate":
255
+ return cmdValidate(flags);
256
+ case "serve":
257
+ return cmdServe(flags);
258
+ case "prompt":
259
+ console.log((0, template_1.aiPrompt)(typeof flags.file === "string" ? flags.file : load_1.DEFAULT_FILE));
260
+ return 0;
261
+ default:
262
+ console.error(c.red(`✗ Comando desconhecido: ${command}`));
263
+ console.log(HELP);
264
+ return 1;
265
+ }
266
+ }
267
+ if (require.main === module) {
268
+ main().then((code) => {
269
+ if (code !== 0)
270
+ process.exitCode = code;
271
+ });
272
+ }
@@ -0,0 +1,19 @@
1
+ export * from "./types";
2
+ export { createTemplate, aiPrompt, SCHEMA_VERSION } from "./template";
3
+ export { loadOnboarding, resolveEnabled, resolveFile, isBlank, DEFAULT_FILE } from "./load";
4
+ export { validateOnboarding, parseEvidence } from "./validate";
5
+ export { resolveBrand, parseColor, toHex } from "./brand";
6
+ export type { Hsl, ResolvedBrand } from "./brand";
7
+ export type { Issue, ValidateOptions } from "./validate";
8
+ export { renderOnboarding, escapeHtml } from "./render";
9
+ export interface RenderedPage {
10
+ status: number;
11
+ html: string;
12
+ }
13
+ /** Lê o onboarding.json a cada chamada e devolve a página pronta (usado pelos adapters). */
14
+ export declare function renderOnboardingPage(file?: string): Promise<RenderedPage>;
15
+ export declare const HTML_HEADERS: {
16
+ readonly "Content-Type": "text/html; charset=utf-8";
17
+ readonly "Cache-Control": "no-store";
18
+ readonly "X-Robots-Tag": "noindex";
19
+ };
package/dist/index.js ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
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
+ exports.renderOnboardingPage = renderOnboardingPage;
19
+ const node_path_1 = require("node:path");
20
+ const load_1 = require("./load");
21
+ const render_1 = require("./render");
22
+ __exportStar(require("./types"), exports);
23
+ var template_1 = require("./template");
24
+ Object.defineProperty(exports, "createTemplate", { enumerable: true, get: function () { return template_1.createTemplate; } });
25
+ Object.defineProperty(exports, "aiPrompt", { enumerable: true, get: function () { return template_1.aiPrompt; } });
26
+ Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return template_1.SCHEMA_VERSION; } });
27
+ var load_2 = require("./load");
28
+ Object.defineProperty(exports, "loadOnboarding", { enumerable: true, get: function () { return load_2.loadOnboarding; } });
29
+ Object.defineProperty(exports, "resolveEnabled", { enumerable: true, get: function () { return load_2.resolveEnabled; } });
30
+ Object.defineProperty(exports, "resolveFile", { enumerable: true, get: function () { return load_2.resolveFile; } });
31
+ Object.defineProperty(exports, "isBlank", { enumerable: true, get: function () { return load_2.isBlank; } });
32
+ Object.defineProperty(exports, "DEFAULT_FILE", { enumerable: true, get: function () { return load_2.DEFAULT_FILE; } });
33
+ var validate_1 = require("./validate");
34
+ Object.defineProperty(exports, "validateOnboarding", { enumerable: true, get: function () { return validate_1.validateOnboarding; } });
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; } });
40
+ var render_2 = require("./render");
41
+ Object.defineProperty(exports, "renderOnboarding", { enumerable: true, get: function () { return render_2.renderOnboarding; } });
42
+ Object.defineProperty(exports, "escapeHtml", { enumerable: true, get: function () { return render_2.escapeHtml; } });
43
+ /** Lê o onboarding.json a cada chamada e devolve a página pronta (usado pelos adapters). */
44
+ async function renderOnboardingPage(file) {
45
+ const result = await (0, load_1.loadOnboarding)(file);
46
+ const root = (0, node_path_1.dirname)(result.file);
47
+ if (!result.ok) {
48
+ return result.reason === "missing"
49
+ ? { status: 200, html: (0, render_1.renderMissingPage)(root) }
50
+ : { status: 500, html: (0, render_1.renderErrorPage)(result.message, root) };
51
+ }
52
+ try {
53
+ return { status: 200, html: (0, render_1.renderOnboarding)(result.data, { root }) };
54
+ }
55
+ catch (err) {
56
+ return { status: 500, html: (0, render_1.renderErrorPage)(err.message, root) };
57
+ }
58
+ }
59
+ exports.HTML_HEADERS = {
60
+ "Content-Type": "text/html; charset=utf-8",
61
+ "Cache-Control": "no-store",
62
+ "X-Robots-Tag": "noindex",
63
+ };
package/dist/load.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { OnboardingData, OnboardingOptions } from "./types";
2
+ export declare const DEFAULT_FILE = "onboarding.json";
3
+ export declare function resolveFile(file?: string): string;
4
+ export declare function resolveEnabled(options?: OnboardingOptions): boolean;
5
+ export type LoadResult = {
6
+ ok: true;
7
+ file: string;
8
+ data: OnboardingData;
9
+ } | {
10
+ ok: false;
11
+ file: string;
12
+ reason: "missing" | "invalid-json";
13
+ message: string;
14
+ };
15
+ export declare function loadOnboarding(file?: string): Promise<LoadResult>;
16
+ /** true quando o valor não tem nenhum texto preenchido (strings vazias, arrays/objetos vazios). */
17
+ export declare function isBlank(value: unknown): boolean;
18
+ /** Remove itens-modelo em branco de um array. */
19
+ export declare function filled<T>(items: T[] | undefined | null): T[];
package/dist/load.js ADDED
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_FILE = void 0;
4
+ exports.resolveFile = resolveFile;
5
+ exports.resolveEnabled = resolveEnabled;
6
+ exports.loadOnboarding = loadOnboarding;
7
+ exports.isBlank = isBlank;
8
+ exports.filled = filled;
9
+ const promises_1 = require("node:fs/promises");
10
+ const node_path_1 = require("node:path");
11
+ exports.DEFAULT_FILE = "onboarding.json";
12
+ function resolveFile(file) {
13
+ return (0, node_path_1.resolve)(process.cwd(), file ?? exports.DEFAULT_FILE);
14
+ }
15
+ function resolveEnabled(options = {}) {
16
+ return options.enabled ?? process.env.NODE_ENV !== "production";
17
+ }
18
+ async function loadOnboarding(file) {
19
+ const path = resolveFile(file);
20
+ let raw;
21
+ try {
22
+ raw = await (0, promises_1.readFile)(path, "utf8");
23
+ }
24
+ catch {
25
+ return { ok: false, file: path, reason: "missing", message: `Arquivo não encontrado: ${path}` };
26
+ }
27
+ try {
28
+ return { ok: true, file: path, data: JSON.parse(raw) };
29
+ }
30
+ catch (err) {
31
+ return {
32
+ ok: false,
33
+ file: path,
34
+ reason: "invalid-json",
35
+ message: `JSON inválido em ${path}: ${err.message}`,
36
+ };
37
+ }
38
+ }
39
+ /** true quando o valor não tem nenhum texto preenchido (strings vazias, arrays/objetos vazios). */
40
+ function isBlank(value) {
41
+ if (value === null || value === undefined)
42
+ return true;
43
+ if (typeof value === "string")
44
+ return value.trim() === "";
45
+ if (typeof value === "boolean" || typeof value === "number")
46
+ return true;
47
+ if (Array.isArray(value))
48
+ return value.every(isBlank);
49
+ if (typeof value === "object") {
50
+ return Object.entries(value)
51
+ .filter(([key]) => !key.startsWith("_"))
52
+ .every(([, v]) => isBlank(v));
53
+ }
54
+ return true;
55
+ }
56
+ /** Remove itens-modelo em branco de um array. */
57
+ function filled(items) {
58
+ return Array.isArray(items) ? items.filter((item) => !isBlank(item)) : [];
59
+ }
@@ -0,0 +1,4 @@
1
+ export declare const MERMAID_URL = "https://cdn.jsdelivr.net/npm/mermaid@11.4.1/dist/mermaid.min.js";
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/* 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";