@praecipio/brand 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # @praecipio/brand
2
+
3
+ The Praecipio brand as a typed, tested library — palette, tint/shade ladders,
4
+ typography, logo rules, icon recipe, and voice, decompiled from Brand Style
5
+ Guide v2.01. Products import this package instead of copy-pasting hex values,
6
+ so every surface stays consistent and updates with a version bump.
7
+
8
+ ## Install
9
+
10
+ Public on npmjs.org — no registry setup, no auth:
11
+
12
+ ```sh
13
+ npm install @praecipio/brand # or pnpm add / yarn add
14
+ ```
15
+
16
+ The package ships tokens, rules, components, and generated CSS only. The
17
+ licensed assets (Freight Sans Pro / FA5 Pro font files, stock photography)
18
+ are not in it — font stacks ship as names, and the repo stays private.
19
+
20
+ ## Use
21
+
22
+ ```ts
23
+ // Typed tokens, ladders, and rules
24
+ import { palette, prime, primeLadder, contrast, luminance } from '@praecipio/brand';
25
+
26
+ primeLadder('orange').tints; // guide p.20, exactly
27
+ contrast('#C84F09', '#FFFFFF'); // the rules ship as functions
28
+ ```
29
+
30
+ ```css
31
+ /* CSS custom properties — every palette color + ladder as --praecipio-* */
32
+ @import '@praecipio/brand/css';
33
+
34
+ .cta { background: var(--praecipio-prime-orange); }
35
+ ```
36
+
37
+ ```tsx
38
+ // React components (react >= 18 is an optional peer dependency)
39
+ import { SwatchGrid, Combinator } from '@praecipio/brand/react';
40
+ ```
41
+
42
+ Other subpaths: `@praecipio/brand/tokens.json` (machine-readable palette),
43
+ `@praecipio/brand/mkdocs.css` (one-file MkDocs Material branding), and
44
+ `@praecipio/brand/hubspot/*` (HubSpot theme `fields.json` + a HubL stylesheet
45
+ exposing the same `--praecipio-*` variables — `make hubspot` regenerates,
46
+ `make hubspot-upload` pushes to the design manager).
47
+
48
+ ## Rules, not guidelines
49
+
50
+ Usage rules from the guide are executable: contrast assertions, colorway
51
+ restrictions (black/white logos are print-only), ≥60% primary coverage,
52
+ no gradients. Import them — don't re-derive them.
53
+
54
+ CMYK values carry no process/ICC spec (`CMYK_INTENT`); treat print output
55
+ as unspecified pending a ruling.
56
+
57
+ ## Versioning
58
+
59
+ Versioned with the repo's tagged releases ("Praecipio Brand x.y.z"). The
60
+ package, the portal, and the release asset bundles are all built from the
61
+ same source at the same tag.
@@ -0,0 +1,192 @@
1
+ // src/color.ts
2
+ var CMYK_INTENT = "as published (guide v2.01, 2024) \u2014 process/ICC/substrate unspecified; needs a print-spec ruling";
3
+ var c = (name, tier, hex, cmyk, pantone) => ({ name, tier, hex, rgb: hexToRgb(hex), cmyk, pantone });
4
+ var prime = {
5
+ orange: c("orange", "prime", "#C84F09", [16, 81, 100, 5], "718 C"),
6
+ teal: c("teal", "prime", "#054950", [92, 56, 55, 38], "7476 C"),
7
+ maroon: c("maroon", "prime", "#6A1933", [38, 95, 61, 44], "7421 C"),
8
+ navy: c("navy", "prime", "#2B3F60", [90, 76, 38, 27], "534 C")
9
+ };
10
+ var accent = {
11
+ peach: c("peach", "accent", "#FFBE7A", [0, 29, 58, 0], "149 C"),
12
+ mint: c("mint", "accent", "#92E5B7", [40, 0, 38, 0], "352 C"),
13
+ lavender: c("lavender", "accent", "#B699E1", [29, 41, 0, 0], "2645 C"),
14
+ cyan: c("cyan", "accent", "#39D3D3", [61, 0, 24, 0], "325 C"),
15
+ coral: c("coral", "accent", "#DD7B6C", [16, 63, 55, 0], "7607 C"),
16
+ steel: c("steel", "accent", "#6EABB3", [58, 18, 28, 0], "7709 C"),
17
+ mauve: c("mauve", "accent", "#A4809C", [38, 53, 22, 0], "5145 C"),
18
+ slate: c("slate", "accent", "#4F8299", [75, 40, 30, 0], "7697 C")
19
+ };
20
+ var neutral = {
21
+ black: c("black", "neutral", "#000000", [20, 20, 20, 100], "Neutral Black C"),
22
+ ink: c("ink", "neutral", "#332E27", [0, 8, 18, 94], "Black C"),
23
+ "gray-dark": c("gray-dark", "neutral", "#7A6E67", [15, 24, 28, 53], "Warm Gray 10 C"),
24
+ gray: c("gray", "neutral", "#9E968D", [40, 36, 42, 2], "Black 0961 C"),
25
+ "gray-light": c("gray-light", "neutral", "#C5B9AC", [23, 24, 30, 0], "7528 C"),
26
+ "gray-faint": c("gray-faint", "neutral", "#D6D1CA", [2, 3, 4, 5], "Warm Gray 1 C")
27
+ };
28
+ var palette = [
29
+ ...Object.values(prime),
30
+ ...Object.values(accent),
31
+ ...Object.values(neutral)
32
+ ];
33
+ function hexToRgb(hex) {
34
+ const m = /^#?([0-9a-f]{6})$/i.exec(hex);
35
+ if (!m) throw new Error(`invalid hex color: ${hex}`);
36
+ const n = parseInt(m[1], 16);
37
+ return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
38
+ }
39
+ function rgbToHex({ r, g, b }) {
40
+ const h = (v) => Math.round(v).toString(16).padStart(2, "0").toUpperCase();
41
+ return `#${h(r)}${h(g)}${h(b)}`;
42
+ }
43
+ var TINT_STEPS = [0.1, 0.2, 0.3, 0.4];
44
+ var shadeFactors = {
45
+ orange: [0.8, 0.6, 0.4, 0.2],
46
+ teal: [0.9, 0.8, 0.7, 0.5],
47
+ maroon: [0.9, 0.8, 0.7, 0.6],
48
+ navy: [0.9, 0.8, 0.7, 0.6]
49
+ };
50
+ function ladder(hex, shades = [0.8, 0.6, 0.4, 0.2]) {
51
+ const { r, g, b } = hexToRgb(hex);
52
+ const tint = (k) => rgbToHex({ r: r + (255 - r) * k, g: g + (255 - g) * k, b: b + (255 - b) * k });
53
+ const shade = (k) => rgbToHex({ r: r * k, g: g * k, b: b * k });
54
+ return {
55
+ base: rgbToHex({ r, g, b }),
56
+ tints: TINT_STEPS.map(tint),
57
+ shades: shades.map(shade)
58
+ };
59
+ }
60
+ function primeLadder(name) {
61
+ return ladder(prime[name].hex, shadeFactors[name]);
62
+ }
63
+
64
+ // src/rules.ts
65
+ var MIN_LOGO_WIDTH_PX = 80;
66
+ var MIN_PRIMARY_COVERAGE = 0.6;
67
+ function luminance(color) {
68
+ const { r, g, b } = typeof color === "string" ? hexToRgb(color) : color;
69
+ const lin = (v) => {
70
+ const s = v / 255;
71
+ return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
72
+ };
73
+ return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
74
+ }
75
+ function contrast(a, b) {
76
+ const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
77
+ return (hi + 0.05) / (lo + 0.05);
78
+ }
79
+ function isAllowedTextOnWhite(hex) {
80
+ const accentHexes = new Set(Object.values(accent).map((c2) => c2.hex));
81
+ return !accentHexes.has(hex.toUpperCase());
82
+ }
83
+ var GRADIENTS_ALLOWED = false;
84
+ var MAX_PATTERN_OPACITY = 0.15;
85
+
86
+ // src/typography.ts
87
+ var fonts = {
88
+ heading: {
89
+ family: "Freight Sans Pro",
90
+ fallback: "'Nunito Sans', system-ui, sans-serif",
91
+ role: "heading",
92
+ license: "commercial (Adobe Fonts / GarageFonts) \u2014 private use only"
93
+ },
94
+ body: {
95
+ family: "Nunito Sans",
96
+ fallback: "system-ui, sans-serif",
97
+ role: "body",
98
+ license: "OFL 1.1"
99
+ }
100
+ };
101
+ var fontStack = (role) => `'${fonts[role].family}', ${fonts[role].fallback}`;
102
+ var typeSpecs = {
103
+ heading: ["Black 11/14", "Bold 11/14", "Semibold 11/14"],
104
+ body: ["Bold 10/14", "Regular 10/14", "Italic 10/14"]
105
+ };
106
+
107
+ // src/logo.ts
108
+ var orientations = {
109
+ hori: "Horizontal \u2014 the primary orientation; use when in doubt",
110
+ verti: "Vertical (stacked) \u2014 avoid at small sizes; can become illegible",
111
+ "verti-sm": "Vertical small \u2014 stacked variant tuned for smaller sizes",
112
+ logomark: "Logomark \u2014 the P icon; supportive, used alongside the full logo"
113
+ };
114
+ var colorways = {
115
+ rgb: { visual: "primary", use: "digital" },
116
+ cmyk: { visual: "primary", use: "print (process)" },
117
+ pms: { visual: "primary", use: "print (spot / Pantone)" },
118
+ "reverse-rgb": { visual: "reverse", use: "digital, on dark backgrounds" },
119
+ "reverse-cmyk": { visual: "reverse", use: "print (process), on dark backgrounds" },
120
+ "reverse-pms": { visual: "reverse", use: "print (spot), on dark backgrounds" },
121
+ black: { visual: "black", use: "one-color print, screen print, embossing, engraving \u2014 never digital" },
122
+ white: { visual: "white", use: "one-color print, screen print, embossing, engraving \u2014 never digital" }
123
+ };
124
+ var canonicalColorway = {
125
+ primary: "rgb",
126
+ reverse: "reverse-rgb",
127
+ black: "black",
128
+ white: "white"
129
+ };
130
+ var logoDoNots = [
131
+ "Do not use a one-color overlay on digital assets",
132
+ "Do not use unapproved color combinations",
133
+ "Do not add a drop shadow",
134
+ "Do not warp or skew the logo",
135
+ "Do not overlay the logo on complicated or busy backgrounds",
136
+ "Do not crop the logo",
137
+ "Do not outline the logo",
138
+ "Do not change the color of the line 'P' inside the logomark",
139
+ "Do not rotate or set the logo at an angle",
140
+ "Do not overlay complicated effects, like bevel or emboss, to a logo",
141
+ "Do not change the opacity of the logo",
142
+ "Do not recreate using any other typefaces",
143
+ "Do not change the integrity of the logo"
144
+ ];
145
+ var logomarkUsage = "Place the logomark discreetly in the corner of assets, always after or in conjunction with the full Praecipio logotype. It is not a replacement for the official logo. Do not alter it \u2014 use the official file.";
146
+ var clearspace = "logomark height on all sides";
147
+
148
+ // src/icons.ts
149
+ var iconRecipe = {
150
+ library: "Google Material Symbols",
151
+ style: "Rounded",
152
+ fill: 0,
153
+ weight: 400,
154
+ grade: 0,
155
+ opticalSize: 40,
156
+ lineColors: ["black", "white"],
157
+ chipColors: "any prime or accent color from the palette"
158
+ };
159
+ var iconUsage = "Icons are supportive symbols \u2014 never the main imagery. Use them in conjunction with text: bullet points, check marks, accompanying labels.";
160
+
161
+ export {
162
+ CMYK_INTENT,
163
+ prime,
164
+ accent,
165
+ neutral,
166
+ palette,
167
+ hexToRgb,
168
+ rgbToHex,
169
+ TINT_STEPS,
170
+ shadeFactors,
171
+ ladder,
172
+ primeLadder,
173
+ MIN_LOGO_WIDTH_PX,
174
+ MIN_PRIMARY_COVERAGE,
175
+ luminance,
176
+ contrast,
177
+ isAllowedTextOnWhite,
178
+ GRADIENTS_ALLOWED,
179
+ MAX_PATTERN_OPACITY,
180
+ fonts,
181
+ fontStack,
182
+ typeSpecs,
183
+ orientations,
184
+ colorways,
185
+ canonicalColorway,
186
+ logoDoNots,
187
+ logomarkUsage,
188
+ clearspace,
189
+ iconRecipe,
190
+ iconUsage
191
+ };
192
+ //# sourceMappingURL=chunk-A6WMWOXD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/color.ts","../src/rules.ts","../src/typography.ts","../src/logo.ts","../src/icons.ts"],"sourcesContent":["// Praecipio palette — Brand Style Guide v2.01 (2024-05-07), pp. 19–20.\n// Values cross-checked against docs/swatches/Praecipio-Color-Values.pdf and\n// the .ase swatch files. Canonical authority is the guide; the logo EPS\n// masters carry the retired legacy orange #C84220 and must not be trusted\n// for color.\n\nexport type Tier = 'prime' | 'accent' | 'neutral';\n\nexport interface Rgb {\n r: number;\n g: number;\n b: number;\n}\n\nexport interface BrandColor {\n name: string;\n tier: Tier;\n hex: string;\n rgb: Rgb;\n /**\n * CMYK percentages exactly as published in guide v2.01 / Color-Values PDF.\n * ⚠ Print intent is UNSPECIFIED — the guide names no process, ink standard\n * (SWOP/GRACoL/FOGRA), ICC profile, or substrate. Treat as reference\n * numbers, not press-ready separations; see CMYK_INTENT.\n */\n cmyk: [number, number, number, number];\n pantone: string;\n}\n\n/** Provenance caveat for all CMYK values in this palette. */\nexport const CMYK_INTENT =\n 'as published (guide v2.01, 2024) — process/ICC/substrate unspecified; needs a print-spec ruling';\n\nconst c = (\n name: string,\n tier: Tier,\n hex: string,\n cmyk: [number, number, number, number],\n pantone: string,\n): BrandColor => ({ name, tier, hex, rgb: hexToRgb(hex), cmyk, pantone });\n\nexport const prime = {\n orange: c('orange', 'prime', '#C84F09', [16, 81, 100, 5], '718 C'),\n teal: c('teal', 'prime', '#054950', [92, 56, 55, 38], '7476 C'),\n maroon: c('maroon', 'prime', '#6A1933', [38, 95, 61, 44], '7421 C'),\n navy: c('navy', 'prime', '#2B3F60', [90, 76, 38, 27], '534 C'),\n} as const;\n\nexport const accent = {\n peach: c('peach', 'accent', '#FFBE7A', [0, 29, 58, 0], '149 C'),\n mint: c('mint', 'accent', '#92E5B7', [40, 0, 38, 0], '352 C'),\n lavender: c('lavender', 'accent', '#B699E1', [29, 41, 0, 0], '2645 C'),\n cyan: c('cyan', 'accent', '#39D3D3', [61, 0, 24, 0], '325 C'),\n coral: c('coral', 'accent', '#DD7B6C', [16, 63, 55, 0], '7607 C'),\n steel: c('steel', 'accent', '#6EABB3', [58, 18, 28, 0], '7709 C'),\n mauve: c('mauve', 'accent', '#A4809C', [38, 53, 22, 0], '5145 C'),\n slate: c('slate', 'accent', '#4F8299', [75, 40, 30, 0], '7697 C'),\n} as const;\n\nexport const neutral = {\n black: c('black', 'neutral', '#000000', [20, 20, 20, 100], 'Neutral Black C'),\n ink: c('ink', 'neutral', '#332E27', [0, 8, 18, 94], 'Black C'),\n 'gray-dark': c('gray-dark', 'neutral', '#7A6E67', [15, 24, 28, 53], 'Warm Gray 10 C'),\n gray: c('gray', 'neutral', '#9E968D', [40, 36, 42, 2], 'Black 0961 C'),\n 'gray-light': c('gray-light', 'neutral', '#C5B9AC', [23, 24, 30, 0], '7528 C'),\n 'gray-faint': c('gray-faint', 'neutral', '#D6D1CA', [2, 3, 4, 5], 'Warm Gray 1 C'),\n} as const;\n\nexport const palette: readonly BrandColor[] = [\n ...Object.values(prime),\n ...Object.values(accent),\n ...Object.values(neutral),\n];\n\nexport function hexToRgb(hex: string): Rgb {\n const m = /^#?([0-9a-f]{6})$/i.exec(hex);\n if (!m) throw new Error(`invalid hex color: ${hex}`);\n const n = parseInt(m[1], 16);\n return { r: (n >> 16) & 0xff, g: (n >> 8) & 0xff, b: n & 0xff };\n}\n\nexport function rgbToHex({ r, g, b }: Rgb): string {\n const h = (v: number) => Math.round(v).toString(16).padStart(2, '0').toUpperCase();\n return `#${h(r)}${h(g)}${h(b)}`;\n}\n\n/**\n * Tint/shade ladder — guide p.20. Tints mix toward white at 10/20/30/40%\n * uniformly. Shade factors were hand-tuned per color (already-dark primes get\n * gentler steps), so they are data, not a formula. From the canonical hexes\n * this reproduces the guide's printed values exactly. (The historical .ase\n * ladder was computed from off-by-one base values — a drift this retires.)\n * Guide rule: marketing collateral always uses the primary colors; tints and\n * shades exist for depth via blending/opacity in digital work only.\n */\nexport interface Ladder {\n base: string;\n tints: string[]; // toward white: 10%, 20%, 30%, 40%\n shades: string[]; // multiples of base, per-color factors, darkest last\n}\n\nexport const TINT_STEPS = [0.1, 0.2, 0.3, 0.4] as const;\n\nexport const shadeFactors: Record<keyof typeof prime, readonly number[]> = {\n orange: [0.8, 0.6, 0.4, 0.2],\n teal: [0.9, 0.8, 0.7, 0.5],\n maroon: [0.9, 0.8, 0.7, 0.6],\n navy: [0.9, 0.8, 0.7, 0.6],\n};\n\nexport function ladder(hex: string, shades: readonly number[] = [0.8, 0.6, 0.4, 0.2]): Ladder {\n const { r, g, b } = hexToRgb(hex);\n const tint = (k: number) =>\n rgbToHex({ r: r + (255 - r) * k, g: g + (255 - g) * k, b: b + (255 - b) * k });\n const shade = (k: number) => rgbToHex({ r: r * k, g: g * k, b: b * k });\n return {\n base: rgbToHex({ r, g, b }),\n tints: TINT_STEPS.map(tint),\n shades: shades.map(shade),\n };\n}\n\n/** The four published prime ladders, exactly as printed in the guide. */\nexport function primeLadder(name: keyof typeof prime): Ladder {\n return ladder(prime[name].hex, shadeFactors[name]);\n}\n","// Executable usage rules — Brand Style Guide v2.01.\nimport { accent, hexToRgb, type Rgb } from './color.js';\n\n/** Guide p.13: minimum logo width is 0.8 in / 2.032 cm / 80 px. */\nexport const MIN_LOGO_WIDTH_PX = 80;\n\n/** Guide p.19: primary colors should comprise at least 60% of a graphic. */\nexport const MIN_PRIMARY_COVERAGE = 0.6;\n\n/** WCAG 2.x relative luminance. */\nexport function luminance(color: string | Rgb): number {\n const { r, g, b } = typeof color === 'string' ? hexToRgb(color) : color;\n const lin = (v: number) => {\n const s = v / 255;\n return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n };\n return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);\n}\n\n/** WCAG contrast ratio between two colors, >= 1. */\nexport function contrast(a: string, b: string): number {\n const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);\n return (hi + 0.05) / (lo + 0.05);\n}\n\n/**\n * Guide p.19: \"Accent colors should never be used on text against a white\n * background.\" White text on an accent background is allowed only for\n * heavy/bold fonts. This predicate encodes the first (hard) rule.\n */\nexport function isAllowedTextOnWhite(hex: string): boolean {\n const accentHexes = new Set(Object.values(accent).map((c) => c.hex));\n return !accentHexes.has(hex.toUpperCase());\n}\n\n/** Guide p.19: \"Do not create gradients with these colors.\" */\nexport const GRADIENTS_ALLOWED = false;\n\n/** Guide p.24: pattern overlays behind text cap at 15% opacity (multiply). */\nexport const MAX_PATTERN_OPACITY = 0.15;\n","// Typography — Brand Style Guide v2.01, pp. 16–17.\nexport interface FontRole {\n family: string;\n fallback: string;\n role: 'heading' | 'body';\n /** Licensing note — governs where the files may ship. */\n license: string;\n}\n\nexport const fonts = {\n heading: {\n family: 'Freight Sans Pro',\n fallback: \"'Nunito Sans', system-ui, sans-serif\",\n role: 'heading',\n license: 'commercial (Adobe Fonts / GarageFonts) — private use only',\n },\n body: {\n family: 'Nunito Sans',\n fallback: 'system-ui, sans-serif',\n role: 'body',\n license: 'OFL 1.1',\n },\n} as const satisfies Record<string, FontRole>;\n\nexport const fontStack = (role: keyof typeof fonts): string =>\n `'${fonts[role].family}', ${fonts[role].fallback}`;\n\n/** Published specimen specs: weight and size/leading per role. */\nexport const typeSpecs = {\n heading: ['Black 11/14', 'Bold 11/14', 'Semibold 11/14'],\n body: ['Bold 10/14', 'Regular 10/14', 'Italic 10/14'],\n} as const;\n","// Logo system — orientations, colorways, and usage rules.\nexport const orientations = {\n hori: 'Horizontal — the primary orientation; use when in doubt',\n verti: 'Vertical (stacked) — avoid at small sizes; can become illegible',\n 'verti-sm': 'Vertical small — stacked variant tuned for smaller sizes',\n logomark: 'Logomark — the P icon; supportive, used alongside the full logo',\n} as const;\n\nexport type VisualClass = 'primary' | 'reverse' | 'black' | 'white';\n\nexport interface Colorway {\n /** Which visually-distinct treatment this colorway renders as. */\n visual: VisualClass;\n use: string;\n}\n\nexport const colorways: Record<string, Colorway> = {\n rgb: { visual: 'primary', use: 'digital' },\n cmyk: { visual: 'primary', use: 'print (process)' },\n pms: { visual: 'primary', use: 'print (spot / Pantone)' },\n 'reverse-rgb': { visual: 'reverse', use: 'digital, on dark backgrounds' },\n 'reverse-cmyk': { visual: 'reverse', use: 'print (process), on dark backgrounds' },\n 'reverse-pms': { visual: 'reverse', use: 'print (spot), on dark backgrounds' },\n black: { visual: 'black', use: 'one-color print, screen print, embossing, engraving — never digital' },\n white: { visual: 'white', use: 'one-color print, screen print, embossing, engraving — never digital' },\n};\n\n/** Canonical colorway to display for each visually-distinct treatment. */\nexport const canonicalColorway: Record<VisualClass, string> = {\n primary: 'rgb',\n reverse: 'reverse-rgb',\n black: 'black',\n white: 'white',\n};\n\n/** Unacceptable usage — the complete list. */\nexport const logoDoNots = [\n 'Do not use a one-color overlay on digital assets',\n 'Do not use unapproved color combinations',\n 'Do not add a drop shadow',\n 'Do not warp or skew the logo',\n 'Do not overlay the logo on complicated or busy backgrounds',\n 'Do not crop the logo',\n 'Do not outline the logo',\n \"Do not change the color of the line 'P' inside the logomark\",\n 'Do not rotate or set the logo at an angle',\n 'Do not overlay complicated effects, like bevel or emboss, to a logo',\n 'Do not change the opacity of the logo',\n 'Do not recreate using any other typefaces',\n 'Do not change the integrity of the logo',\n] as const;\n\nexport const logomarkUsage =\n 'Place the logomark discreetly in the corner of assets, always after or in ' +\n 'conjunction with the full Praecipio logotype. It is not a replacement for ' +\n 'the official logo. Do not alter it — use the official file.';\n\n/** Clear space: keep the logomark-height padding free around the logo. */\nexport const clearspace = 'logomark height on all sides';\n","// Iconography recipe — the icon library is generated, not drawn.\nexport const iconRecipe = {\n library: 'Google Material Symbols',\n style: 'Rounded',\n fill: 0,\n weight: 400,\n grade: 0,\n opticalSize: 40,\n lineColors: ['black', 'white'] as const,\n chipColors: 'any prime or accent color from the palette',\n} as const;\n\nexport const iconUsage =\n 'Icons are supportive symbols — never the main imagery. Use them in ' +\n 'conjunction with text: bullet points, check marks, accompanying labels.';\n"],"mappings":"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","names":["c"]}
@@ -0,0 +1,14 @@
1
+ # Praecipio brand tokens for HubSpot
2
+
3
+ Generated by `@praecipio/brand` — regenerate with `make hubspot`, never edit.
4
+
5
+ - **`fields.json`** — drop the two groups into a theme's `fields.json`
6
+ (or merge into an existing one). The palette becomes page-editor color
7
+ fields, defaulted to canonical values.
8
+ - **`praecipio-tokens.hubl.css`** — include in the theme's CSS. It maps the
9
+ theme fields onto the same `--praecipio-*` custom properties every other
10
+ Praecipio build uses, so modules written against the tokens work unchanged
11
+ outside HubSpot (and vice versa).
12
+
13
+ Upload to the design manager with `make hubspot-upload` (requires
14
+ `HUBSPOT_PERSONAL_ACCESS_KEY` and `HUBSPOT_ACCOUNT_ID` in the environment).
@@ -0,0 +1,217 @@
1
+ [
2
+ {
3
+ "type": "group",
4
+ "name": "praecipio_colors",
5
+ "label": "Praecipio colors",
6
+ "help_text": "Canonical palette from @praecipio/brand — do not hand-edit values.",
7
+ "children": [
8
+ {
9
+ "type": "color",
10
+ "name": "prime_orange",
11
+ "label": "prime / orange",
12
+ "help_text": "#C84F09 · 718 C",
13
+ "default": {
14
+ "color": "#C84F09",
15
+ "opacity": 100
16
+ }
17
+ },
18
+ {
19
+ "type": "color",
20
+ "name": "prime_teal",
21
+ "label": "prime / teal",
22
+ "help_text": "#054950 · 7476 C",
23
+ "default": {
24
+ "color": "#054950",
25
+ "opacity": 100
26
+ }
27
+ },
28
+ {
29
+ "type": "color",
30
+ "name": "prime_maroon",
31
+ "label": "prime / maroon",
32
+ "help_text": "#6A1933 · 7421 C",
33
+ "default": {
34
+ "color": "#6A1933",
35
+ "opacity": 100
36
+ }
37
+ },
38
+ {
39
+ "type": "color",
40
+ "name": "prime_navy",
41
+ "label": "prime / navy",
42
+ "help_text": "#2B3F60 · 534 C",
43
+ "default": {
44
+ "color": "#2B3F60",
45
+ "opacity": 100
46
+ }
47
+ },
48
+ {
49
+ "type": "color",
50
+ "name": "accent_peach",
51
+ "label": "accent / peach",
52
+ "help_text": "#FFBE7A · 149 C",
53
+ "default": {
54
+ "color": "#FFBE7A",
55
+ "opacity": 100
56
+ }
57
+ },
58
+ {
59
+ "type": "color",
60
+ "name": "accent_mint",
61
+ "label": "accent / mint",
62
+ "help_text": "#92E5B7 · 352 C",
63
+ "default": {
64
+ "color": "#92E5B7",
65
+ "opacity": 100
66
+ }
67
+ },
68
+ {
69
+ "type": "color",
70
+ "name": "accent_lavender",
71
+ "label": "accent / lavender",
72
+ "help_text": "#B699E1 · 2645 C",
73
+ "default": {
74
+ "color": "#B699E1",
75
+ "opacity": 100
76
+ }
77
+ },
78
+ {
79
+ "type": "color",
80
+ "name": "accent_cyan",
81
+ "label": "accent / cyan",
82
+ "help_text": "#39D3D3 · 325 C",
83
+ "default": {
84
+ "color": "#39D3D3",
85
+ "opacity": 100
86
+ }
87
+ },
88
+ {
89
+ "type": "color",
90
+ "name": "accent_coral",
91
+ "label": "accent / coral",
92
+ "help_text": "#DD7B6C · 7607 C",
93
+ "default": {
94
+ "color": "#DD7B6C",
95
+ "opacity": 100
96
+ }
97
+ },
98
+ {
99
+ "type": "color",
100
+ "name": "accent_steel",
101
+ "label": "accent / steel",
102
+ "help_text": "#6EABB3 · 7709 C",
103
+ "default": {
104
+ "color": "#6EABB3",
105
+ "opacity": 100
106
+ }
107
+ },
108
+ {
109
+ "type": "color",
110
+ "name": "accent_mauve",
111
+ "label": "accent / mauve",
112
+ "help_text": "#A4809C · 5145 C",
113
+ "default": {
114
+ "color": "#A4809C",
115
+ "opacity": 100
116
+ }
117
+ },
118
+ {
119
+ "type": "color",
120
+ "name": "accent_slate",
121
+ "label": "accent / slate",
122
+ "help_text": "#4F8299 · 7697 C",
123
+ "default": {
124
+ "color": "#4F8299",
125
+ "opacity": 100
126
+ }
127
+ },
128
+ {
129
+ "type": "color",
130
+ "name": "neutral_black",
131
+ "label": "neutral / black",
132
+ "help_text": "#000000 · Neutral Black C",
133
+ "default": {
134
+ "color": "#000000",
135
+ "opacity": 100
136
+ }
137
+ },
138
+ {
139
+ "type": "color",
140
+ "name": "neutral_ink",
141
+ "label": "neutral / ink",
142
+ "help_text": "#332E27 · Black C",
143
+ "default": {
144
+ "color": "#332E27",
145
+ "opacity": 100
146
+ }
147
+ },
148
+ {
149
+ "type": "color",
150
+ "name": "neutral_gray_dark",
151
+ "label": "neutral / gray-dark",
152
+ "help_text": "#7A6E67 · Warm Gray 10 C",
153
+ "default": {
154
+ "color": "#7A6E67",
155
+ "opacity": 100
156
+ }
157
+ },
158
+ {
159
+ "type": "color",
160
+ "name": "neutral_gray",
161
+ "label": "neutral / gray",
162
+ "help_text": "#9E968D · Black 0961 C",
163
+ "default": {
164
+ "color": "#9E968D",
165
+ "opacity": 100
166
+ }
167
+ },
168
+ {
169
+ "type": "color",
170
+ "name": "neutral_gray_light",
171
+ "label": "neutral / gray-light",
172
+ "help_text": "#C5B9AC · 7528 C",
173
+ "default": {
174
+ "color": "#C5B9AC",
175
+ "opacity": 100
176
+ }
177
+ },
178
+ {
179
+ "type": "color",
180
+ "name": "neutral_gray_faint",
181
+ "label": "neutral / gray-faint",
182
+ "help_text": "#D6D1CA · Warm Gray 1 C",
183
+ "default": {
184
+ "color": "#D6D1CA",
185
+ "opacity": 100
186
+ }
187
+ }
188
+ ]
189
+ },
190
+ {
191
+ "type": "group",
192
+ "name": "praecipio_type",
193
+ "label": "Praecipio typography",
194
+ "children": [
195
+ {
196
+ "type": "font",
197
+ "name": "heading_font",
198
+ "label": "Headings",
199
+ "help_text": "Freight Sans Pro is the licensed brand heading font (commercial (Adobe Fonts / GarageFonts) — private use only) — add as a custom font only if web-licensed. Nunito Sans is the approved web fallback.",
200
+ "default": {
201
+ "font": "Nunito Sans",
202
+ "font_set": "GOOGLE"
203
+ }
204
+ },
205
+ {
206
+ "type": "font",
207
+ "name": "body_font",
208
+ "label": "Body",
209
+ "help_text": "OFL 1.1.",
210
+ "default": {
211
+ "font": "Nunito Sans",
212
+ "font_set": "GOOGLE"
213
+ }
214
+ }
215
+ ]
216
+ }
217
+ ]
@@ -0,0 +1,58 @@
1
+ /* Praecipio brand tokens for HubSpot — generated by @praecipio/brand; do not edit.
2
+ Theme fields resolve the palette; ladder values are static build-time
3
+ derivations of those same colors. */
4
+ :root {
5
+ --praecipio-prime-orange: {{ theme.praecipio_colors.prime_orange.color }};
6
+ --praecipio-prime-teal: {{ theme.praecipio_colors.prime_teal.color }};
7
+ --praecipio-prime-maroon: {{ theme.praecipio_colors.prime_maroon.color }};
8
+ --praecipio-prime-navy: {{ theme.praecipio_colors.prime_navy.color }};
9
+ --praecipio-accent-peach: {{ theme.praecipio_colors.accent_peach.color }};
10
+ --praecipio-accent-mint: {{ theme.praecipio_colors.accent_mint.color }};
11
+ --praecipio-accent-lavender: {{ theme.praecipio_colors.accent_lavender.color }};
12
+ --praecipio-accent-cyan: {{ theme.praecipio_colors.accent_cyan.color }};
13
+ --praecipio-accent-coral: {{ theme.praecipio_colors.accent_coral.color }};
14
+ --praecipio-accent-steel: {{ theme.praecipio_colors.accent_steel.color }};
15
+ --praecipio-accent-mauve: {{ theme.praecipio_colors.accent_mauve.color }};
16
+ --praecipio-accent-slate: {{ theme.praecipio_colors.accent_slate.color }};
17
+ --praecipio-neutral-black: {{ theme.praecipio_colors.neutral_black.color }};
18
+ --praecipio-neutral-ink: {{ theme.praecipio_colors.neutral_ink.color }};
19
+ --praecipio-neutral-gray-dark: {{ theme.praecipio_colors.neutral_gray_dark.color }};
20
+ --praecipio-neutral-gray: {{ theme.praecipio_colors.neutral_gray.color }};
21
+ --praecipio-neutral-gray-light: {{ theme.praecipio_colors.neutral_gray_light.color }};
22
+ --praecipio-neutral-gray-faint: {{ theme.praecipio_colors.neutral_gray_faint.color }};
23
+ /* derived ladders (regenerate on palette change) */
24
+ --praecipio-orange-tint-10: #ce6122;
25
+ --praecipio-orange-tint-20: #d3723a;
26
+ --praecipio-orange-tint-30: #d98453;
27
+ --praecipio-orange-tint-40: #de956b;
28
+ --praecipio-orange-shade-80: #a03f07;
29
+ --praecipio-orange-shade-60: #782f05;
30
+ --praecipio-orange-shade-40: #502004;
31
+ --praecipio-orange-shade-20: #281002;
32
+ --praecipio-teal-tint-10: #1e5b62;
33
+ --praecipio-teal-tint-20: #376d73;
34
+ --praecipio-teal-tint-30: #508085;
35
+ --praecipio-teal-tint-40: #699296;
36
+ --praecipio-teal-shade-90: #054248;
37
+ --praecipio-teal-shade-80: #043a40;
38
+ --praecipio-teal-shade-70: #043338;
39
+ --praecipio-teal-shade-50: #032528;
40
+ --praecipio-maroon-tint-10: #793047;
41
+ --praecipio-maroon-tint-20: #88475c;
42
+ --praecipio-maroon-tint-30: #975e70;
43
+ --praecipio-maroon-tint-40: #a67585;
44
+ --praecipio-maroon-shade-90: #5f172e;
45
+ --praecipio-maroon-shade-80: #551429;
46
+ --praecipio-maroon-shade-70: #4a1224;
47
+ --praecipio-maroon-shade-60: #400f1f;
48
+ --praecipio-navy-tint-10: #405270;
49
+ --praecipio-navy-tint-20: #556580;
50
+ --praecipio-navy-tint-30: #6b7990;
51
+ --praecipio-navy-tint-40: #808ca0;
52
+ --praecipio-navy-shade-90: #273956;
53
+ --praecipio-navy-shade-80: #22324d;
54
+ --praecipio-navy-shade-70: #1e2c43;
55
+ --praecipio-navy-shade-60: #1a263a;
56
+ --praecipio-font-heading: '{{ theme.praecipio_type.heading_font.font }}', 'Nunito Sans', system-ui, sans-serif;
57
+ --praecipio-font-body: '{{ theme.praecipio_type.body_font.font }}', system-ui, sans-serif;
58
+ }