@brandsystem/mcp 0.3.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 +515 -0
- package/bin/brandsystem-mcp.mjs +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/brand-dir.d.ts +56 -0
- package/dist/lib/brand-dir.d.ts.map +1 -0
- package/dist/lib/brand-dir.js +270 -0
- package/dist/lib/brand-dir.js.map +1 -0
- package/dist/lib/color-namer.d.ts +28 -0
- package/dist/lib/color-namer.d.ts.map +1 -0
- package/dist/lib/color-namer.js +155 -0
- package/dist/lib/color-namer.js.map +1 -0
- package/dist/lib/confidence.d.ts +19 -0
- package/dist/lib/confidence.d.ts.map +1 -0
- package/dist/lib/confidence.js +66 -0
- package/dist/lib/confidence.js.map +1 -0
- package/dist/lib/content-scorer.d.ts +38 -0
- package/dist/lib/content-scorer.d.ts.map +1 -0
- package/dist/lib/content-scorer.js +571 -0
- package/dist/lib/content-scorer.js.map +1 -0
- package/dist/lib/css-parser.d.ts +45 -0
- package/dist/lib/css-parser.d.ts.map +1 -0
- package/dist/lib/css-parser.js +330 -0
- package/dist/lib/css-parser.js.map +1 -0
- package/dist/lib/dtcg-compiler.d.ts +7 -0
- package/dist/lib/dtcg-compiler.d.ts.map +1 -0
- package/dist/lib/dtcg-compiler.js +89 -0
- package/dist/lib/dtcg-compiler.js.map +1 -0
- package/dist/lib/interaction-policy-compiler.d.ts +40 -0
- package/dist/lib/interaction-policy-compiler.d.ts.map +1 -0
- package/dist/lib/interaction-policy-compiler.js +60 -0
- package/dist/lib/interaction-policy-compiler.js.map +1 -0
- package/dist/lib/logo-extractor.d.ts +49 -0
- package/dist/lib/logo-extractor.d.ts.map +1 -0
- package/dist/lib/logo-extractor.js +384 -0
- package/dist/lib/logo-extractor.js.map +1 -0
- package/dist/lib/report-html.d.ts +20 -0
- package/dist/lib/report-html.d.ts.map +1 -0
- package/dist/lib/report-html.js +938 -0
- package/dist/lib/report-html.js.map +1 -0
- package/dist/lib/response.d.ts +20 -0
- package/dist/lib/response.d.ts.map +1 -0
- package/dist/lib/response.js +54 -0
- package/dist/lib/response.js.map +1 -0
- package/dist/lib/runtime-compiler.d.ts +60 -0
- package/dist/lib/runtime-compiler.d.ts.map +1 -0
- package/dist/lib/runtime-compiler.js +96 -0
- package/dist/lib/runtime-compiler.js.map +1 -0
- package/dist/lib/svg-resolver.d.ts +21 -0
- package/dist/lib/svg-resolver.d.ts.map +1 -0
- package/dist/lib/svg-resolver.js +115 -0
- package/dist/lib/svg-resolver.js.map +1 -0
- package/dist/lib/url-validator.d.ts +11 -0
- package/dist/lib/url-validator.d.ts.map +1 -0
- package/dist/lib/url-validator.js +93 -0
- package/dist/lib/url-validator.js.map +1 -0
- package/dist/lib/version.d.ts +2 -0
- package/dist/lib/version.d.ts.map +1 -0
- package/dist/lib/version.js +19 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/vim-generator.d.ts +13 -0
- package/dist/lib/vim-generator.d.ts.map +1 -0
- package/dist/lib/vim-generator.js +718 -0
- package/dist/lib/vim-generator.js.map +1 -0
- package/dist/resources/brand-resources.d.ts +4 -0
- package/dist/resources/brand-resources.d.ts.map +1 -0
- package/dist/resources/brand-resources.js +34 -0
- package/dist/resources/brand-resources.js.map +1 -0
- package/dist/schemas/brand-config.d.ts +28 -0
- package/dist/schemas/brand-config.d.ts.map +1 -0
- package/dist/schemas/brand-config.js +11 -0
- package/dist/schemas/brand-config.js.map +1 -0
- package/dist/schemas/brand-runtime.d.ts +251 -0
- package/dist/schemas/brand-runtime.d.ts.map +1 -0
- package/dist/schemas/brand-runtime.js +54 -0
- package/dist/schemas/brand-runtime.js.map +1 -0
- package/dist/schemas/core-identity.d.ts +302 -0
- package/dist/schemas/core-identity.d.ts.map +1 -0
- package/dist/schemas/core-identity.js +51 -0
- package/dist/schemas/core-identity.js.map +1 -0
- package/dist/schemas/index.d.ts +11 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +11 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/interaction-policy.d.ts +150 -0
- package/dist/schemas/interaction-policy.d.ts.map +1 -0
- package/dist/schemas/interaction-policy.js +34 -0
- package/dist/schemas/interaction-policy.js.map +1 -0
- package/dist/schemas/messaging.d.ts +776 -0
- package/dist/schemas/messaging.d.ts.map +1 -0
- package/dist/schemas/messaging.js +68 -0
- package/dist/schemas/messaging.js.map +1 -0
- package/dist/schemas/needs-clarification.d.ts +62 -0
- package/dist/schemas/needs-clarification.d.ts.map +1 -0
- package/dist/schemas/needs-clarification.js +13 -0
- package/dist/schemas/needs-clarification.js.map +1 -0
- package/dist/schemas/strategy.d.ts +537 -0
- package/dist/schemas/strategy.d.ts.map +1 -0
- package/dist/schemas/strategy.js +71 -0
- package/dist/schemas/strategy.js.map +1 -0
- package/dist/schemas/tokens.d.ts +35 -0
- package/dist/schemas/tokens.d.ts.map +1 -0
- package/dist/schemas/tokens.js +15 -0
- package/dist/schemas/tokens.js.map +1 -0
- package/dist/schemas/visual-identity.d.ts +224 -0
- package/dist/schemas/visual-identity.d.ts.map +1 -0
- package/dist/schemas/visual-identity.js +42 -0
- package/dist/schemas/visual-identity.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +75 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/brand-audit-content.d.ts +3 -0
- package/dist/tools/brand-audit-content.d.ts.map +1 -0
- package/dist/tools/brand-audit-content.js +116 -0
- package/dist/tools/brand-audit-content.js.map +1 -0
- package/dist/tools/brand-audit-drift.d.ts +3 -0
- package/dist/tools/brand-audit-drift.d.ts.map +1 -0
- package/dist/tools/brand-audit-drift.js +301 -0
- package/dist/tools/brand-audit-drift.js.map +1 -0
- package/dist/tools/brand-audit.d.ts +3 -0
- package/dist/tools/brand-audit.d.ts.map +1 -0
- package/dist/tools/brand-audit.js +129 -0
- package/dist/tools/brand-audit.js.map +1 -0
- package/dist/tools/brand-build-journey.d.ts +3 -0
- package/dist/tools/brand-build-journey.d.ts.map +1 -0
- package/dist/tools/brand-build-journey.js +312 -0
- package/dist/tools/brand-build-journey.js.map +1 -0
- package/dist/tools/brand-build-matrix.d.ts +3 -0
- package/dist/tools/brand-build-matrix.d.ts.map +1 -0
- package/dist/tools/brand-build-matrix.js +525 -0
- package/dist/tools/brand-build-matrix.js.map +1 -0
- package/dist/tools/brand-build-personas.d.ts +3 -0
- package/dist/tools/brand-build-personas.d.ts.map +1 -0
- package/dist/tools/brand-build-personas.js +436 -0
- package/dist/tools/brand-build-personas.js.map +1 -0
- package/dist/tools/brand-build-themes.d.ts +3 -0
- package/dist/tools/brand-build-themes.d.ts.map +1 -0
- package/dist/tools/brand-build-themes.js +476 -0
- package/dist/tools/brand-build-themes.js.map +1 -0
- package/dist/tools/brand-check-compliance.d.ts +3 -0
- package/dist/tools/brand-check-compliance.d.ts.map +1 -0
- package/dist/tools/brand-check-compliance.js +243 -0
- package/dist/tools/brand-check-compliance.js.map +1 -0
- package/dist/tools/brand-clarify.d.ts +21 -0
- package/dist/tools/brand-clarify.d.ts.map +1 -0
- package/dist/tools/brand-clarify.js +497 -0
- package/dist/tools/brand-clarify.js.map +1 -0
- package/dist/tools/brand-compile-messaging.d.ts +3 -0
- package/dist/tools/brand-compile-messaging.d.ts.map +1 -0
- package/dist/tools/brand-compile-messaging.js +759 -0
- package/dist/tools/brand-compile-messaging.js.map +1 -0
- package/dist/tools/brand-compile.d.ts +3 -0
- package/dist/tools/brand-compile.d.ts.map +1 -0
- package/dist/tools/brand-compile.js +182 -0
- package/dist/tools/brand-compile.js.map +1 -0
- package/dist/tools/brand-deepen-identity.d.ts +3 -0
- package/dist/tools/brand-deepen-identity.d.ts.map +1 -0
- package/dist/tools/brand-deepen-identity.js +483 -0
- package/dist/tools/brand-deepen-identity.js.map +1 -0
- package/dist/tools/brand-export.d.ts +17 -0
- package/dist/tools/brand-export.d.ts.map +1 -0
- package/dist/tools/brand-export.js +730 -0
- package/dist/tools/brand-export.js.map +1 -0
- package/dist/tools/brand-extract-figma.d.ts +3 -0
- package/dist/tools/brand-extract-figma.d.ts.map +1 -0
- package/dist/tools/brand-extract-figma.js +174 -0
- package/dist/tools/brand-extract-figma.js.map +1 -0
- package/dist/tools/brand-extract-messaging.d.ts +3 -0
- package/dist/tools/brand-extract-messaging.d.ts.map +1 -0
- package/dist/tools/brand-extract-messaging.js +620 -0
- package/dist/tools/brand-extract-messaging.js.map +1 -0
- package/dist/tools/brand-extract-web.d.ts +3 -0
- package/dist/tools/brand-extract-web.d.ts.map +1 -0
- package/dist/tools/brand-extract-web.js +477 -0
- package/dist/tools/brand-extract-web.js.map +1 -0
- package/dist/tools/brand-feedback.d.ts +3 -0
- package/dist/tools/brand-feedback.d.ts.map +1 -0
- package/dist/tools/brand-feedback.js +366 -0
- package/dist/tools/brand-feedback.js.map +1 -0
- package/dist/tools/brand-ingest-assets.d.ts +3 -0
- package/dist/tools/brand-ingest-assets.d.ts.map +1 -0
- package/dist/tools/brand-ingest-assets.js +233 -0
- package/dist/tools/brand-ingest-assets.js.map +1 -0
- package/dist/tools/brand-init.d.ts +3 -0
- package/dist/tools/brand-init.d.ts.map +1 -0
- package/dist/tools/brand-init.js +66 -0
- package/dist/tools/brand-init.js.map +1 -0
- package/dist/tools/brand-preflight.d.ts +3 -0
- package/dist/tools/brand-preflight.d.ts.map +1 -0
- package/dist/tools/brand-preflight.js +608 -0
- package/dist/tools/brand-preflight.js.map +1 -0
- package/dist/tools/brand-report.d.ts +3 -0
- package/dist/tools/brand-report.d.ts.map +1 -0
- package/dist/tools/brand-report.js +154 -0
- package/dist/tools/brand-report.js.map +1 -0
- package/dist/tools/brand-runtime.d.ts +3 -0
- package/dist/tools/brand-runtime.d.ts.map +1 -0
- package/dist/tools/brand-runtime.js +37 -0
- package/dist/tools/brand-runtime.js.map +1 -0
- package/dist/tools/brand-set-logo.d.ts +3 -0
- package/dist/tools/brand-set-logo.d.ts.map +1 -0
- package/dist/tools/brand-set-logo.js +170 -0
- package/dist/tools/brand-set-logo.js.map +1 -0
- package/dist/tools/brand-start.d.ts +3 -0
- package/dist/tools/brand-start.d.ts.map +1 -0
- package/dist/tools/brand-start.js +686 -0
- package/dist/tools/brand-start.js.map +1 -0
- package/dist/tools/brand-status.d.ts +3 -0
- package/dist/tools/brand-status.d.ts.map +1 -0
- package/dist/tools/brand-status.js +175 -0
- package/dist/tools/brand-status.js.map +1 -0
- package/dist/tools/brand-write.d.ts +3 -0
- package/dist/tools/brand-write.d.ts.map +1 -0
- package/dist/tools/brand-write.js +442 -0
- package/dist/tools/brand-write.js.map +1 -0
- package/dist/types/index.d.ts +331 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +52 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
import { sanitizeSvg } from "./svg-resolver.js";
|
|
2
|
+
/**
|
|
3
|
+
* Generate a plain-text brand instruction block that can be pasted
|
|
4
|
+
* into any AI tool's custom instructions / project context / system prompt.
|
|
5
|
+
* Written as a directive to an AI, not a description for a human.
|
|
6
|
+
*/
|
|
7
|
+
export function generateBrandInstructions(config, identity) {
|
|
8
|
+
const lines = [];
|
|
9
|
+
lines.push(`# Brand Identity: ${config.client_name}`);
|
|
10
|
+
lines.push("");
|
|
11
|
+
lines.push(`Apply these guidelines to all visual output, code-generated artifacts, and design work for ${config.client_name}.`);
|
|
12
|
+
// Logo
|
|
13
|
+
const logoVariant = identity.logo[0]?.variants[0];
|
|
14
|
+
if (logoVariant?.inline_svg) {
|
|
15
|
+
lines.push("");
|
|
16
|
+
lines.push("## Logo");
|
|
17
|
+
lines.push("");
|
|
18
|
+
lines.push(`IMPORTANT: Always use the SVG below for the ${config.client_name} logo. Never type the company name in a font — always embed this vector markup. For dark backgrounds, add fill="#ffffff" to override the path fills.`);
|
|
19
|
+
lines.push("");
|
|
20
|
+
lines.push("```svg");
|
|
21
|
+
lines.push(logoVariant.inline_svg.trim());
|
|
22
|
+
lines.push("```");
|
|
23
|
+
if (logoVariant.data_uri) {
|
|
24
|
+
lines.push("");
|
|
25
|
+
lines.push("For `<img>` tags or contexts that don't support inline SVG, use this data URI as the src:");
|
|
26
|
+
lines.push("");
|
|
27
|
+
lines.push("```");
|
|
28
|
+
lines.push(logoVariant.data_uri);
|
|
29
|
+
lines.push("```");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// Colors
|
|
33
|
+
const namedColors = identity.colors.filter((c) => c.role !== "unknown" && c.confidence !== "low");
|
|
34
|
+
const unknownColors = identity.colors.filter((c) => c.role === "unknown" && c.confidence !== "low");
|
|
35
|
+
if (namedColors.length > 0 || unknownColors.length > 0) {
|
|
36
|
+
lines.push("");
|
|
37
|
+
lines.push("## Colors");
|
|
38
|
+
lines.push("");
|
|
39
|
+
lines.push("Use these exact hex values. Do not substitute approximate colors.");
|
|
40
|
+
lines.push("");
|
|
41
|
+
lines.push("| Role | Hex |");
|
|
42
|
+
lines.push("|------|-----|");
|
|
43
|
+
for (const c of namedColors) {
|
|
44
|
+
lines.push(`| ${c.role} | ${c.value} |`);
|
|
45
|
+
}
|
|
46
|
+
for (const c of unknownColors) {
|
|
47
|
+
lines.push(`| (unassigned) | ${c.value} |`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Typography
|
|
51
|
+
const fonts = identity.typography.filter((t) => t.confidence !== "low");
|
|
52
|
+
if (fonts.length > 0) {
|
|
53
|
+
lines.push("");
|
|
54
|
+
lines.push("## Typography");
|
|
55
|
+
lines.push("");
|
|
56
|
+
for (const f of fonts) {
|
|
57
|
+
lines.push(`- ${f.family}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Rules
|
|
61
|
+
lines.push("");
|
|
62
|
+
lines.push("## Rules");
|
|
63
|
+
lines.push("");
|
|
64
|
+
if (logoVariant?.inline_svg) {
|
|
65
|
+
lines.push("- Never approximate the logo with text in a similar font — always use the SVG above");
|
|
66
|
+
}
|
|
67
|
+
lines.push("- Use exact hex values from the color table — no \"close enough\" substitutions");
|
|
68
|
+
lines.push("- When generating HTML, CSS, or any visual code, reference these brand values directly");
|
|
69
|
+
if (identity.colors.some((c) => c.role === "surface") && identity.colors.some((c) => c.role === "text")) {
|
|
70
|
+
lines.push("- For dark-themed content, swap surface and text colors and invert the logo to white");
|
|
71
|
+
}
|
|
72
|
+
return lines.join("\n");
|
|
73
|
+
}
|
|
74
|
+
function escapeHtml(str) {
|
|
75
|
+
return str
|
|
76
|
+
.replace(/&/g, "&")
|
|
77
|
+
.replace(/</g, "<")
|
|
78
|
+
.replace(/>/g, ">")
|
|
79
|
+
.replace(/"/g, """);
|
|
80
|
+
}
|
|
81
|
+
function confidenceBadge(c) {
|
|
82
|
+
const cls = {
|
|
83
|
+
confirmed: "badge-confirmed",
|
|
84
|
+
high: "badge-high",
|
|
85
|
+
medium: "badge-medium",
|
|
86
|
+
low: "badge-low",
|
|
87
|
+
};
|
|
88
|
+
return `<span class="badge ${cls[c] || "badge-low"}">${c}</span>`;
|
|
89
|
+
}
|
|
90
|
+
function roleBadge(role) {
|
|
91
|
+
if (role === "unknown")
|
|
92
|
+
return `<span class="badge badge-warn">needs role</span>`;
|
|
93
|
+
return `<span class="badge badge-role">${role}</span>`;
|
|
94
|
+
}
|
|
95
|
+
/** Relative luminance for contrast detection */
|
|
96
|
+
function luminance(hex) {
|
|
97
|
+
const h = hex.replace("#", "");
|
|
98
|
+
const [r, g, b] = [0, 2, 4].map((i) => {
|
|
99
|
+
const s = parseInt(h.substring(i, i + 2), 16) / 255;
|
|
100
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
101
|
+
});
|
|
102
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
103
|
+
}
|
|
104
|
+
function buildColorCards(identity) {
|
|
105
|
+
return identity.colors
|
|
106
|
+
.map((c) => {
|
|
107
|
+
const isLight = luminance(c.value) > 0.7;
|
|
108
|
+
return `
|
|
109
|
+
<div class="color-card">
|
|
110
|
+
<div class="color-swatch${isLight ? " is-light" : ""}" style="background:${c.value}"></div>
|
|
111
|
+
<div class="color-info">
|
|
112
|
+
<div class="color-role">${roleBadge(c.role)}</div>
|
|
113
|
+
<div class="color-hex">${c.value}</div>
|
|
114
|
+
<div class="color-meta">${confidenceBadge(c.confidence)} <span class="source">via ${c.source}</span></div>
|
|
115
|
+
</div>
|
|
116
|
+
</div>`;
|
|
117
|
+
})
|
|
118
|
+
.join("\n");
|
|
119
|
+
}
|
|
120
|
+
function buildFontCards(identity) {
|
|
121
|
+
return identity.typography
|
|
122
|
+
.map((t) => `
|
|
123
|
+
<div class="font-card">
|
|
124
|
+
<div class="font-specimen">${escapeHtml(t.family)}</div>
|
|
125
|
+
<div class="font-meta">
|
|
126
|
+
${confidenceBadge(t.confidence)}
|
|
127
|
+
<span class="source">via ${t.source}</span>
|
|
128
|
+
${t.weight ? `<span class="detail">weight ${t.weight}</span>` : ""}
|
|
129
|
+
</div>
|
|
130
|
+
</div>`)
|
|
131
|
+
.join("\n");
|
|
132
|
+
}
|
|
133
|
+
function buildLogoSection(identity) {
|
|
134
|
+
if (identity.logo.length === 0) {
|
|
135
|
+
return `
|
|
136
|
+
<div class="empty-state">
|
|
137
|
+
No logo detected. Add one via Figma extraction or manual upload.
|
|
138
|
+
</div>`;
|
|
139
|
+
}
|
|
140
|
+
const blocks = [];
|
|
141
|
+
for (const logo of identity.logo) {
|
|
142
|
+
for (const variant of logo.variants) {
|
|
143
|
+
const rawSvg = variant.inline_svg || "";
|
|
144
|
+
if (!rawSvg)
|
|
145
|
+
continue;
|
|
146
|
+
const svgMarkup = sanitizeSvg(rawSvg);
|
|
147
|
+
blocks.push(`
|
|
148
|
+
<div class="logo-pair">
|
|
149
|
+
<div class="logo-display logo-light">
|
|
150
|
+
<div class="logo-inner">${svgMarkup}</div>
|
|
151
|
+
<span class="logo-label">On light</span>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="logo-display logo-dark">
|
|
154
|
+
<div class="logo-inner">${svgMarkup}</div>
|
|
155
|
+
<span class="logo-label logo-label-dark">On dark</span>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
<div class="logo-meta-row">
|
|
159
|
+
<span>Type: ${logo.type}</span>
|
|
160
|
+
<span>${confidenceBadge(logo.confidence)}</span>
|
|
161
|
+
<span class="source">via ${logo.source}</span>
|
|
162
|
+
</div>`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return blocks.join("\n") || `<div class="empty-state">Logo file found but no inline SVG available.</div>`;
|
|
166
|
+
}
|
|
167
|
+
let copyBlockCounter = 0;
|
|
168
|
+
function nextCopyId() {
|
|
169
|
+
return `copy-ref-${++copyBlockCounter}`;
|
|
170
|
+
}
|
|
171
|
+
function buildUsageSection(identity) {
|
|
172
|
+
const parts = [];
|
|
173
|
+
// Logo usage
|
|
174
|
+
const logoVariant = identity.logo[0]?.variants[0];
|
|
175
|
+
if (logoVariant?.inline_svg) {
|
|
176
|
+
const svgId = nextCopyId();
|
|
177
|
+
const uriId = nextCopyId();
|
|
178
|
+
parts.push(`
|
|
179
|
+
<div class="usage-block">
|
|
180
|
+
<h3>Logo SVG</h3>
|
|
181
|
+
<p>Never type the company name in a font. Always use this vector:</p>
|
|
182
|
+
<div class="copy-wrap" id="${svgId}">
|
|
183
|
+
<button class="copy-btn" onclick="copyBlock('${svgId}')">Copy</button>
|
|
184
|
+
<pre><code>${escapeHtml(logoVariant.inline_svg.trim())}</code></pre>
|
|
185
|
+
</div>
|
|
186
|
+
${logoVariant.data_uri ? `<h3>Logo Data URI</h3>
|
|
187
|
+
<p>For <img> tags — use as src value:</p>
|
|
188
|
+
<div class="copy-wrap compact" id="${uriId}">
|
|
189
|
+
<button class="copy-btn" onclick="copyBlock('${uriId}')">Copy</button>
|
|
190
|
+
<pre><code>${escapeHtml(logoVariant.data_uri)}</code></pre>
|
|
191
|
+
</div>` : ""}
|
|
192
|
+
</div>`);
|
|
193
|
+
}
|
|
194
|
+
// Color quick-ref
|
|
195
|
+
const namedColors = identity.colors.filter((c) => c.role !== "unknown");
|
|
196
|
+
if (namedColors.length > 0) {
|
|
197
|
+
const colorLine = namedColors.map((c) => `${c.role}: ${c.value}`).join(" | ");
|
|
198
|
+
const colorId = nextCopyId();
|
|
199
|
+
parts.push(`
|
|
200
|
+
<div class="usage-block">
|
|
201
|
+
<h3>Colors</h3>
|
|
202
|
+
<div class="copy-wrap" id="${colorId}">
|
|
203
|
+
<button class="copy-btn" onclick="copyBlock('${colorId}')">Copy</button>
|
|
204
|
+
<pre><code>${escapeHtml(colorLine)}</code></pre>
|
|
205
|
+
</div>
|
|
206
|
+
</div>`);
|
|
207
|
+
}
|
|
208
|
+
// Font quick-ref
|
|
209
|
+
const highConfFonts = identity.typography.filter((t) => t.confidence !== "low");
|
|
210
|
+
if (highConfFonts.length > 0) {
|
|
211
|
+
const fontLine = highConfFonts.map((t) => t.family).join(", ");
|
|
212
|
+
const fontId = nextCopyId();
|
|
213
|
+
parts.push(`
|
|
214
|
+
<div class="usage-block">
|
|
215
|
+
<h3>Fonts</h3>
|
|
216
|
+
<div class="copy-wrap" id="${fontId}">
|
|
217
|
+
<button class="copy-btn" onclick="copyBlock('${fontId}')">Copy</button>
|
|
218
|
+
<pre><code>font-family: ${escapeHtml(fontLine)}</code></pre>
|
|
219
|
+
</div>
|
|
220
|
+
</div>`);
|
|
221
|
+
}
|
|
222
|
+
return parts.join("\n");
|
|
223
|
+
}
|
|
224
|
+
function buildComparisonSection(config, identity) {
|
|
225
|
+
const hasLogo = identity.logo.length > 0 && identity.logo[0]?.variants[0]?.inline_svg;
|
|
226
|
+
const primaryColor = identity.colors.find((c) => c.role === "primary");
|
|
227
|
+
const colorCount = identity.colors.filter((c) => c.confidence !== "low").length;
|
|
228
|
+
const brandFonts = identity.typography.filter((t) => t.confidence !== "low");
|
|
229
|
+
const clientName = escapeHtml(config.client_name);
|
|
230
|
+
return `
|
|
231
|
+
<section>
|
|
232
|
+
<h2>Your Brand vs. Generic AI</h2>
|
|
233
|
+
<p class="section-intro">
|
|
234
|
+
This is what your AI tools know now vs. what they’d guess without a brand system.
|
|
235
|
+
</p>
|
|
236
|
+
<div class="comp-grid">
|
|
237
|
+
<div class="comp-card comp-card-brand">
|
|
238
|
+
<div class="comp-card-header">
|
|
239
|
+
<span class="comp-card-dot comp-dot-brand"></span>
|
|
240
|
+
With Your Brand System
|
|
241
|
+
</div>
|
|
242
|
+
<div class="comp-card-body">
|
|
243
|
+
<div class="comp-row">
|
|
244
|
+
<span class="comp-row-label">Logo</span>
|
|
245
|
+
<span class="comp-row-value">${hasLogo
|
|
246
|
+
? `<div class="comp-logo-preview">${sanitizeSvg(identity.logo[0].variants[0].inline_svg || "")}</div>Embedded vector — renders everywhere`
|
|
247
|
+
: `<span class="comp-missing">Not yet extracted — add via Figma or upload</span>`}</span>
|
|
248
|
+
</div>
|
|
249
|
+
<div class="comp-row">
|
|
250
|
+
<span class="comp-row-label">Colors</span>
|
|
251
|
+
<span class="comp-row-value">${primaryColor
|
|
252
|
+
? `<span class="comp-swatch" style="background:${primaryColor.value}"></span>${primaryColor.value} (primary) + ${colorCount - 1} more`
|
|
253
|
+
: colorCount > 0
|
|
254
|
+
? `${colorCount} colors extracted with hex values`
|
|
255
|
+
: `<span class="comp-missing">Not yet extracted</span>`}</span>
|
|
256
|
+
</div>
|
|
257
|
+
<div class="comp-row">
|
|
258
|
+
<span class="comp-row-label">Fonts</span>
|
|
259
|
+
<span class="comp-row-value">${brandFonts.length > 0
|
|
260
|
+
? brandFonts.map((f) => f.family).join(", ")
|
|
261
|
+
: `<span class="comp-missing">Not yet extracted</span>`}</span>
|
|
262
|
+
</div>
|
|
263
|
+
<div class="comp-row">
|
|
264
|
+
<span class="comp-row-label">Tokens</span>
|
|
265
|
+
<span class="comp-row-value">Machine-readable DTCG format</span>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
<div class="comp-card comp-card-generic">
|
|
270
|
+
<div class="comp-card-header">
|
|
271
|
+
<span class="comp-card-dot comp-dot-generic"></span>
|
|
272
|
+
Without It
|
|
273
|
+
</div>
|
|
274
|
+
<div class="comp-card-body">
|
|
275
|
+
<div class="comp-row">
|
|
276
|
+
<span class="comp-row-label">Logo</span>
|
|
277
|
+
<span class="comp-row-value comp-generic-text">Would type “${clientName}” in a similar-looking font</span>
|
|
278
|
+
</div>
|
|
279
|
+
<div class="comp-row">
|
|
280
|
+
<span class="comp-row-label">Colors</span>
|
|
281
|
+
<span class="comp-row-value comp-generic-text">Would pick a blue primary or “professional” defaults</span>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="comp-row">
|
|
284
|
+
<span class="comp-row-label">Fonts</span>
|
|
285
|
+
<span class="comp-row-value comp-generic-text">Would default to Inter, system-ui, or Arial</span>
|
|
286
|
+
</div>
|
|
287
|
+
<div class="comp-row">
|
|
288
|
+
<span class="comp-row-label">Tokens</span>
|
|
289
|
+
<span class="comp-row-value comp-generic-text">Would re-interpret a PDF or screenshot every time</span>
|
|
290
|
+
</div>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
</div>
|
|
294
|
+
</section>`;
|
|
295
|
+
}
|
|
296
|
+
function buildSessionProgression() {
|
|
297
|
+
return `
|
|
298
|
+
<section>
|
|
299
|
+
<h2>Brand System Depth</h2>
|
|
300
|
+
<p class="section-intro">
|
|
301
|
+
Your brand system gets more powerful with each session.
|
|
302
|
+
</p>
|
|
303
|
+
<div class="session-track">
|
|
304
|
+
<div class="session-step session-complete">
|
|
305
|
+
<div class="session-pip">
|
|
306
|
+
<div class="session-pip-inner session-pip-done">
|
|
307
|
+
<svg width="12" height="12" viewBox="0 0 12 12" fill="none"><path d="M2.5 6L5 8.5L9.5 3.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
308
|
+
</div>
|
|
309
|
+
<div class="session-connector session-connector-done"></div>
|
|
310
|
+
</div>
|
|
311
|
+
<div class="session-content">
|
|
312
|
+
<div class="session-name">Core Identity</div>
|
|
313
|
+
<div class="session-desc">Colors, typography, logo, design tokens. The basics every AI tool needs.</div>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
<div class="session-step session-next">
|
|
317
|
+
<div class="session-pip">
|
|
318
|
+
<div class="session-pip-inner session-pip-upcoming">2</div>
|
|
319
|
+
<div class="session-connector"></div>
|
|
320
|
+
</div>
|
|
321
|
+
<div class="session-content">
|
|
322
|
+
<div class="session-name">Full Visual Identity</div>
|
|
323
|
+
<div class="session-desc">Composition rules, patterns, illustration language, anti-patterns, automated preflight. Makes output <em>recognizable</em>, not just color-correct.</div>
|
|
324
|
+
</div>
|
|
325
|
+
</div>
|
|
326
|
+
<div class="session-step session-future">
|
|
327
|
+
<div class="session-pip">
|
|
328
|
+
<div class="session-pip-inner session-pip-future">3</div>
|
|
329
|
+
<div class="session-connector"></div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="session-content">
|
|
332
|
+
<div class="session-name">Brand Voice & Messaging</div>
|
|
333
|
+
<div class="session-desc">Voice profile, key messages, audience personas. Written content sounds like you, not like AI.</div>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
<div class="session-step session-future">
|
|
337
|
+
<div class="session-pip">
|
|
338
|
+
<div class="session-pip-inner session-pip-future">4</div>
|
|
339
|
+
<div class="session-connector"></div>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="session-content">
|
|
342
|
+
<div class="session-name">Claims & Evidence</div>
|
|
343
|
+
<div class="session-desc">Proof points with confidence scores. What you can say, what needs qualification, what to never claim.</div>
|
|
344
|
+
</div>
|
|
345
|
+
</div>
|
|
346
|
+
<div class="session-step session-future">
|
|
347
|
+
<div class="session-pip">
|
|
348
|
+
<div class="session-pip-inner session-pip-future">5</div>
|
|
349
|
+
<div class="session-connector"></div>
|
|
350
|
+
</div>
|
|
351
|
+
<div class="session-content">
|
|
352
|
+
<div class="session-name">Content Strategy</div>
|
|
353
|
+
<div class="session-desc">Application rules by content type. Blog posts, social, email, case studies — each with its own governance.</div>
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="session-step session-future">
|
|
357
|
+
<div class="session-pip">
|
|
358
|
+
<div class="session-pip-inner session-pip-future">6</div>
|
|
359
|
+
<div class="session-connector-none"></div>
|
|
360
|
+
</div>
|
|
361
|
+
<div class="session-content">
|
|
362
|
+
<div class="session-name">Full Operations</div>
|
|
363
|
+
<div class="session-desc">Production engines, measurement loops, content library. The complete brand operating system.</div>
|
|
364
|
+
</div>
|
|
365
|
+
</div>
|
|
366
|
+
</div>
|
|
367
|
+
</section>`;
|
|
368
|
+
}
|
|
369
|
+
function buildClarifications(items) {
|
|
370
|
+
if (items.length === 0)
|
|
371
|
+
return "";
|
|
372
|
+
return `
|
|
373
|
+
<section>
|
|
374
|
+
<h2>Needs Clarification</h2>
|
|
375
|
+
<div class="clarify-list">
|
|
376
|
+
${items
|
|
377
|
+
.map((item, i) => `
|
|
378
|
+
<div class="clarify-card">
|
|
379
|
+
<div class="clarify-num">${i + 1}</div>
|
|
380
|
+
<div>
|
|
381
|
+
<div class="clarify-q">${escapeHtml(item.question)}</div>
|
|
382
|
+
<div class="clarify-field">${escapeHtml(item.field)} • ${item.priority} priority</div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>`)
|
|
385
|
+
.join("\n")}
|
|
386
|
+
</div>
|
|
387
|
+
</section>`;
|
|
388
|
+
}
|
|
389
|
+
export function generateReportHTML(data) {
|
|
390
|
+
copyBlockCounter = 0;
|
|
391
|
+
const { config, identity, clarifications, tokenCount, auditSummary } = data;
|
|
392
|
+
const overall = auditSummary.fail > 0 ? "FAIL" : auditSummary.warn > 0 ? "WARN" : "PASS";
|
|
393
|
+
const brandInstructions = escapeHtml(generateBrandInstructions(config, identity));
|
|
394
|
+
const clientName = escapeHtml(config.client_name);
|
|
395
|
+
const mcpConfig = `{
|
|
396
|
+
"mcpServers": {
|
|
397
|
+
"brandsystem": {
|
|
398
|
+
"command": "npx",
|
|
399
|
+
"args": ["@brandsystem/mcp"]
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}`;
|
|
403
|
+
return `<!DOCTYPE html>
|
|
404
|
+
<html lang="en">
|
|
405
|
+
<head>
|
|
406
|
+
<meta charset="UTF-8">
|
|
407
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
408
|
+
<title>${clientName} — Brand Identity Report</title>
|
|
409
|
+
<style>
|
|
410
|
+
/* =========================================================
|
|
411
|
+
brandsystem.app — Brand Identity Report
|
|
412
|
+
========================================================= */
|
|
413
|
+
|
|
414
|
+
/* --- Reset & Base --- */
|
|
415
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
416
|
+
body{
|
|
417
|
+
font-family:Inter,system-ui,-apple-system,sans-serif;
|
|
418
|
+
background:#0a0a0c;
|
|
419
|
+
color:#f0f0f2;
|
|
420
|
+
max-width:760px;
|
|
421
|
+
margin:0 auto;
|
|
422
|
+
padding:48px 32px 80px;
|
|
423
|
+
line-height:1.7;
|
|
424
|
+
-webkit-font-smoothing:antialiased;
|
|
425
|
+
-moz-osx-font-smoothing:grayscale;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/* --- Badges --- */
|
|
429
|
+
.badge{display:inline-block;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;padding:3px 8px;border-radius:4px;vertical-align:middle}
|
|
430
|
+
.badge-confirmed{background:rgba(129,140,248,.12);color:#818cf8}
|
|
431
|
+
.badge-high{background:rgba(129,140,248,.12);color:#a5b4fc}
|
|
432
|
+
.badge-medium{background:rgba(129,140,248,.08);color:#818cf8}
|
|
433
|
+
.badge-low{background:rgba(248,113,113,.1);color:#f87171}
|
|
434
|
+
.badge-warn{background:rgba(251,191,36,.1);color:#fbbf24}
|
|
435
|
+
.badge-role{background:rgba(129,140,248,.1);color:#a5b4fc;text-transform:capitalize}
|
|
436
|
+
.source{font-size:11px;color:#5a5a66}
|
|
437
|
+
.detail{font-size:11px;color:#5a5a66}
|
|
438
|
+
|
|
439
|
+
/* --- Header --- */
|
|
440
|
+
header{padding-bottom:32px;margin-bottom:48px;border-bottom:1px solid #2a2a32}
|
|
441
|
+
.overline{
|
|
442
|
+
font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.16em;
|
|
443
|
+
color:#818cf8;margin-bottom:12px;
|
|
444
|
+
}
|
|
445
|
+
h1{
|
|
446
|
+
font-size:44px;font-weight:700;color:#fff;letter-spacing:-.02em;
|
|
447
|
+
line-height:1.1;margin-bottom:8px;
|
|
448
|
+
}
|
|
449
|
+
.subtitle{font-size:14px;color:#8b8b96;line-height:1.6}
|
|
450
|
+
.audit-line{
|
|
451
|
+
margin-top:16px;font-size:13px;color:#5a5a66;
|
|
452
|
+
display:flex;flex-wrap:wrap;gap:6px;align-items:center;
|
|
453
|
+
}
|
|
454
|
+
.audit-pill{
|
|
455
|
+
display:inline-flex;align-items:center;gap:4px;
|
|
456
|
+
background:#141418;border:1px solid #2a2a32;border-radius:20px;
|
|
457
|
+
padding:4px 12px;font-size:12px;font-weight:500;color:#8b8b96;
|
|
458
|
+
}
|
|
459
|
+
.audit-pill-pass{color:#818cf8;border-color:rgba(129,140,248,.2)}
|
|
460
|
+
.audit-pill strong{color:#818cf8;font-weight:600}
|
|
461
|
+
|
|
462
|
+
/* --- Sections --- */
|
|
463
|
+
section{margin-bottom:64px}
|
|
464
|
+
h2{
|
|
465
|
+
font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.14em;
|
|
466
|
+
color:#5a5a66;margin-bottom:24px;padding-bottom:0;
|
|
467
|
+
}
|
|
468
|
+
.section-intro{font-size:14px;color:#8b8b96;line-height:1.7;margin-bottom:24px}
|
|
469
|
+
|
|
470
|
+
/* --- Logo --- */
|
|
471
|
+
.logo-pair{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:12px}
|
|
472
|
+
.logo-display{
|
|
473
|
+
border-radius:12px;padding:48px 40px;
|
|
474
|
+
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
|
475
|
+
position:relative;
|
|
476
|
+
}
|
|
477
|
+
.logo-inner{width:100%;display:flex;align-items:center;justify-content:center}
|
|
478
|
+
.logo-inner svg{width:100%;max-width:320px;height:auto}
|
|
479
|
+
.logo-light{background:#ffffff}
|
|
480
|
+
.logo-dark{background:#141418;border:1px solid #2a2a32}
|
|
481
|
+
.logo-dark svg path,.logo-dark svg polygon,.logo-dark svg rect,.logo-dark svg circle{fill:#fff !important}
|
|
482
|
+
.logo-label{
|
|
483
|
+
position:absolute;bottom:12px;left:50%;transform:translateX(-50%);
|
|
484
|
+
font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.1em;
|
|
485
|
+
color:#8b8b96;
|
|
486
|
+
}
|
|
487
|
+
.logo-label-dark{color:#5a5a66}
|
|
488
|
+
.logo-meta-row{display:flex;gap:12px;align-items:center;font-size:12px;color:#5a5a66;margin-bottom:12px}
|
|
489
|
+
|
|
490
|
+
/* --- Colors --- */
|
|
491
|
+
.color-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:12px}
|
|
492
|
+
.color-card{border-radius:12px;overflow:hidden;background:#141418;border:1px solid #2a2a32;transition:border-color .15s}
|
|
493
|
+
.color-card:hover{border-color:#3a3a44}
|
|
494
|
+
.color-swatch{height:80px}
|
|
495
|
+
.color-swatch.is-light{border-bottom:1px solid #2a2a32}
|
|
496
|
+
.color-info{padding:14px 16px}
|
|
497
|
+
.color-role{margin-bottom:4px}
|
|
498
|
+
.color-hex{font-size:13px;font-family:'SF Mono',ui-monospace,monospace;color:#8b8b96;margin-bottom:6px}
|
|
499
|
+
.color-meta{display:flex;gap:6px;align-items:center;flex-wrap:wrap}
|
|
500
|
+
|
|
501
|
+
/* --- Typography --- */
|
|
502
|
+
.font-list{display:flex;flex-direction:column;gap:12px}
|
|
503
|
+
.font-card{background:#141418;border:1px solid #2a2a32;border-radius:12px;padding:24px;transition:border-color .15s}
|
|
504
|
+
.font-card:hover{border-color:#3a3a44}
|
|
505
|
+
.font-specimen{font-size:24px;font-weight:600;color:#fff;margin-bottom:8px;letter-spacing:-.01em}
|
|
506
|
+
.font-meta{display:flex;gap:8px;align-items:center}
|
|
507
|
+
|
|
508
|
+
/* --- Quick Reference / Usage --- */
|
|
509
|
+
.usage-block{margin-bottom:28px}
|
|
510
|
+
.usage-block h3{font-size:14px;font-weight:600;color:#f0f0f2;margin-bottom:8px}
|
|
511
|
+
.usage-block p{font-size:14px;color:#8b8b96;line-height:1.7;margin-bottom:10px}
|
|
512
|
+
|
|
513
|
+
/* --- Clarifications --- */
|
|
514
|
+
.clarify-list{display:flex;flex-direction:column;gap:12px}
|
|
515
|
+
.clarify-card{background:#141418;border:1px solid #2a2a32;border-radius:12px;padding:18px 20px;display:flex;gap:14px;align-items:flex-start;transition:border-color .15s}
|
|
516
|
+
.clarify-card:hover{border-color:#3a3a44}
|
|
517
|
+
.clarify-num{flex-shrink:0;width:24px;height:24px;background:#1c1c22;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700;color:#5a5a66}
|
|
518
|
+
.clarify-q{font-size:14px;color:#f0f0f2;line-height:1.6}
|
|
519
|
+
.clarify-field{font-size:11px;font-family:'SF Mono',ui-monospace,monospace;color:#5a5a66;margin-top:4px}
|
|
520
|
+
|
|
521
|
+
/* --- Empty State --- */
|
|
522
|
+
.empty-state{background:#141418;border:1px dashed #2a2a32;border-radius:12px;padding:40px;text-align:center;font-size:14px;color:#5a5a66}
|
|
523
|
+
|
|
524
|
+
/* --- Portable Notice --- */
|
|
525
|
+
.portable-notice{
|
|
526
|
+
background:rgba(129,140,248,.06);
|
|
527
|
+
border:1px solid rgba(129,140,248,.15);
|
|
528
|
+
border-radius:12px;padding:18px 22px;
|
|
529
|
+
font-size:14px;color:#a5b4fc;line-height:1.7;margin-bottom:48px;
|
|
530
|
+
}
|
|
531
|
+
.portable-notice strong{color:#c7d2fe}
|
|
532
|
+
|
|
533
|
+
/* --- Copyable code blocks --- */
|
|
534
|
+
.copy-wrap{position:relative;margin-bottom:12px}
|
|
535
|
+
.copy-wrap pre{
|
|
536
|
+
background:#141418;border:1px solid #2a2a32;border-radius:10px;
|
|
537
|
+
padding:16px 20px;padding-right:72px;
|
|
538
|
+
overflow-x:auto;max-height:180px;overflow-y:auto;
|
|
539
|
+
}
|
|
540
|
+
.copy-wrap code{
|
|
541
|
+
font-family:'SF Mono',ui-monospace,monospace;font-size:12px;
|
|
542
|
+
color:#a5b4fc;white-space:pre-wrap;word-break:break-word;line-height:1.6;
|
|
543
|
+
}
|
|
544
|
+
.copy-wrap.compact code{font-size:10px;color:#818cf8}
|
|
545
|
+
.copy-btn{
|
|
546
|
+
position:absolute;top:10px;right:10px;
|
|
547
|
+
background:#1c1c22;border:1px solid #2a2a32;
|
|
548
|
+
color:#8b8b96;font-size:11px;font-weight:600;
|
|
549
|
+
padding:5px 14px;border-radius:6px;cursor:pointer;transition:all .15s;
|
|
550
|
+
}
|
|
551
|
+
.copy-btn:hover{background:#2a2a32;color:#f0f0f2}
|
|
552
|
+
.copy-btn.copied{background:rgba(129,140,248,.15);border-color:rgba(129,140,248,.3);color:#818cf8}
|
|
553
|
+
|
|
554
|
+
/* --- Platform tabs --- */
|
|
555
|
+
.tab-bar{display:flex;gap:2px;margin-bottom:0;overflow-x:auto}
|
|
556
|
+
.tab-btn{
|
|
557
|
+
background:#141418;border:1px solid #2a2a32;border-bottom:none;
|
|
558
|
+
border-radius:10px 10px 0 0;padding:12px 20px;
|
|
559
|
+
font-size:12px;font-weight:600;color:#5a5a66;
|
|
560
|
+
cursor:pointer;white-space:nowrap;transition:all .15s;
|
|
561
|
+
}
|
|
562
|
+
.tab-btn:hover{color:#8b8b96;background:#1c1c22}
|
|
563
|
+
.tab-btn.active{background:#141418;color:#f0f0f2;border-color:#2a2a32;border-bottom-color:#141418}
|
|
564
|
+
.tab-panel{display:none;background:#141418;border:1px solid #2a2a32;border-radius:0 10px 10px 10px;padding:28px}
|
|
565
|
+
.tab-panel.active{display:block}
|
|
566
|
+
.tab-panel h3{font-size:16px;font-weight:600;color:#f0f0f2;margin-bottom:14px;letter-spacing:-.01em}
|
|
567
|
+
.tab-panel p,.tab-panel li{font-size:14px;color:#8b8b96;line-height:1.7}
|
|
568
|
+
.tab-panel ol,.tab-panel ul{padding-left:20px;margin-bottom:18px}
|
|
569
|
+
.tab-panel li{margin-bottom:6px}
|
|
570
|
+
.tab-panel li strong{color:#f0f0f2}
|
|
571
|
+
.tab-panel .tip{
|
|
572
|
+
background:rgba(129,140,248,.06);border:1px solid rgba(129,140,248,.12);
|
|
573
|
+
border-radius:8px;padding:14px 18px;font-size:13px;color:#a5b4fc;line-height:1.6;margin-top:16px;
|
|
574
|
+
}
|
|
575
|
+
.tab-panel .tip strong{color:#c7d2fe}
|
|
576
|
+
.tab-section-label{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:#5a5a66;margin:20px 0 10px}
|
|
577
|
+
|
|
578
|
+
/* --- Comparison cards --- */
|
|
579
|
+
.comp-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
|
|
580
|
+
@media(max-width:640px){.comp-grid{grid-template-columns:1fr}}
|
|
581
|
+
.comp-card{border-radius:12px;overflow:hidden;border:1px solid #2a2a32}
|
|
582
|
+
.comp-card-brand{border-color:rgba(129,140,248,.3);background:#141418}
|
|
583
|
+
.comp-card-generic{background:#111114;border-color:#1c1c22}
|
|
584
|
+
.comp-card-header{
|
|
585
|
+
padding:14px 20px;font-size:12px;font-weight:700;text-transform:uppercase;
|
|
586
|
+
letter-spacing:.08em;display:flex;align-items:center;gap:8px;
|
|
587
|
+
border-bottom:1px solid #2a2a32;
|
|
588
|
+
}
|
|
589
|
+
.comp-card-brand .comp-card-header{color:#818cf8;border-color:rgba(129,140,248,.15)}
|
|
590
|
+
.comp-card-generic .comp-card-header{color:#5a5a66;border-color:#1c1c22}
|
|
591
|
+
.comp-card-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}
|
|
592
|
+
.comp-dot-brand{background:#818cf8}
|
|
593
|
+
.comp-dot-generic{background:#3a3a44}
|
|
594
|
+
.comp-card-body{padding:6px 0}
|
|
595
|
+
.comp-row{padding:12px 20px;display:flex;gap:12px;align-items:flex-start}
|
|
596
|
+
.comp-row:not(:last-child){border-bottom:1px solid rgba(42,42,50,.5)}
|
|
597
|
+
.comp-row-label{font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:#5a5a66;min-width:56px;padding-top:2px;flex-shrink:0}
|
|
598
|
+
.comp-row-value{font-size:13px;color:#f0f0f2;line-height:1.6}
|
|
599
|
+
.comp-generic-text{color:#5a5a66;font-style:italic}
|
|
600
|
+
.comp-swatch{display:inline-block;width:14px;height:14px;border-radius:4px;vertical-align:middle;margin-right:6px;border:1px solid #2a2a32}
|
|
601
|
+
.comp-logo-preview{max-width:120px;margin-bottom:8px}
|
|
602
|
+
.comp-logo-preview svg{width:100%;height:auto}
|
|
603
|
+
.comp-missing{color:#fbbf24;font-style:normal}
|
|
604
|
+
|
|
605
|
+
/* --- Session progression (horizontal timeline) --- */
|
|
606
|
+
.session-track{display:flex;flex-direction:column;gap:0}
|
|
607
|
+
.session-step{display:flex;gap:0;align-items:stretch}
|
|
608
|
+
.session-pip{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:32px}
|
|
609
|
+
.session-pip-inner{
|
|
610
|
+
width:28px;height:28px;border-radius:50%;
|
|
611
|
+
display:flex;align-items:center;justify-content:center;
|
|
612
|
+
font-size:11px;font-weight:700;flex-shrink:0;
|
|
613
|
+
}
|
|
614
|
+
.session-pip-done{background:rgba(129,140,248,.15);color:#818cf8}
|
|
615
|
+
.session-pip-upcoming{background:rgba(129,140,248,.1);color:#818cf8;border:2px solid rgba(129,140,248,.3)}
|
|
616
|
+
.session-pip-future{background:#1c1c22;color:#5a5a66}
|
|
617
|
+
.session-connector{flex:1;width:2px;background:#2a2a32;margin:4px auto;min-height:12px}
|
|
618
|
+
.session-connector-done{background:rgba(129,140,248,.25)}
|
|
619
|
+
.session-connector-none{flex:1;width:2px;background:transparent;margin:4px auto;min-height:0}
|
|
620
|
+
.session-content{padding:4px 0 20px 16px;flex:1}
|
|
621
|
+
.session-complete .session-name{color:#818cf8}
|
|
622
|
+
.session-next .session-name{color:#a5b4fc}
|
|
623
|
+
.session-future .session-name{color:#5a5a66}
|
|
624
|
+
.session-name{font-size:14px;font-weight:600;margin-bottom:4px}
|
|
625
|
+
.session-desc{font-size:13px;color:#5a5a66;line-height:1.6}
|
|
626
|
+
|
|
627
|
+
/* --- Fix section --- */
|
|
628
|
+
.fix-grid{display:flex;flex-direction:column;gap:16px}
|
|
629
|
+
.fix-card{background:#141418;border:1px solid #2a2a32;border-radius:12px;padding:24px;transition:border-color .15s}
|
|
630
|
+
.fix-card:hover{border-color:#3a3a44}
|
|
631
|
+
.fix-card-title{font-size:14px;font-weight:600;color:#f0f0f2;margin-bottom:4px}
|
|
632
|
+
.fix-card-desc{font-size:13px;color:#5a5a66;line-height:1.6;margin-bottom:14px}
|
|
633
|
+
|
|
634
|
+
/* --- Footer --- */
|
|
635
|
+
footer{
|
|
636
|
+
border-top:1px solid #2a2a32;padding-top:32px;margin-top:16px;
|
|
637
|
+
font-size:12px;color:#3a3a44;line-height:1.7;
|
|
638
|
+
display:flex;flex-wrap:wrap;gap:8px;align-items:center;
|
|
639
|
+
}
|
|
640
|
+
footer a{color:#818cf8;text-decoration:none;font-weight:600;transition:color .15s}
|
|
641
|
+
footer a:hover{color:#a5b4fc}
|
|
642
|
+
footer .footer-sep{color:#2a2a32}
|
|
643
|
+
</style>
|
|
644
|
+
</head>
|
|
645
|
+
<body>
|
|
646
|
+
|
|
647
|
+
<header>
|
|
648
|
+
<div class="overline">brandsystem.app</div>
|
|
649
|
+
<h1>${clientName}</h1>
|
|
650
|
+
<div class="subtitle">${config.website_url ? `${escapeHtml(config.website_url)}` : "Manual entry"}${config.industry ? ` • ${escapeHtml(config.industry)}` : ""}</div>
|
|
651
|
+
<div class="audit-line">
|
|
652
|
+
<span class="audit-pill audit-pill-pass"><strong>${auditSummary.pass}</strong> pass</span>
|
|
653
|
+
<span class="audit-pill">${auditSummary.warn} warn</span>
|
|
654
|
+
<span class="audit-pill">${auditSummary.fail} fail</span>
|
|
655
|
+
<span class="audit-pill">${tokenCount} tokens</span>
|
|
656
|
+
<span class="audit-pill">${clarifications.length} to clarify</span>
|
|
657
|
+
</div>
|
|
658
|
+
</header>
|
|
659
|
+
|
|
660
|
+
<div class="portable-notice">
|
|
661
|
+
<strong>This document is portable.</strong> Upload it to any AI conversation and say
|
|
662
|
+
“Use this as my brand guidelines for all visual output.”
|
|
663
|
+
Logos are embedded as vectors — no external files needed.
|
|
664
|
+
</div>
|
|
665
|
+
|
|
666
|
+
${buildSessionProgression()}
|
|
667
|
+
|
|
668
|
+
<section>
|
|
669
|
+
<h2>Logo</h2>
|
|
670
|
+
${buildLogoSection(identity)}
|
|
671
|
+
</section>
|
|
672
|
+
|
|
673
|
+
<section>
|
|
674
|
+
<h2>Colors — ${identity.colors.length} extracted</h2>
|
|
675
|
+
<div class="color-grid">
|
|
676
|
+
${buildColorCards(identity)}
|
|
677
|
+
</div>
|
|
678
|
+
</section>
|
|
679
|
+
|
|
680
|
+
<section>
|
|
681
|
+
<h2>Typography — ${identity.typography.length} font${identity.typography.length !== 1 ? "s" : ""}</h2>
|
|
682
|
+
<div class="font-list">
|
|
683
|
+
${buildFontCards(identity)}
|
|
684
|
+
</div>
|
|
685
|
+
</section>
|
|
686
|
+
|
|
687
|
+
<section>
|
|
688
|
+
<h2>Quick Reference</h2>
|
|
689
|
+
${buildUsageSection(identity)}
|
|
690
|
+
</section>
|
|
691
|
+
|
|
692
|
+
${buildComparisonSection(config, identity)}
|
|
693
|
+
|
|
694
|
+
${buildClarifications(clarifications)}
|
|
695
|
+
|
|
696
|
+
<!-- USE YOUR BRAND — Platform Tabs -->
|
|
697
|
+
<section>
|
|
698
|
+
<h2>Use Your Brand</h2>
|
|
699
|
+
<div class="tab-bar">
|
|
700
|
+
<button class="tab-btn active" data-tab="claude">Claude</button>
|
|
701
|
+
<button class="tab-btn" data-tab="chatgpt">ChatGPT</button>
|
|
702
|
+
<button class="tab-btn" data-tab="gemini">Gemini</button>
|
|
703
|
+
<button class="tab-btn" data-tab="code">Coding Tools</button>
|
|
704
|
+
</div>
|
|
705
|
+
|
|
706
|
+
<!-- CLAUDE -->
|
|
707
|
+
<div class="tab-panel active" id="tab-claude">
|
|
708
|
+
<h3>Set up in Claude</h3>
|
|
709
|
+
<ol>
|
|
710
|
+
<li>Go to <strong>claude.ai</strong> and create a new <strong>Project</strong></li>
|
|
711
|
+
<li>Open the project, then click <strong>Project knowledge</strong> in the sidebar</li>
|
|
712
|
+
<li>Upload this HTML file as a knowledge source — Claude will read it directly</li>
|
|
713
|
+
<li>In <strong>Project instructions</strong>, paste the prompt below</li>
|
|
714
|
+
</ol>
|
|
715
|
+
<div class="tab-section-label">Paste into Project Instructions</div>
|
|
716
|
+
<div class="copy-wrap" id="copy-claude">
|
|
717
|
+
<button class="copy-btn" onclick="copyBlock('copy-claude')">Copy</button>
|
|
718
|
+
<pre><code>You have access to the ${clientName} brand identity report in this project's knowledge.
|
|
719
|
+
|
|
720
|
+
For ALL visual output — HTML artifacts, SVG graphics, diagrams, mockups — apply the brand:
|
|
721
|
+
- Use the exact SVG logo from the report. Never type the company name in a font.
|
|
722
|
+
- Use the exact hex color values. Primary is for CTAs and emphasis.
|
|
723
|
+
- Reference the brand fonts by name in CSS font-family declarations.
|
|
724
|
+
- For dark backgrounds, invert the logo fills to #ffffff.
|
|
725
|
+
|
|
726
|
+
When generating any visual artifact, load the brand report first and follow its color, typography, and logo specifications exactly.</code></pre>
|
|
727
|
+
</div>
|
|
728
|
+
<div class="tip">
|
|
729
|
+
<strong>Pro tip:</strong> You can also create a <strong>Claude Skill</strong> that wraps these instructions,
|
|
730
|
+
so you can invoke it from any project with a slash command. In your project, look for
|
|
731
|
+
Skills in the sidebar to set one up.
|
|
732
|
+
</div>
|
|
733
|
+
</div>
|
|
734
|
+
|
|
735
|
+
<!-- CHATGPT -->
|
|
736
|
+
<div class="tab-panel" id="tab-chatgpt">
|
|
737
|
+
<h3>Set up in ChatGPT</h3>
|
|
738
|
+
<ol>
|
|
739
|
+
<li>Go to <strong>Explore GPTs</strong> → <strong>Create</strong></li>
|
|
740
|
+
<li>Name it <strong>“${clientName} Brand Assistant”</strong></li>
|
|
741
|
+
<li>Upload this HTML file under <strong>Knowledge</strong></li>
|
|
742
|
+
<li>Paste the prompt below into <strong>Instructions</strong></li>
|
|
743
|
+
<li>Save — now you have a branded GPT</li>
|
|
744
|
+
</ol>
|
|
745
|
+
<div class="tab-section-label">Paste into GPT Instructions</div>
|
|
746
|
+
<div class="copy-wrap" id="copy-chatgpt">
|
|
747
|
+
<button class="copy-btn" onclick="copyBlock('copy-chatgpt')">Copy</button>
|
|
748
|
+
<pre><code>You are the ${clientName} brand assistant. You have the brand identity report in your knowledge base.
|
|
749
|
+
|
|
750
|
+
For ALL visual output — HTML, SVG, code, mockups — you MUST:
|
|
751
|
+
- Use the exact SVG logo from the brand report. Never type "${clientName}" in a font.
|
|
752
|
+
- Use the exact hex colors from the report. Do not approximate.
|
|
753
|
+
- Use the brand font names in CSS font-family.
|
|
754
|
+
- For dark backgrounds, set logo path fills to #ffffff.
|
|
755
|
+
|
|
756
|
+
Before generating any visual content, reference the brand report and apply its specifications.</code></pre>
|
|
757
|
+
</div>
|
|
758
|
+
<div class="tip">
|
|
759
|
+
<strong>Alternative:</strong> Go to <strong>Settings → Personalization → Custom Instructions</strong>
|
|
760
|
+
to apply your brand across all conversations (character limit is tighter — skip the logo SVG and
|
|
761
|
+
focus on colors + fonts).
|
|
762
|
+
</div>
|
|
763
|
+
</div>
|
|
764
|
+
|
|
765
|
+
<!-- GEMINI -->
|
|
766
|
+
<div class="tab-panel" id="tab-gemini">
|
|
767
|
+
<h3>Set up in Gemini</h3>
|
|
768
|
+
<ol>
|
|
769
|
+
<li>Open <strong>Gemini</strong> and click <strong>Gem manager</strong> → <strong>New Gem</strong></li>
|
|
770
|
+
<li>Name it <strong>“${clientName} Brand”</strong></li>
|
|
771
|
+
<li>Paste the prompt below into the Gem’s instructions</li>
|
|
772
|
+
<li>Upload this HTML file if the Gem supports file attachments</li>
|
|
773
|
+
<li>Save the Gem</li>
|
|
774
|
+
</ol>
|
|
775
|
+
<div class="tab-section-label">Paste into Gem Instructions</div>
|
|
776
|
+
<div class="copy-wrap" id="copy-gemini">
|
|
777
|
+
<button class="copy-btn" onclick="copyBlock('copy-gemini')">Copy</button>
|
|
778
|
+
<pre><code>You are a brand-compliant design assistant for ${clientName}.
|
|
779
|
+
|
|
780
|
+
Apply these brand specifications to all visual output:
|
|
781
|
+
|
|
782
|
+
${brandInstructions}</code></pre>
|
|
783
|
+
</div>
|
|
784
|
+
</div>
|
|
785
|
+
|
|
786
|
+
<!-- CODING TOOLS -->
|
|
787
|
+
<div class="tab-panel" id="tab-code">
|
|
788
|
+
<h3>Set up in your coding tool</h3>
|
|
789
|
+
<p style="margin-bottom:18px">
|
|
790
|
+
For production-grade brand compliance, install the <strong>brandsystem MCP server</strong>.
|
|
791
|
+
It gives your coding tool direct access to your brand identity — logo vectors, exact colors,
|
|
792
|
+
font families — at the moment of creation.
|
|
793
|
+
</p>
|
|
794
|
+
|
|
795
|
+
<div class="tab-section-label">Step 1 — Add the MCP server</div>
|
|
796
|
+
<div class="copy-wrap" id="copy-mcp">
|
|
797
|
+
<button class="copy-btn" onclick="copyBlock('copy-mcp')">Copy</button>
|
|
798
|
+
<pre><code>${escapeHtml(mcpConfig)}</code></pre>
|
|
799
|
+
</div>
|
|
800
|
+
<ul style="margin-bottom:18px">
|
|
801
|
+
<li><strong>Claude Code</strong> — save as <code>.mcp.json</code> in your project root</li>
|
|
802
|
+
<li><strong>Cursor</strong> — save as <code>.cursor/mcp.json</code></li>
|
|
803
|
+
<li><strong>Windsurf</strong> — add to Windsurf MCP settings</li>
|
|
804
|
+
</ul>
|
|
805
|
+
|
|
806
|
+
<div class="tab-section-label">Step 2 — Upload this report + paste the prompt</div>
|
|
807
|
+
<p>Upload this HTML file to your project, restart your editor, then paste:</p>
|
|
808
|
+
<div class="copy-wrap" id="copy-code-prompt">
|
|
809
|
+
<button class="copy-btn" onclick="copyBlock('copy-code-prompt')">Copy</button>
|
|
810
|
+
<pre><code>I've uploaded my brand identity report (brand-report.html) from brandsystem.app. The basic brand extraction (colors, fonts, logo) is already done — this report has everything from the initial web scan.
|
|
811
|
+
|
|
812
|
+
Before we start, check if the brandsystem MCP server is available by looking for brand_status in your tools. If it's not there, help me install it:
|
|
813
|
+
- For Claude Code: create a .mcp.json file in the project root with the brandsystem server config (command: "npx", args: ["@brandsystem/mcp"])
|
|
814
|
+
- For Cursor: create .cursor/mcp.json with the same config
|
|
815
|
+
- Then restart so the MCP loads
|
|
816
|
+
|
|
817
|
+
Once the MCP is available:
|
|
818
|
+
1. Run brand_init with client name "${clientName}"${config.website_url ? ` and website "${escapeHtml(config.website_url)}"` : ""}
|
|
819
|
+
2. Import the existing identity from the uploaded brand report — don't re-scan the website, the basics are already captured
|
|
820
|
+
3. Then let's go deeper — Figma extraction for higher-accuracy colors, the full logo set, and typography weights</code></pre>
|
|
821
|
+
</div>
|
|
822
|
+
|
|
823
|
+
<div class="tip">
|
|
824
|
+
<strong>What this unlocks:</strong> The MCP server gives your coding tool direct access to your brand
|
|
825
|
+
identity at the moment of creation. It supports Figma extraction (higher accuracy than web),
|
|
826
|
+
design token compilation (DTCG format), brand auditing, and preflight checks.
|
|
827
|
+
No more copy-pasting hex values — the brand is just <em>there</em>.
|
|
828
|
+
</div>
|
|
829
|
+
|
|
830
|
+
<div class="tip" style="margin-top:8px">
|
|
831
|
+
<strong>Alternative:</strong> Skip the MCP and just upload this HTML file to your project. Add this to
|
|
832
|
+
your <code>CLAUDE.md</code>, <code>.cursorrules</code>, or project rules:
|
|
833
|
+
</div>
|
|
834
|
+
<div class="copy-wrap" id="copy-rules-line" style="margin-top:8px">
|
|
835
|
+
<button class="copy-btn" onclick="copyBlock('copy-rules-line')">Copy</button>
|
|
836
|
+
<pre><code>Use the brand identity in brand-report.html for all visual output. Use the inline SVG for the logo — never type the company name in a font. Use exact hex values from the report for all colors.</code></pre>
|
|
837
|
+
</div>
|
|
838
|
+
</div>
|
|
839
|
+
</section>
|
|
840
|
+
|
|
841
|
+
<!-- SOMETHING LOOK WRONG? -->
|
|
842
|
+
<section>
|
|
843
|
+
<h2>Something Look Wrong?</h2>
|
|
844
|
+
<p class="section-intro">
|
|
845
|
+
Go back to your AI chat and paste one of these prompts to fix what’s off.
|
|
846
|
+
</p>
|
|
847
|
+
<div class="fix-grid">
|
|
848
|
+
|
|
849
|
+
<div class="fix-card">
|
|
850
|
+
<div class="fix-card-title">Connect to Figma</div>
|
|
851
|
+
<div class="fix-card-desc">Extract logo, colors, and typography directly from your design file (highest accuracy)</div>
|
|
852
|
+
<div class="copy-wrap" id="copy-fix-figma">
|
|
853
|
+
<button class="copy-btn" onclick="copyBlock('copy-fix-figma')">Copy</button>
|
|
854
|
+
<pre><code>I have a Figma file with my brand's design system. Can you walk me through connecting to it to extract our exact colors, typography, and logo? The web extraction got close but I need higher accuracy from the source design file.</code></pre>
|
|
855
|
+
</div>
|
|
856
|
+
</div>
|
|
857
|
+
|
|
858
|
+
<div class="fix-card">
|
|
859
|
+
<div class="fix-card-title">Upload brand guidelines</div>
|
|
860
|
+
<div class="fix-card-desc">Share your brand guidelines PDF or document for accurate extraction</div>
|
|
861
|
+
<div class="copy-wrap" id="copy-fix-guidelines">
|
|
862
|
+
<button class="copy-btn" onclick="copyBlock('copy-fix-guidelines')">Copy</button>
|
|
863
|
+
<pre><code>I'm uploading our brand guidelines document. Please extract the correct colors (with their roles — primary, secondary, accent, etc.), typography (font families, weights, and usage), and any logo specifications. Compare what you find against the brand report I set up earlier and tell me what needs to be corrected.</code></pre>
|
|
864
|
+
</div>
|
|
865
|
+
</div>
|
|
866
|
+
|
|
867
|
+
<div class="fix-card">
|
|
868
|
+
<div class="fix-card-title">Upload an on-brand asset</div>
|
|
869
|
+
<div class="fix-card-desc">Share a file you know is correct and we’ll sample from it</div>
|
|
870
|
+
<div class="copy-wrap" id="copy-fix-asset">
|
|
871
|
+
<button class="copy-btn" onclick="copyBlock('copy-fix-asset')">Copy</button>
|
|
872
|
+
<pre><code>I'm uploading a file that I know is on-brand (it was approved by our design team). Please sample the colors, fonts, and any logo usage from it and compare against the brand report I set up. Update the brand identity with any corrections you find.</code></pre>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<div class="fix-card">
|
|
877
|
+
<div class="fix-card-title">Send to your design team</div>
|
|
878
|
+
<div class="fix-card-desc">Forward this report for review — they can send back corrections</div>
|
|
879
|
+
<div class="copy-wrap" id="copy-fix-team">
|
|
880
|
+
<button class="copy-btn" onclick="copyBlock('copy-fix-team')">Copy</button>
|
|
881
|
+
<pre><code>Can you draft a short message I can send to our design team? I need them to review this brand identity report and tell me:
|
|
882
|
+
1. Are the colors correct? What are the actual hex values and roles (primary, secondary, accent)?
|
|
883
|
+
2. Are the fonts correct? What are the exact family names and weights?
|
|
884
|
+
3. Can they send me the logo as an SVG file?
|
|
885
|
+
4. Anything else that's wrong or missing?</code></pre>
|
|
886
|
+
</div>
|
|
887
|
+
</div>
|
|
888
|
+
|
|
889
|
+
<div class="fix-card">
|
|
890
|
+
<div class="fix-card-title">Scan a different page</div>
|
|
891
|
+
<div class="fix-card-desc">If this wasn’t your main brand page, try a different URL</div>
|
|
892
|
+
<div class="copy-wrap" id="copy-fix-rescan">
|
|
893
|
+
<button class="copy-btn" onclick="copyBlock('copy-fix-rescan')">Copy</button>
|
|
894
|
+
<pre><code>The brand extraction didn't get the right results from that URL. Let's try scanning a different page — I think [PASTE YOUR URL HERE] would be a better source for our brand colors and logo. Please re-run the extraction and update the report.</code></pre>
|
|
895
|
+
</div>
|
|
896
|
+
</div>
|
|
897
|
+
|
|
898
|
+
</div>
|
|
899
|
+
</section>
|
|
900
|
+
|
|
901
|
+
<footer>
|
|
902
|
+
<span>Generated by</span>
|
|
903
|
+
<a href="https://brandsystem.app">brandsystem.app</a>
|
|
904
|
+
<span class="footer-sep">•</span>
|
|
905
|
+
<span>v0.1.0</span>
|
|
906
|
+
<span class="footer-sep">•</span>
|
|
907
|
+
<span>${new Date().toISOString().split("T")[0]}</span>
|
|
908
|
+
<span class="footer-sep">•</span>
|
|
909
|
+
<span>Audit: ${overall} (${auditSummary.pass}/${auditSummary.warn}/${auditSummary.fail})</span>
|
|
910
|
+
</footer>
|
|
911
|
+
|
|
912
|
+
<script>
|
|
913
|
+
// Tab switching
|
|
914
|
+
document.querySelectorAll('.tab-btn').forEach(btn => {
|
|
915
|
+
btn.addEventListener('click', () => {
|
|
916
|
+
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
917
|
+
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
|
918
|
+
btn.classList.add('active');
|
|
919
|
+
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
|
|
920
|
+
});
|
|
921
|
+
});
|
|
922
|
+
|
|
923
|
+
// Click to copy
|
|
924
|
+
function copyBlock(wrapperId) {
|
|
925
|
+
const wrap = document.getElementById(wrapperId);
|
|
926
|
+
const code = wrap.querySelector('code');
|
|
927
|
+
const btn = wrap.querySelector('.copy-btn');
|
|
928
|
+
navigator.clipboard.writeText(code.textContent).then(() => {
|
|
929
|
+
btn.textContent = 'Copied!';
|
|
930
|
+
btn.classList.add('copied');
|
|
931
|
+
setTimeout(() => { btn.textContent = 'Copy'; btn.classList.remove('copied'); }, 2000);
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
</script>
|
|
935
|
+
</body>
|
|
936
|
+
</html>`;
|
|
937
|
+
}
|
|
938
|
+
//# sourceMappingURL=report-html.js.map
|