@praecipio/brand 0.1.1 → 0.2.1

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 CHANGED
@@ -21,25 +21,41 @@ are not in it — font stacks ship as names, and the repo stays private.
21
21
 
22
22
  ```ts
23
23
  // Typed tokens, ladders, and rules
24
- import { palette, prime, primeLadder, contrast, luminance } from '@praecipio/brand';
24
+ import { palette, prime, primeLadder, contrast, luminance, themes } from '@praecipio/brand';
25
25
 
26
26
  primeLadder('orange').tints; // guide p.20, exactly
27
27
  contrast('#C84F09', '#FFFFFF'); // the rules ship as functions
28
+ themes.dark.surface; // roles, derived from the palette
28
29
  ```
29
30
 
30
31
  ```css
31
- /* CSS custom properties — every palette color + ladder as --praecipio-* */
32
+ /* CSS custom properties. Two layers:
33
+ * palette — every color + ladder as --praecipio-<tier>-<name>. Fixed hues.
34
+ * roles — surface / text / border / link. Redefined per theme. */
32
35
  @import '@praecipio/brand/css';
33
36
 
34
- .cta { background: var(--praecipio-prime-orange); }
37
+ .cta { background: var(--praecipio-prime-orange); } /* a hue */
38
+ .panel { background: var(--praecipio-surface-card); /* a job */
39
+ color: var(--praecipio-text); }
35
40
  ```
36
41
 
42
+ Three themes ship: **light** (warm paper), **twilight** (the brand teal at
43
+ dusk), **dark** (the brand ink as a warm charcoal night). The bare `:root` is
44
+ light, the reader's system preference supplies dark, and
45
+ `<html data-theme="light|twilight|dark">` pins one over both. Import the
46
+ stylesheet and dark mode works with no further wiring.
47
+
48
+ Every role is derived from the palette and asserted to clear its WCAG tier
49
+ against *every* surface in its theme, so a token is safe wherever it lands.
50
+ See [the design note](../../docs/design-notes/dark-mode-2026-09.md).
51
+
37
52
  ```tsx
38
53
  // React components (react >= 18 is an optional peer dependency)
39
54
  import { SwatchGrid, Combinator } from '@praecipio/brand/react';
40
55
  ```
41
56
 
42
57
  Other subpaths: `@praecipio/brand/tokens.json` (machine-readable palette),
58
+ `@praecipio/brand/themes.json` (the resolved role values per theme),
43
59
  `@praecipio/brand/mkdocs.css` (one-file MkDocs Material branding), and
44
60
  `@praecipio/brand/hubspot/*` (HubSpot theme `fields.json` + a HubL stylesheet
45
61
  exposing the same `--praecipio-*` variables — `make hubspot` regenerates,
@@ -49,7 +65,7 @@ exposing the same `--praecipio-*` variables — `make hubspot` regenerates,
49
65
 
50
66
  Usage rules from the guide are executable: contrast assertions, colorway
51
67
  restrictions (black/white logos are print-only), ≥60% primary coverage,
52
- no gradients. Import them — don't re-derive them.
68
+ no accent-color gradients. Import them — don't re-derive them.
53
69
 
54
70
  CMYK values carry no process/ICC spec (`CMYK_INTENT`); treat print output
55
71
  as unspecified pending a ruling.
@@ -50,11 +50,11 @@ var shadeFactors = {
50
50
  function ladder(hex, shades = [0.8, 0.6, 0.4, 0.2]) {
51
51
  const { r, g, b } = hexToRgb(hex);
52
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 });
53
+ const shade2 = (k) => rgbToHex({ r: r * k, g: g * k, b: b * k });
54
54
  return {
55
55
  base: rgbToHex({ r, g, b }),
56
56
  tints: TINT_STEPS.map(tint),
57
- shades: shades.map(shade)
57
+ shades: shades.map(shade2)
58
58
  };
59
59
  }
60
60
  function primeLadder(name) {
@@ -80,9 +80,151 @@ function isAllowedTextOnWhite(hex) {
80
80
  const accentHexes = new Set(Object.values(accent).map((c2) => c2.hex));
81
81
  return !accentHexes.has(hex.toUpperCase());
82
82
  }
83
- var GRADIENTS_ALLOWED = false;
83
+ var ACCENT_GRADIENTS_ALLOWED = false;
84
+ var GRADIENTS_ALLOWED = ACCENT_GRADIENTS_ALLOWED;
84
85
  var MAX_PATTERN_OPACITY = 0.15;
85
86
 
87
+ // src/theme.ts
88
+ function mix(a, b, t) {
89
+ const A = hexToRgb(a);
90
+ const B = hexToRgb(b);
91
+ return rgbToHex({
92
+ r: A.r + (B.r - A.r) * t,
93
+ g: A.g + (B.g - A.g) * t,
94
+ b: A.b + (B.b - A.b) * t
95
+ });
96
+ }
97
+ function shade(hex, k) {
98
+ const { r, g, b } = hexToRgb(hex);
99
+ return rgbToHex({ r: r * k, g: g * k, b: b * k });
100
+ }
101
+ var AA_TEXT = 4.5;
102
+ var AAA_TEXT = 7;
103
+ var AA_LARGE = 3;
104
+ var DECORATIVE = 2.2;
105
+ function poleAgainst(surface) {
106
+ return contrast("#FFFFFF", surface) >= contrast("#000000", surface) ? "#FFFFFF" : "#000000";
107
+ }
108
+ function readableOn(hue, against, target = AA_TEXT) {
109
+ const pole = poleAgainst(against);
110
+ for (let t = 0; t <= 1.0001; t += 0.01) {
111
+ const step = mix(hue, pole, t);
112
+ if (contrast(step, against) >= target) return step;
113
+ }
114
+ return pole;
115
+ }
116
+ var accentCousin = {
117
+ orange: accent.peach,
118
+ teal: accent.steel,
119
+ navy: accent.slate,
120
+ maroon: accent.coral
121
+ };
122
+ var PAPER = mix(neutral["gray-faint"].hex, "#FFFFFF", 0.6);
123
+ var grounds = {
124
+ // Day: the palette's faintest gray, lifted toward white. The ground stays a
125
+ // warm paper and white is reserved for the top layer, so cards read as raised
126
+ // without a shadow doing the work.
127
+ light: {
128
+ anchor: neutral["gray-faint"].hex,
129
+ shadeK: 1,
130
+ toward: "#FFFFFF",
131
+ lifts: [0.5, 0.66, 0.93, 1]
132
+ },
133
+ // Dusk: the brand teal, taken down and lifted just off black.
134
+ twilight: { anchor: prime.teal.hex, shadeK: 0.55, toward: PAPER, lifts: [0.02, 0.05, 0.09, 0.13] },
135
+ // Night: the brand ink — warm charcoal, never a blue-black.
136
+ dark: { anchor: neutral.ink.hex, shadeK: 0.35, toward: PAPER, lifts: [0.02, 0.05, 0.09, 0.13] }
137
+ };
138
+ var inkTiers = { secondary: AAA_TEXT, muted: AA_TEXT, disabled: DECORATIVE };
139
+ function quietest(hue, surface, target) {
140
+ let last = hue;
141
+ for (let t = 0; t <= 1.0001; t += 0.01) {
142
+ const step = mix(hue, surface, t);
143
+ if (contrast(step, surface) < target) return last;
144
+ last = step;
145
+ }
146
+ return last;
147
+ }
148
+ function build(scheme) {
149
+ const { anchor, shadeK, toward, lifts } = grounds[scheme];
150
+ const isLight = scheme === "light";
151
+ const base = shade(anchor, shadeK);
152
+ const [lSunken, lGround, lCard, lRaised] = lifts;
153
+ const lift = (t) => mix(base, toward, t);
154
+ const surfaceSunken = lift(lSunken);
155
+ const surface = lift(lGround);
156
+ const surfaceCard = lift(lCard);
157
+ const surfaceRaised = lift(lRaised);
158
+ const worst = isLight ? surfaceSunken : surfaceRaised;
159
+ const text = isLight ? neutral.ink.hex : PAPER;
160
+ const readable = (name) => readableOn(isLight ? prime[name].hex : accentCousin[name].hex, worst);
161
+ const channel = (hex) => {
162
+ const { r, g, b } = hexToRgb(hex);
163
+ return `${r},${g},${b}`;
164
+ };
165
+ const textTeal = readable("teal");
166
+ return {
167
+ scheme,
168
+ colorScheme: isLight ? "light" : "dark",
169
+ anchor,
170
+ surface,
171
+ surfaceSunken,
172
+ surfaceCard,
173
+ surfaceRaised,
174
+ text,
175
+ textSecondary: quietest(text, worst, inkTiers.secondary),
176
+ textMuted: quietest(text, worst, inkTiers.muted),
177
+ textDisabled: quietest(text, worst, inkTiers.disabled),
178
+ textRgb: channel(text),
179
+ // The hairline is an alpha tint of the ink, so it rides any surface. The
180
+ // strong rule is a real color that clears the 3:1 UI-component floor.
181
+ border: `rgba(${channel(text)},${isLight ? 0.1 : 0.11})`,
182
+ borderStrong: readableOn(worst, worst, AA_LARGE),
183
+ textOrange: readable("orange"),
184
+ textTeal,
185
+ textNavy: readable("navy"),
186
+ textMaroon: readable("maroon"),
187
+ link: textTeal,
188
+ // Hover deepens away from the ground — darker by day, brighter by night —
189
+ // so the state change is visible without a second hue.
190
+ linkHover: mix(textTeal, poleAgainst(worst), 0.22),
191
+ focusRing: `rgba(${channel(textTeal)},0.35)`,
192
+ scrim: isLight ? "rgba(28,25,20,0.4)" : "rgba(0,0,0,0.55)",
193
+ shadowRgb: isLight ? channel(neutral.ink.hex) : "0,0,0"
194
+ };
195
+ }
196
+ var themes = {
197
+ light: build("light"),
198
+ twilight: build("twilight"),
199
+ dark: build("dark")
200
+ };
201
+ var SCHEMES = ["light", "twilight", "dark"];
202
+ function themeVars(theme) {
203
+ return [
204
+ `--praecipio-surface: ${theme.surface};`,
205
+ `--praecipio-surface-sunken: ${theme.surfaceSunken};`,
206
+ `--praecipio-surface-card: ${theme.surfaceCard};`,
207
+ `--praecipio-surface-raised: ${theme.surfaceRaised};`,
208
+ `--praecipio-text: ${theme.text};`,
209
+ `--praecipio-text-secondary: ${theme.textSecondary};`,
210
+ `--praecipio-text-muted: ${theme.textMuted};`,
211
+ `--praecipio-text-disabled: ${theme.textDisabled};`,
212
+ `--praecipio-text-rgb: ${theme.textRgb};`,
213
+ `--praecipio-border: ${theme.border};`,
214
+ `--praecipio-border-strong: ${theme.borderStrong};`,
215
+ `--praecipio-text-orange: ${theme.textOrange};`,
216
+ `--praecipio-text-teal: ${theme.textTeal};`,
217
+ `--praecipio-text-navy: ${theme.textNavy};`,
218
+ `--praecipio-text-maroon: ${theme.textMaroon};`,
219
+ `--praecipio-link: ${theme.link};`,
220
+ `--praecipio-link-hover: ${theme.linkHover};`,
221
+ `--praecipio-focus-ring: ${theme.focusRing};`,
222
+ `--praecipio-scrim: ${theme.scrim};`,
223
+ `--praecipio-shadow-rgb: ${theme.shadowRgb};`,
224
+ `color-scheme: ${theme.colorScheme};`
225
+ ].map((decl) => decl.toLowerCase());
226
+ }
227
+
86
228
  // src/typography.ts
87
229
  var fonts = {
88
230
  heading: {
@@ -175,8 +317,22 @@ export {
175
317
  luminance,
176
318
  contrast,
177
319
  isAllowedTextOnWhite,
320
+ ACCENT_GRADIENTS_ALLOWED,
178
321
  GRADIENTS_ALLOWED,
179
322
  MAX_PATTERN_OPACITY,
323
+ mix,
324
+ shade,
325
+ AA_TEXT,
326
+ AAA_TEXT,
327
+ AA_LARGE,
328
+ DECORATIVE,
329
+ poleAgainst,
330
+ readableOn,
331
+ accentCousin,
332
+ PAPER,
333
+ themes,
334
+ SCHEMES,
335
+ themeVars,
180
336
  fonts,
181
337
  fontStack,
182
338
  typeSpecs,
@@ -189,4 +345,4 @@ export {
189
345
  iconRecipe,
190
346
  iconUsage
191
347
  };
192
- //# sourceMappingURL=chunk-A6WMWOXD.js.map
348
+ //# sourceMappingURL=chunk-N3QXN43G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/color.ts","../src/rules.ts","../src/theme.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/**\n * Guide p.19, in the accent section: \"Do not create gradients with these colors.\"\n * The ban covers the accent colours. A gradient between two primes (the deck\n * spectrum's teal to orange, kept by marketing's 2026-09-09 deck review) is not\n * covered.\n */\nexport const ACCENT_GRADIENTS_ALLOWED = false;\n\n/** @deprecated Read as the accent-only rule; use ACCENT_GRADIENTS_ALLOWED. */\nexport const GRADIENTS_ALLOWED = ACCENT_GRADIENTS_ALLOWED;\n\n/** Guide p.24: pattern overlays behind text cap at 15% opacity (multiply). */\nexport const MAX_PATTERN_OPACITY = 0.15;\n","// Themes — the role layer over the palette. Brand Style Guide v2.01 fixes 18\n// colors and their ladders; it says nothing about dark interfaces. This module\n// derives three themed *roles* from those fixed colors, so a dark surface is a\n// generated consequence of the palette rather than a second, hand-picked one.\n//\n// Two kinds of token, and the difference is load-bearing:\n//\n// - PALETTE tokens (`--praecipio-prime-teal`, the tint/shade ladders) name a\n// HUE. They never change value. Use them for fills.\n// - ROLE tokens (everything here) name a JOB — page ground, primary text,\n// hairline. Each theme redefines the whole set. The structural role names\n// carry no hue, so no token can lie about its value: `--praecipio-text` is\n// ink by day and paper by night, and reads correctly either way. The four\n// `text-<hue>` roles are the deliberate exception — they name a hue family\n// and stay inside it.\n//\n// Derivation, in full:\n//\n// paper = neutral.gray-faint tinted 60% toward white — the off-white that\n// both the light grounds and the dark inks are built from. The\n// guide publishes no white; PAPER is this platform's ruling, and\n// the one value here invented rather than derived (see the open\n// decision in docs/design-notes/dark-mode-2026-09.md).\n// ground = the theme's anchor color shaded by its factor, then lifted toward\n// paper. Lifting off pure black is what keeps the dark themes warm\n// and keeps text from haloing.\n// surfaces= the same lift, continued. Sunken, ground, card, raised.\n// inks = paper (or neutral.ink, by day) faded back toward the ground until\n// each rung sits just above its legibility tier.\n// accents = by day the prime itself; by night the prime's ACCENT COUSIN, the\n// palette's own lighter relative of that hue. Either way it moves\n// only as far as WCAG AA demands. Tinting a prime straight to\n// legibility on a dark ground drains its chroma into gray; starting\n// from the cousin keeps the hue recognizably Praecipio.\n//\n// Every readable role is contrast-checked against the surface that fights it\n// hardest — the lightest surface in a dark theme, the darkest in a light one.\n// Clear that and the token is safe on all four, so no consumer has to know\n// which layer they are painting on. packages/brand/test/theme.test.ts asserts\n// every role against every surface; it is the legality gate.\n\nimport { accent, hexToRgb, neutral, prime, rgbToHex } from './color.js';\nimport { contrast } from './rules.js';\n\n/** Linear mix in sRGB: t=0 yields `a`, t=1 yields `b`. */\nexport function mix(a: string, b: string, t: number): string {\n const A = hexToRgb(a);\n const B = hexToRgb(b);\n return rgbToHex({\n r: A.r + (B.r - A.r) * t,\n g: A.g + (B.g - A.g) * t,\n b: A.b + (B.b - A.b) * t,\n });\n}\n\n/** Multiply toward black — the same shade operation the guide's ladders use. */\nexport function shade(hex: string, k: number): string {\n const { r, g, b } = hexToRgb(hex);\n return rgbToHex({ r: r * k, g: g * k, b: b * k });\n}\n\n/** WCAG AA for normal text. */\nexport const AA_TEXT = 4.5;\n/** WCAG AAA for normal text — the target for primary and secondary copy. */\nexport const AAA_TEXT = 7;\n/** WCAG AA for large text, UI components, and graphical objects. */\nexport const AA_LARGE = 3;\n/** Disabled text is exempt from WCAG contrast; this keeps it merely visible. */\nexport const DECORATIVE = 2.2;\n\n/** Whichever of white or black a color must move toward to gain contrast. */\nexport function poleAgainst(surface: string): string {\n return contrast('#FFFFFF', surface) >= contrast('#000000', surface) ? '#FFFFFF' : '#000000';\n}\n\n/**\n * Walk `hue` away from `against` in 1% steps until it clears `target` contrast,\n * moving toward white on dark grounds and toward black on light ones. Returns\n * the first step that clears — the most saturated legal value, never a paler\n * one than the rule requires.\n */\nexport function readableOn(hue: string, against: string, target = AA_TEXT): string {\n const pole = poleAgainst(against);\n for (let t = 0; t <= 1.0001; t += 0.01) {\n const step = mix(hue, pole, t);\n if (contrast(step, against) >= target) return step;\n }\n return pole;\n}\n\n/**\n * The palette's own lighter relative of each prime, by hue. These pairings are\n * judgments, not arithmetic — peach IS the guide's light orange, steel its\n * light teal — so they are data, like the shade factors in color.ts.\n *\n * Maroon (341°) sits almost exactly between mauve (313°) and coral (8°). Coral\n * wins on chroma: mauve is so desaturated that lightening it to legibility\n * yields a gray, which is the failure mode the cousin rule exists to avoid.\n */\nexport const accentCousin = {\n orange: accent.peach,\n teal: accent.steel,\n navy: accent.slate,\n maroon: accent.coral,\n} as const satisfies Record<keyof typeof prime, { hex: string }>;\n\n/**\n * PAPER — the off-white ground. Derived as gray-faint tinted 60% toward white,\n * which lands warm rather than clinical. The guide publishes no white value;\n * this is the platform's ruling and the one open decision in this file.\n */\nexport const PAPER = mix(neutral['gray-faint'].hex, '#FFFFFF', 0.6);\n\nexport type Scheme = 'light' | 'twilight' | 'dark';\n\nexport interface Theme {\n scheme: Scheme;\n /** `light` or `dark` — drives the CSS `color-scheme` property. */\n colorScheme: 'light' | 'dark';\n /** The palette color the grounds are built from. */\n anchor: string;\n /** Page ground, and the three surfaces that sit relative to it. */\n surface: string;\n surfaceSunken: string;\n surfaceCard: string;\n surfaceRaised: string;\n /** Text hierarchy. `textDisabled` is exempt from contrast rules by design. */\n text: string;\n textSecondary: string;\n textMuted: string;\n textDisabled: string;\n /** Hairlines and dividers. `borderStrong` clears AA-large as a UI boundary. */\n border: string;\n borderStrong: string;\n /**\n * Readable twins of the four primes — the hue, as text, safe on every\n * surface. These live in the `text-*` family rather than `accent-*` so they\n * never collide with the palette's accent tier, which names hues.\n */\n textOrange: string;\n textTeal: string;\n textNavy: string;\n textMaroon: string;\n /** Links resolve to the theme's readable teal; hover deepens away from the ground. */\n link: string;\n linkHover: string;\n focusRing: string;\n /** Modal veil, and the channel box-shadows tint from. */\n scrim: string;\n /** `r,g,b` triples for alpha tints: rgba(var(--praecipio-text-rgb), .07). */\n textRgb: string;\n shadowRgb: string;\n}\n\ninterface Ground {\n /** The palette color the surfaces are built from. */\n anchor: string;\n /** How far the anchor is shaded before lifting. */\n shadeK: number;\n /** What the surfaces are lifted toward. */\n toward: string;\n /** Lift depths for sunken, ground, card, raised. */\n lifts: [number, number, number, number];\n}\n\n/**\n * Per-theme grounds: which palette color anchors the surfaces, how far it is\n * shaded, and how far each surface is lifted. Hand-tuned per anchor for the\n * same reason the guide's shade factors are — a dark teal and a dark charcoal\n * do not want the same treatment — so this is data, not formula.\n */\nconst grounds: Record<Scheme, Ground> = {\n // Day: the palette's faintest gray, lifted toward white. The ground stays a\n // warm paper and white is reserved for the top layer, so cards read as raised\n // without a shadow doing the work.\n light: {\n anchor: neutral['gray-faint'].hex,\n shadeK: 1,\n toward: '#FFFFFF',\n lifts: [0.5, 0.66, 0.93, 1],\n },\n // Dusk: the brand teal, taken down and lifted just off black.\n twilight: { anchor: prime.teal.hex, shadeK: 0.55, toward: PAPER, lifts: [0.02, 0.05, 0.09, 0.13] },\n // Night: the brand ink — warm charcoal, never a blue-black.\n dark: { anchor: neutral.ink.hex, shadeK: 0.35, toward: PAPER, lifts: [0.02, 0.05, 0.09, 0.13] },\n};\n\n/**\n * The text hierarchy is defined by LEGIBILITY, not by opacity. Each rung is the\n * faintest value that still clears its tier against the theme's worst surface,\n * so \"muted\" means \"as quiet as AA permits\" rather than an arbitrary percent.\n */\nconst inkTiers = { secondary: AAA_TEXT, muted: AA_TEXT, disabled: DECORATIVE } as const;\n\n/**\n * Fade `hue` toward `surface` until it sits just above `target` — the quietest\n * legal value. The mirror of readableOn, which brightens until legal.\n */\nfunction quietest(hue: string, surface: string, target: number): string {\n let last = hue;\n for (let t = 0; t <= 1.0001; t += 0.01) {\n const step = mix(hue, surface, t);\n if (contrast(step, surface) < target) return last;\n last = step;\n }\n return last;\n}\n\nfunction build(scheme: Scheme): Theme {\n const { anchor, shadeK, toward, lifts } = grounds[scheme];\n const isLight = scheme === 'light';\n const base = shade(anchor, shadeK);\n const [lSunken, lGround, lCard, lRaised] = lifts;\n const lift = (t: number) => mix(base, toward, t);\n\n const surfaceSunken = lift(lSunken);\n const surface = lift(lGround);\n const surfaceCard = lift(lCard);\n const surfaceRaised = lift(lRaised);\n\n // Every readable role is checked against the surface that fights it hardest.\n // A light theme's inks and accents are dark, so the DARKEST surface is the\n // worst case; a dark theme's are light, so the LIGHTEST one is. Clear that\n // surface and the token is safe on all four — no consumer needs to know which\n // layer they are painting on.\n const worst = isLight ? surfaceSunken : surfaceRaised;\n\n // Primary ink is the far pole from the ground: ink by day, paper by night.\n const text = isLight ? neutral.ink.hex : PAPER;\n\n // Readable accents start from the palette's own lighter relative of the prime\n // on dark grounds, and from the prime itself by day; either way they move\n // only as far as AA demands.\n const readable = (name: keyof typeof prime) =>\n readableOn(isLight ? prime[name].hex : accentCousin[name].hex, worst);\n\n const channel = (hex: string) => {\n const { r, g, b } = hexToRgb(hex);\n return `${r},${g},${b}`;\n };\n\n const textTeal = readable('teal');\n\n return {\n scheme,\n colorScheme: isLight ? 'light' : 'dark',\n anchor,\n surface,\n surfaceSunken,\n surfaceCard,\n surfaceRaised,\n text,\n textSecondary: quietest(text, worst, inkTiers.secondary),\n textMuted: quietest(text, worst, inkTiers.muted),\n textDisabled: quietest(text, worst, inkTiers.disabled),\n textRgb: channel(text),\n // The hairline is an alpha tint of the ink, so it rides any surface. The\n // strong rule is a real color that clears the 3:1 UI-component floor.\n border: `rgba(${channel(text)},${isLight ? 0.1 : 0.11})`,\n borderStrong: readableOn(worst, worst, AA_LARGE),\n textOrange: readable('orange'),\n textTeal,\n textNavy: readable('navy'),\n textMaroon: readable('maroon'),\n link: textTeal,\n // Hover deepens away from the ground — darker by day, brighter by night —\n // so the state change is visible without a second hue.\n linkHover: mix(textTeal, poleAgainst(worst), 0.22),\n focusRing: `rgba(${channel(textTeal)},0.35)`,\n scrim: isLight ? 'rgba(28,25,20,0.4)' : 'rgba(0,0,0,0.55)',\n shadowRgb: isLight ? channel(neutral.ink.hex) : '0,0,0',\n };\n}\n\nexport const themes: Record<Scheme, Theme> = {\n light: build('light'),\n twilight: build('twilight'),\n dark: build('dark'),\n};\n\nexport const SCHEMES = ['light', 'twilight', 'dark'] as const;\n\n/** Role tokens as `--praecipio-*` CSS custom properties, without the wrapper. */\nexport function themeVars(theme: Theme): string[] {\n return [\n `--praecipio-surface: ${theme.surface};`,\n `--praecipio-surface-sunken: ${theme.surfaceSunken};`,\n `--praecipio-surface-card: ${theme.surfaceCard};`,\n `--praecipio-surface-raised: ${theme.surfaceRaised};`,\n `--praecipio-text: ${theme.text};`,\n `--praecipio-text-secondary: ${theme.textSecondary};`,\n `--praecipio-text-muted: ${theme.textMuted};`,\n `--praecipio-text-disabled: ${theme.textDisabled};`,\n `--praecipio-text-rgb: ${theme.textRgb};`,\n `--praecipio-border: ${theme.border};`,\n `--praecipio-border-strong: ${theme.borderStrong};`,\n `--praecipio-text-orange: ${theme.textOrange};`,\n `--praecipio-text-teal: ${theme.textTeal};`,\n `--praecipio-text-navy: ${theme.textNavy};`,\n `--praecipio-text-maroon: ${theme.textMaroon};`,\n `--praecipio-link: ${theme.link};`,\n `--praecipio-link-hover: ${theme.linkHover};`,\n `--praecipio-focus-ring: ${theme.focusRing};`,\n `--praecipio-scrim: ${theme.scrim};`,\n `--praecipio-shadow-rgb: ${theme.shadowRgb};`,\n `color-scheme: ${theme.colorScheme};`,\n ].map((decl) => decl.toLowerCase());\n}\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":["shade","c"]}
package/dist/index.d.ts CHANGED
@@ -81,11 +81,104 @@ declare function contrast(a: string, b: string): number;
81
81
  * heavy/bold fonts. This predicate encodes the first (hard) rule.
82
82
  */
83
83
  declare function isAllowedTextOnWhite(hex: string): boolean;
84
- /** Guide p.19: "Do not create gradients with these colors." */
84
+ /**
85
+ * Guide p.19, in the accent section: "Do not create gradients with these colors."
86
+ * The ban covers the accent colours. A gradient between two primes (the deck
87
+ * spectrum's teal to orange, kept by marketing's 2026-09-09 deck review) is not
88
+ * covered.
89
+ */
90
+ declare const ACCENT_GRADIENTS_ALLOWED = false;
91
+ /** @deprecated Read as the accent-only rule; use ACCENT_GRADIENTS_ALLOWED. */
85
92
  declare const GRADIENTS_ALLOWED = false;
86
93
  /** Guide p.24: pattern overlays behind text cap at 15% opacity (multiply). */
87
94
  declare const MAX_PATTERN_OPACITY = 0.15;
88
95
 
96
+ /** Linear mix in sRGB: t=0 yields `a`, t=1 yields `b`. */
97
+ declare function mix(a: string, b: string, t: number): string;
98
+ /** Multiply toward black — the same shade operation the guide's ladders use. */
99
+ declare function shade(hex: string, k: number): string;
100
+ /** WCAG AA for normal text. */
101
+ declare const AA_TEXT = 4.5;
102
+ /** WCAG AAA for normal text — the target for primary and secondary copy. */
103
+ declare const AAA_TEXT = 7;
104
+ /** WCAG AA for large text, UI components, and graphical objects. */
105
+ declare const AA_LARGE = 3;
106
+ /** Disabled text is exempt from WCAG contrast; this keeps it merely visible. */
107
+ declare const DECORATIVE = 2.2;
108
+ /** Whichever of white or black a color must move toward to gain contrast. */
109
+ declare function poleAgainst(surface: string): string;
110
+ /**
111
+ * Walk `hue` away from `against` in 1% steps until it clears `target` contrast,
112
+ * moving toward white on dark grounds and toward black on light ones. Returns
113
+ * the first step that clears — the most saturated legal value, never a paler
114
+ * one than the rule requires.
115
+ */
116
+ declare function readableOn(hue: string, against: string, target?: number): string;
117
+ /**
118
+ * The palette's own lighter relative of each prime, by hue. These pairings are
119
+ * judgments, not arithmetic — peach IS the guide's light orange, steel its
120
+ * light teal — so they are data, like the shade factors in color.ts.
121
+ *
122
+ * Maroon (341°) sits almost exactly between mauve (313°) and coral (8°). Coral
123
+ * wins on chroma: mauve is so desaturated that lightening it to legibility
124
+ * yields a gray, which is the failure mode the cousin rule exists to avoid.
125
+ */
126
+ declare const accentCousin: {
127
+ readonly orange: BrandColor;
128
+ readonly teal: BrandColor;
129
+ readonly navy: BrandColor;
130
+ readonly maroon: BrandColor;
131
+ };
132
+ /**
133
+ * PAPER — the off-white ground. Derived as gray-faint tinted 60% toward white,
134
+ * which lands warm rather than clinical. The guide publishes no white value;
135
+ * this is the platform's ruling and the one open decision in this file.
136
+ */
137
+ declare const PAPER: string;
138
+ type Scheme = 'light' | 'twilight' | 'dark';
139
+ interface Theme {
140
+ scheme: Scheme;
141
+ /** `light` or `dark` — drives the CSS `color-scheme` property. */
142
+ colorScheme: 'light' | 'dark';
143
+ /** The palette color the grounds are built from. */
144
+ anchor: string;
145
+ /** Page ground, and the three surfaces that sit relative to it. */
146
+ surface: string;
147
+ surfaceSunken: string;
148
+ surfaceCard: string;
149
+ surfaceRaised: string;
150
+ /** Text hierarchy. `textDisabled` is exempt from contrast rules by design. */
151
+ text: string;
152
+ textSecondary: string;
153
+ textMuted: string;
154
+ textDisabled: string;
155
+ /** Hairlines and dividers. `borderStrong` clears AA-large as a UI boundary. */
156
+ border: string;
157
+ borderStrong: string;
158
+ /**
159
+ * Readable twins of the four primes — the hue, as text, safe on every
160
+ * surface. These live in the `text-*` family rather than `accent-*` so they
161
+ * never collide with the palette's accent tier, which names hues.
162
+ */
163
+ textOrange: string;
164
+ textTeal: string;
165
+ textNavy: string;
166
+ textMaroon: string;
167
+ /** Links resolve to the theme's readable teal; hover deepens away from the ground. */
168
+ link: string;
169
+ linkHover: string;
170
+ focusRing: string;
171
+ /** Modal veil, and the channel box-shadows tint from. */
172
+ scrim: string;
173
+ /** `r,g,b` triples for alpha tints: rgba(var(--praecipio-text-rgb), .07). */
174
+ textRgb: string;
175
+ shadowRgb: string;
176
+ }
177
+ declare const themes: Record<Scheme, Theme>;
178
+ declare const SCHEMES: readonly ["light", "twilight", "dark"];
179
+ /** Role tokens as `--praecipio-*` CSS custom properties, without the wrapper. */
180
+ declare function themeVars(theme: Theme): string[];
181
+
89
182
  interface FontRole {
90
183
  family: string;
91
184
  fallback: string;
@@ -147,4 +240,4 @@ declare const iconRecipe: {
147
240
  };
148
241
  declare const iconUsage: string;
149
242
 
150
- export { type BrandColor, CMYK_INTENT, type Colorway, type FontRole, GRADIENTS_ALLOWED, type Ladder, MAX_PATTERN_OPACITY, MIN_LOGO_WIDTH_PX, MIN_PRIMARY_COVERAGE, type Rgb, TINT_STEPS, type Tier, type VisualClass, accent, canonicalColorway, clearspace, colorways, contrast, fontStack, fonts, hexToRgb, iconRecipe, iconUsage, isAllowedTextOnWhite, ladder, logoDoNots, logomarkUsage, luminance, neutral, orientations, palette, prime, primeLadder, rgbToHex, shadeFactors, typeSpecs };
243
+ export { AAA_TEXT, AA_LARGE, AA_TEXT, ACCENT_GRADIENTS_ALLOWED, type BrandColor, CMYK_INTENT, type Colorway, DECORATIVE, type FontRole, GRADIENTS_ALLOWED, type Ladder, MAX_PATTERN_OPACITY, MIN_LOGO_WIDTH_PX, MIN_PRIMARY_COVERAGE, PAPER, type Rgb, SCHEMES, type Scheme, TINT_STEPS, type Theme, type Tier, type VisualClass, accent, accentCousin, canonicalColorway, clearspace, colorways, contrast, fontStack, fonts, hexToRgb, iconRecipe, iconUsage, isAllowedTextOnWhite, ladder, logoDoNots, logomarkUsage, luminance, mix, neutral, orientations, palette, poleAgainst, prime, primeLadder, readableOn, rgbToHex, shade, shadeFactors, themeVars, themes, typeSpecs };
package/dist/index.js CHANGED
@@ -1,11 +1,19 @@
1
1
  import {
2
+ AAA_TEXT,
3
+ AA_LARGE,
4
+ AA_TEXT,
5
+ ACCENT_GRADIENTS_ALLOWED,
2
6
  CMYK_INTENT,
7
+ DECORATIVE,
3
8
  GRADIENTS_ALLOWED,
4
9
  MAX_PATTERN_OPACITY,
5
10
  MIN_LOGO_WIDTH_PX,
6
11
  MIN_PRIMARY_COVERAGE,
12
+ PAPER,
13
+ SCHEMES,
7
14
  TINT_STEPS,
8
15
  accent,
16
+ accentCousin,
9
17
  canonicalColorway,
10
18
  clearspace,
11
19
  colorways,
@@ -20,23 +28,37 @@ import {
20
28
  logoDoNots,
21
29
  logomarkUsage,
22
30
  luminance,
31
+ mix,
23
32
  neutral,
24
33
  orientations,
25
34
  palette,
35
+ poleAgainst,
26
36
  prime,
27
37
  primeLadder,
38
+ readableOn,
28
39
  rgbToHex,
40
+ shade,
29
41
  shadeFactors,
42
+ themeVars,
43
+ themes,
30
44
  typeSpecs
31
- } from "./chunk-A6WMWOXD.js";
45
+ } from "./chunk-N3QXN43G.js";
32
46
  export {
47
+ AAA_TEXT,
48
+ AA_LARGE,
49
+ AA_TEXT,
50
+ ACCENT_GRADIENTS_ALLOWED,
33
51
  CMYK_INTENT,
52
+ DECORATIVE,
34
53
  GRADIENTS_ALLOWED,
35
54
  MAX_PATTERN_OPACITY,
36
55
  MIN_LOGO_WIDTH_PX,
37
56
  MIN_PRIMARY_COVERAGE,
57
+ PAPER,
58
+ SCHEMES,
38
59
  TINT_STEPS,
39
60
  accent,
61
+ accentCousin,
40
62
  canonicalColorway,
41
63
  clearspace,
42
64
  colorways,
@@ -51,13 +73,19 @@ export {
51
73
  logoDoNots,
52
74
  logomarkUsage,
53
75
  luminance,
76
+ mix,
54
77
  neutral,
55
78
  orientations,
56
79
  palette,
80
+ poleAgainst,
57
81
  prime,
58
82
  primeLadder,
83
+ readableOn,
59
84
  rgbToHex,
85
+ shade,
60
86
  shadeFactors,
87
+ themeVars,
88
+ themes,
61
89
  typeSpecs
62
90
  };
63
91
  //# sourceMappingURL=index.js.map
@@ -2,6 +2,10 @@
2
2
  * Brands any mkdocs-material site:
3
3
  * theme: { name: material, palette: { primary: custom } }
4
4
  * extra_css: [praecipio-mkdocs.css]
5
+ *
6
+ * Three schemes, one per library theme: default (warm paper day),
7
+ * twilight (the brand teal at dusk), slate (warm charcoal night).
8
+ * Every value derives from the palette — see packages/brand/src/theme.ts.
5
9
  */
6
10
  :root {
7
11
  --praecipio-prime-orange: #c84f09;
@@ -58,61 +62,149 @@
58
62
  --praecipio-font-body: 'Nunito Sans', system-ui, sans-serif;
59
63
  }
60
64
 
61
- /* mkdocs-material variable mapping — three schemes:
62
- * default = light on warm design-gray paper (never stark white)
63
- * twilight = dim warm neutral, graphic-arts gray for judging color
64
- * slate = dark
65
- * Surfaces for artwork tiles are exposed as --praecipio-tile-* so galleries
66
- * read correctly in every scheme. */
67
65
  :root, [data-md-color-scheme="default"] {
68
- --md-primary-fg-color: var(--praecipio-prime-teal);
69
- --md-primary-fg-color--light: var(--praecipio-teal-tint-20);
70
- --md-primary-fg-color--dark: var(--praecipio-teal-shade-80);
71
- --md-accent-fg-color: var(--praecipio-prime-orange);
72
- --md-typeset-a-color: var(--praecipio-prime-teal);
66
+ --praecipio-surface: #f1efed;
67
+ --praecipio-surface-sunken: #ebe8e5;
68
+ --praecipio-surface-card: #fcfcfb;
69
+ --praecipio-surface-raised: #ffffff;
70
+ --praecipio-text: #332e27;
71
+ --praecipio-text-secondary: #4f4a44;
72
+ --praecipio-text-muted: #6c6862;
73
+ --praecipio-text-disabled: #a09c97;
74
+ --praecipio-text-rgb: 51,46,39;
75
+ --praecipio-border: rgba(51,46,39,0.1);
76
+ --praecipio-border-strong: #868483;
77
+ --praecipio-text-orange: #b24608;
78
+ --praecipio-text-teal: #054950;
79
+ --praecipio-text-navy: #2b3f60;
80
+ --praecipio-text-maroon: #6a1933;
81
+ --praecipio-link: #054950;
82
+ --praecipio-link-hover: #04393e;
83
+ --praecipio-focus-ring: rgba(5,73,80,0.35);
84
+ --praecipio-scrim: rgba(28,25,20,0.4);
85
+ --praecipio-shadow-rgb: 51,46,39;
86
+ color-scheme: light;
87
+ --md-default-bg-color: #F1EFED;
88
+ --md-default-fg-color: #332E27;
89
+ --md-default-fg-color--light: #4F4A44;
90
+ --md-default-fg-color--lighter: #6C6862;
91
+ --md-default-fg-color--lightest: rgba(51, 46, 39, 0.12);
92
+ --md-typeset-color: #332E27;
93
+ --md-typeset-a-color: #054950;
94
+ --md-accent-fg-color: #B24608;
95
+ --md-primary-fg-color: #054950;
96
+ --md-primary-fg-color--light: #346A6F;
97
+ --md-primary-fg-color--dark: #04373C;
98
+ --md-primary-bg-color: #EFEDEA;
99
+ --md-primary-bg-color--light: rgba(239, 237, 234, 0.7);
100
+ --md-code-bg-color: #EBE8E5;
101
+ --md-code-fg-color: #4F4A44;
102
+ --md-footer-bg-color: #EBE8E5;
73
103
  --md-text-font-family: var(--praecipio-font-body);
74
- --md-default-bg-color: #f6f4f1; /* warm paper — not white */
75
- --md-code-bg-color: #edeae5;
76
- --praecipio-tile-a: #ece9e4;
77
- --praecipio-tile-b: #f8f6f3;
78
- --praecipio-card-bg: #fffefc;
79
- --praecipio-card-fg: var(--praecipio-neutral-ink);
104
+ --praecipio-tile-a: #FCFCFB;
105
+ --praecipio-tile-b: #FFFFFF;
106
+ --praecipio-card-bg: #FCFCFB;
107
+ --praecipio-card-fg: #332E27;
80
108
  }
109
+
81
110
  [data-md-color-scheme="twilight"] {
82
- --md-default-bg-color: #33302b; /* warm neutral gray — design viewing */
83
- --md-default-fg-color: rgba(232, 228, 222, 0.87);
84
- --md-default-fg-color--light: rgba(232, 228, 222, 0.62);
85
- --md-default-fg-color--lighter: rgba(232, 228, 222, 0.32);
86
- --md-default-fg-color--lightest: rgba(232, 228, 222, 0.12);
87
- --md-typeset-color: rgba(232, 228, 222, 0.87);
88
- --md-typeset-a-color: var(--praecipio-teal-tint-40);
89
- --md-accent-fg-color: var(--praecipio-orange-tint-30);
90
- --md-primary-fg-color: var(--praecipio-teal-shade-80);
91
- --md-code-bg-color: #2a2723;
92
- --md-code-fg-color: var(--praecipio-neutral-gray-light);
93
- --md-footer-bg-color: #2a2723;
94
- --praecipio-tile-a: #4a463f;
95
- --praecipio-tile-b: #55504a;
96
- --praecipio-card-bg: #3d3934;
97
- --praecipio-card-fg: var(--praecipio-neutral-gray-light);
111
+ --praecipio-surface: #0f3236;
112
+ --praecipio-surface-sunken: #082c30;
113
+ --praecipio-surface-card: #183a3d;
114
+ --praecipio-surface-raised: #224245;
115
+ --praecipio-text: #efedea;
116
+ --praecipio-text-secondary: #ced2d0;
117
+ --praecipio-text-muted: #9faaaa;
118
+ --praecipio-text-disabled: #5f7576;
119
+ --praecipio-text-rgb: 239,237,234;
120
+ --praecipio-border: rgba(239,237,234,0.11);
121
+ --praecipio-border-strong: #788c8e;
122
+ --praecipio-text-orange: #ffbe7a;
123
+ --praecipio-text-teal: #78b1b8;
124
+ --praecipio-text-navy: #8badbc;
125
+ --praecipio-text-maroon: #e39386;
126
+ --praecipio-link: #78b1b8;
127
+ --praecipio-link-hover: #96c2c8;
128
+ --praecipio-focus-ring: rgba(120,177,184,0.35);
129
+ --praecipio-scrim: rgba(0,0,0,0.55);
130
+ --praecipio-shadow-rgb: 0,0,0;
131
+ color-scheme: dark;
132
+ --md-default-bg-color: #0F3236;
133
+ --md-default-fg-color: #EFEDEA;
134
+ --md-default-fg-color--light: #CED2D0;
135
+ --md-default-fg-color--lighter: #9FAAAA;
136
+ --md-default-fg-color--lightest: rgba(239, 237, 234, 0.12);
137
+ --md-typeset-color: #EFEDEA;
138
+ --md-typeset-a-color: #78B1B8;
139
+ --md-accent-fg-color: #FFBE7A;
140
+ --md-primary-fg-color: #082C30;
141
+ --md-primary-fg-color--light: #365355;
142
+ --md-primary-fg-color--dark: #062124;
143
+ --md-primary-bg-color: #EFEDEA;
144
+ --md-primary-bg-color--light: rgba(239, 237, 234, 0.7);
145
+ --md-code-bg-color: #082C30;
146
+ --md-code-fg-color: #CED2D0;
147
+ --md-footer-bg-color: #082C30;
148
+ --md-text-font-family: var(--praecipio-font-body);
149
+ --praecipio-tile-a: #183A3D;
150
+ --praecipio-tile-b: #224245;
151
+ --praecipio-card-bg: #183A3D;
152
+ --praecipio-card-fg: #EFEDEA;
98
153
  }
154
+
99
155
  [data-md-color-scheme="slate"] {
100
- --md-primary-fg-color: var(--praecipio-prime-teal);
101
- --md-accent-fg-color: var(--praecipio-prime-orange);
102
- --md-typeset-a-color: var(--praecipio-teal-tint-40);
103
- --md-default-bg-color: #1b1916; /* warm near-black, not blue-slate */
104
- --praecipio-tile-a: #35322d;
105
- --praecipio-tile-b: #403c36;
106
- --praecipio-card-bg: #262320;
107
- --praecipio-card-fg: var(--praecipio-neutral-gray-light);
156
+ --praecipio-surface: #1d1b19;
157
+ --praecipio-surface-sunken: #161412;
158
+ --praecipio-surface-card: #262422;
159
+ --praecipio-surface-raised: #2f2d2b;
160
+ --praecipio-text: #efedea;
161
+ --praecipio-text-secondary: #bbb9b6;
162
+ --praecipio-text-muted: #979592;
163
+ --praecipio-text-disabled: #63615f;
164
+ --praecipio-text-rgb: 239,237,234;
165
+ --praecipio-border: rgba(239,237,234,0.11);
166
+ --praecipio-border-strong: #787775;
167
+ --praecipio-text-orange: #ffbe7a;
168
+ --praecipio-text-teal: #6eabb3;
169
+ --praecipio-text-navy: #709aac;
170
+ --praecipio-text-maroon: #dd7b6c;
171
+ --praecipio-link: #6eabb3;
172
+ --praecipio-link-hover: #8ebdc4;
173
+ --praecipio-focus-ring: rgba(110,171,179,0.35);
174
+ --praecipio-scrim: rgba(0,0,0,0.55);
175
+ --praecipio-shadow-rgb: 0,0,0;
176
+ color-scheme: dark;
177
+ --md-default-bg-color: #1D1B19;
178
+ --md-default-fg-color: #EFEDEA;
179
+ --md-default-fg-color--light: #BBB9B6;
180
+ --md-default-fg-color--lighter: #979592;
181
+ --md-default-fg-color--lightest: rgba(239, 237, 234, 0.12);
182
+ --md-typeset-color: #EFEDEA;
183
+ --md-typeset-a-color: #6EABB3;
184
+ --md-accent-fg-color: #FFBE7A;
185
+ --md-primary-fg-color: #161412;
186
+ --md-primary-fg-color--light: #413F3D;
187
+ --md-primary-fg-color--dark: #110F0E;
188
+ --md-primary-bg-color: #EFEDEA;
189
+ --md-primary-bg-color--light: rgba(239, 237, 234, 0.7);
190
+ --md-code-bg-color: #161412;
191
+ --md-code-fg-color: #BBB9B6;
192
+ --md-footer-bg-color: #161412;
193
+ --md-text-font-family: var(--praecipio-font-body);
194
+ --praecipio-tile-a: #262422;
195
+ --praecipio-tile-b: #2F2D2B;
196
+ --praecipio-card-bg: #262422;
197
+ --praecipio-card-fg: #EFEDEA;
108
198
  }
199
+
109
200
  .md-typeset h1, .md-typeset h2, .md-typeset h3,
110
201
  .md-typeset h4, .md-typeset h5, .md-typeset h6 {
111
202
  font-family: var(--praecipio-font-heading);
112
203
  }
113
- /* restrained brand pop: accent rule under page titles */
204
+ /* restrained brand pop: accent rule under page titles, in the theme's own
205
+ * readable orange so it holds up on a dark ground */
114
206
  .md-typeset h1 {
115
207
  padding-bottom: 0.25em;
116
- border-bottom: 3px solid var(--praecipio-prime-orange);
208
+ border-bottom: 3px solid var(--praecipio-text-orange);
117
209
  display: inline-block;
118
210
  }
@@ -0,0 +1,77 @@
1
+ {
2
+ "light": {
3
+ "scheme": "light",
4
+ "colorScheme": "light",
5
+ "anchor": "#D6D1CA",
6
+ "surface": "#F1EFED",
7
+ "surfaceSunken": "#EBE8E5",
8
+ "surfaceCard": "#FCFCFB",
9
+ "surfaceRaised": "#FFFFFF",
10
+ "text": "#332E27",
11
+ "textSecondary": "#4F4A44",
12
+ "textMuted": "#6C6862",
13
+ "textDisabled": "#A09C97",
14
+ "textRgb": "51,46,39",
15
+ "border": "rgba(51,46,39,0.1)",
16
+ "borderStrong": "#868483",
17
+ "textOrange": "#B24608",
18
+ "textTeal": "#054950",
19
+ "textNavy": "#2B3F60",
20
+ "textMaroon": "#6A1933",
21
+ "link": "#054950",
22
+ "linkHover": "#04393E",
23
+ "focusRing": "rgba(5,73,80,0.35)",
24
+ "scrim": "rgba(28,25,20,0.4)",
25
+ "shadowRgb": "51,46,39"
26
+ },
27
+ "twilight": {
28
+ "scheme": "twilight",
29
+ "colorScheme": "dark",
30
+ "anchor": "#054950",
31
+ "surface": "#0F3236",
32
+ "surfaceSunken": "#082C30",
33
+ "surfaceCard": "#183A3D",
34
+ "surfaceRaised": "#224245",
35
+ "text": "#EFEDEA",
36
+ "textSecondary": "#CED2D0",
37
+ "textMuted": "#9FAAAA",
38
+ "textDisabled": "#5F7576",
39
+ "textRgb": "239,237,234",
40
+ "border": "rgba(239,237,234,0.11)",
41
+ "borderStrong": "#788C8E",
42
+ "textOrange": "#FFBE7A",
43
+ "textTeal": "#78B1B8",
44
+ "textNavy": "#8BADBC",
45
+ "textMaroon": "#E39386",
46
+ "link": "#78B1B8",
47
+ "linkHover": "#96C2C8",
48
+ "focusRing": "rgba(120,177,184,0.35)",
49
+ "scrim": "rgba(0,0,0,0.55)",
50
+ "shadowRgb": "0,0,0"
51
+ },
52
+ "dark": {
53
+ "scheme": "dark",
54
+ "colorScheme": "dark",
55
+ "anchor": "#332E27",
56
+ "surface": "#1D1B19",
57
+ "surfaceSunken": "#161412",
58
+ "surfaceCard": "#262422",
59
+ "surfaceRaised": "#2F2D2B",
60
+ "text": "#EFEDEA",
61
+ "textSecondary": "#BBB9B6",
62
+ "textMuted": "#979592",
63
+ "textDisabled": "#63615F",
64
+ "textRgb": "239,237,234",
65
+ "border": "rgba(239,237,234,0.11)",
66
+ "borderStrong": "#787775",
67
+ "textOrange": "#FFBE7A",
68
+ "textTeal": "#6EABB3",
69
+ "textNavy": "#709AAC",
70
+ "textMaroon": "#DD7B6C",
71
+ "link": "#6EABB3",
72
+ "linkHover": "#8EBDC4",
73
+ "focusRing": "rgba(110,171,179,0.35)",
74
+ "scrim": "rgba(0,0,0,0.55)",
75
+ "shadowRgb": "0,0,0"
76
+ }
77
+ }
@@ -1,4 +1,6 @@
1
1
  /* Praecipio brand tokens — generated by @praecipio/brand; do not edit. */
2
+
3
+ /* Palette: hue constants. Same value in every theme. */
2
4
  :root {
3
5
  --praecipio-prime-orange: #c84f09;
4
6
  --praecipio-prime-teal: #054950;
@@ -52,4 +54,123 @@
52
54
  --praecipio-navy-shade-60: #1a263a;
53
55
  --praecipio-font-heading: 'Freight Sans Pro', 'Nunito Sans', system-ui, sans-serif;
54
56
  --praecipio-font-body: 'Nunito Sans', system-ui, sans-serif;
57
+ --praecipio-surface: #f1efed;
58
+ --praecipio-surface-sunken: #ebe8e5;
59
+ --praecipio-surface-card: #fcfcfb;
60
+ --praecipio-surface-raised: #ffffff;
61
+ --praecipio-text: #332e27;
62
+ --praecipio-text-secondary: #4f4a44;
63
+ --praecipio-text-muted: #6c6862;
64
+ --praecipio-text-disabled: #a09c97;
65
+ --praecipio-text-rgb: 51,46,39;
66
+ --praecipio-border: rgba(51,46,39,0.1);
67
+ --praecipio-border-strong: #868483;
68
+ --praecipio-text-orange: #b24608;
69
+ --praecipio-text-teal: #054950;
70
+ --praecipio-text-navy: #2b3f60;
71
+ --praecipio-text-maroon: #6a1933;
72
+ --praecipio-link: #054950;
73
+ --praecipio-link-hover: #04393e;
74
+ --praecipio-focus-ring: rgba(5,73,80,0.35);
75
+ --praecipio-scrim: rgba(28,25,20,0.4);
76
+ --praecipio-shadow-rgb: 51,46,39;
77
+ color-scheme: light;
78
+ }
79
+
80
+ /* Unpinned + system dark preference. */
81
+ @media (prefers-color-scheme: dark) {
82
+ :root:not([data-theme="light"]):not([data-theme="twilight"]):not([data-theme="dark"]) {
83
+ --praecipio-surface: #1d1b19;
84
+ --praecipio-surface-sunken: #161412;
85
+ --praecipio-surface-card: #262422;
86
+ --praecipio-surface-raised: #2f2d2b;
87
+ --praecipio-text: #efedea;
88
+ --praecipio-text-secondary: #bbb9b6;
89
+ --praecipio-text-muted: #979592;
90
+ --praecipio-text-disabled: #63615f;
91
+ --praecipio-text-rgb: 239,237,234;
92
+ --praecipio-border: rgba(239,237,234,0.11);
93
+ --praecipio-border-strong: #787775;
94
+ --praecipio-text-orange: #ffbe7a;
95
+ --praecipio-text-teal: #6eabb3;
96
+ --praecipio-text-navy: #709aac;
97
+ --praecipio-text-maroon: #dd7b6c;
98
+ --praecipio-link: #6eabb3;
99
+ --praecipio-link-hover: #8ebdc4;
100
+ --praecipio-focus-ring: rgba(110,171,179,0.35);
101
+ --praecipio-scrim: rgba(0,0,0,0.55);
102
+ --praecipio-shadow-rgb: 0,0,0;
103
+ color-scheme: dark;
104
+ }
105
+ }
106
+
107
+ /* Explicit pins win over the system preference. */
108
+ :root[data-theme="light"] {
109
+ --praecipio-surface: #f1efed;
110
+ --praecipio-surface-sunken: #ebe8e5;
111
+ --praecipio-surface-card: #fcfcfb;
112
+ --praecipio-surface-raised: #ffffff;
113
+ --praecipio-text: #332e27;
114
+ --praecipio-text-secondary: #4f4a44;
115
+ --praecipio-text-muted: #6c6862;
116
+ --praecipio-text-disabled: #a09c97;
117
+ --praecipio-text-rgb: 51,46,39;
118
+ --praecipio-border: rgba(51,46,39,0.1);
119
+ --praecipio-border-strong: #868483;
120
+ --praecipio-text-orange: #b24608;
121
+ --praecipio-text-teal: #054950;
122
+ --praecipio-text-navy: #2b3f60;
123
+ --praecipio-text-maroon: #6a1933;
124
+ --praecipio-link: #054950;
125
+ --praecipio-link-hover: #04393e;
126
+ --praecipio-focus-ring: rgba(5,73,80,0.35);
127
+ --praecipio-scrim: rgba(28,25,20,0.4);
128
+ --praecipio-shadow-rgb: 51,46,39;
129
+ color-scheme: light;
130
+ }
131
+ :root[data-theme="twilight"] {
132
+ --praecipio-surface: #0f3236;
133
+ --praecipio-surface-sunken: #082c30;
134
+ --praecipio-surface-card: #183a3d;
135
+ --praecipio-surface-raised: #224245;
136
+ --praecipio-text: #efedea;
137
+ --praecipio-text-secondary: #ced2d0;
138
+ --praecipio-text-muted: #9faaaa;
139
+ --praecipio-text-disabled: #5f7576;
140
+ --praecipio-text-rgb: 239,237,234;
141
+ --praecipio-border: rgba(239,237,234,0.11);
142
+ --praecipio-border-strong: #788c8e;
143
+ --praecipio-text-orange: #ffbe7a;
144
+ --praecipio-text-teal: #78b1b8;
145
+ --praecipio-text-navy: #8badbc;
146
+ --praecipio-text-maroon: #e39386;
147
+ --praecipio-link: #78b1b8;
148
+ --praecipio-link-hover: #96c2c8;
149
+ --praecipio-focus-ring: rgba(120,177,184,0.35);
150
+ --praecipio-scrim: rgba(0,0,0,0.55);
151
+ --praecipio-shadow-rgb: 0,0,0;
152
+ color-scheme: dark;
153
+ }
154
+ :root[data-theme="dark"] {
155
+ --praecipio-surface: #1d1b19;
156
+ --praecipio-surface-sunken: #161412;
157
+ --praecipio-surface-card: #262422;
158
+ --praecipio-surface-raised: #2f2d2b;
159
+ --praecipio-text: #efedea;
160
+ --praecipio-text-secondary: #bbb9b6;
161
+ --praecipio-text-muted: #979592;
162
+ --praecipio-text-disabled: #63615f;
163
+ --praecipio-text-rgb: 239,237,234;
164
+ --praecipio-border: rgba(239,237,234,0.11);
165
+ --praecipio-border-strong: #787775;
166
+ --praecipio-text-orange: #ffbe7a;
167
+ --praecipio-text-teal: #6eabb3;
168
+ --praecipio-text-navy: #709aac;
169
+ --praecipio-text-maroon: #dd7b6c;
170
+ --praecipio-link: #6eabb3;
171
+ --praecipio-link-hover: #8ebdc4;
172
+ --praecipio-focus-ring: rgba(110,171,179,0.35);
173
+ --praecipio-scrim: rgba(0,0,0,0.55);
174
+ --praecipio-shadow-rgb: 0,0,0;
175
+ color-scheme: dark;
55
176
  }
@@ -7,7 +7,7 @@ import {
7
7
  palette,
8
8
  prime,
9
9
  primeLadder
10
- } from "../chunk-A6WMWOXD.js";
10
+ } from "../chunk-N3QXN43G.js";
11
11
 
12
12
  // src/react/SwatchGrid.tsx
13
13
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -98,7 +98,7 @@ function prompt(c) {
98
98
  `- text: ${c.text.label} (${c.text.hex}), headings Freight Sans Pro, body Nunito Sans`,
99
99
  `- accent: ${c.acc.label} (${c.acc.hex}) for graphic elements only \u2014 never as text on white`,
100
100
  `- arrangement: ${c.arrangement}`,
101
- "- rules: no gradients, no drop shadows, no rotation, patterns <= 15% opacity multiply"
101
+ "- rules: no accent-color gradients, no drop shadows, no rotation, patterns <= 15% opacity multiply"
102
102
  ].join("\n");
103
103
  }
104
104
  function Combinator({ assetBase }) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/react/SwatchGrid.tsx","../../src/react/Combinator.tsx","../../src/react/Sampler.tsx"],"sourcesContent":["// Swatch grid rendered FROM the library — the portal documents the palette\n// with the palette. If @praecipio/brand changes, this page changes.\nimport { palette, prime, primeLadder, CMYK_INTENT } from '../index.js';\n\nexport function SwatchGrid() {\n return (\n <div className=\"swatch-grid\" title={`CMYK: ${CMYK_INTENT}`}>\n {palette.map((c) => {\n const isPrime = c.tier === 'prime';\n const l = isPrime ? primeLadder(c.name as keyof typeof prime) : null;\n return (\n <div className=\"swatch\" key={c.name}>\n <div className=\"swatch-chip\" style={{ background: c.hex }} />\n {l && (\n <div className=\"swatch-ladder\">\n {[...l.shades].reverse().map((hex) => (\n <span key={hex} style={{ background: hex }} />\n ))}\n <span style={{ background: l.base }} />\n {l.tints.map((hex) => (\n <span key={hex} style={{ background: hex }} />\n ))}\n </div>\n )}\n <div className=\"swatch-meta\">\n <strong>{c.name}</strong> <em>({c.tier})</em>\n <br />\n {c.hex} · {c.pantone}\n <br />\n CMYK {c.cmyk.join('.')}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","// Brand combinator: shuffles LEGAL combinations of surface, logo variant,\n// accent, and arrangement — legality comes from the same @praecipio/brand\n// rules the packages ship, so illegal combos are unrepresentable. Each\n// result includes a copy-pastable prompt for asking Claude to compose it.\nimport { useMemo, useState } from 'react';\nimport { prime, accent, neutral, primeLadder, contrast, luminance } from '../index.js';\n\ninterface Surface {\n label: string;\n hex: string;\n kind: 'light' | 'dark';\n}\n\n// kind is derived, not hand-labeled — the library's luminance() decides\nconst surface = (label: string, hex: string): Surface => ({\n label,\n hex,\n kind: luminance(hex) > 0.35 ? 'light' : 'dark',\n});\n\nconst surfaces: Surface[] = [\n surface('white', '#FFFFFF'),\n surface('prime-teal', prime.teal.hex),\n surface('prime-maroon', prime.maroon.hex),\n surface('prime-navy', prime.navy.hex),\n surface('teal-shade-80', primeLadder('teal').shades[1]),\n surface('navy-shade-80', primeLadder('navy').shades[1]),\n surface('orange-tint-30', primeLadder('orange').tints[2]),\n surface('teal-tint-40', primeLadder('teal').tints[3]),\n surface('gray-faint', neutral['gray-faint'].hex),\n];\n\n// digital-legal logo treatments only (black/white are print-only)\nconst logoFor = (s: Surface, orient: string) => {\n const name = { hori: 'Hori', verti: 'Verti', logomark: 'Logomark' }[orient];\n return s.kind === 'light'\n ? { file: `Praecipio_${name}_RGB.png`, visual: 'primary', dir: `${orient}/primary` }\n : orient === 'logomark'\n ? { file: 'Praecipio_Logomark_White.png', visual: 'white (logomark exception on dark)', dir: 'logomark/white' }\n : { file: `Praecipio_${name}_RVRS_Light_RGB.png`, visual: 'reverse', dir: `${orient}/reverse` };\n};\n\nconst orients = ['hori', 'verti', 'logomark'];\nconst arrangements = [\n 'hero: logo top-left, headline centered-left, accent callout chip lower-right',\n 'centered: logomark above headline, generous clearspace, single accent rule below',\n 'split: left half surface color with logo + headline, right half white with body text',\n 'badge: content leads, logomark discreet in the corner (after the full logotype)',\n];\n\nconst pick = <T,>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];\n\nfunction legalAccent(surface: Surface): { label: string; hex: string } {\n const candidates = Object.values(accent)\n .map((c) => ({ label: `accent-${c.name}`, hex: c.hex }))\n // accents never as text on white; as graphic elements require 3:1 on the surface\n .filter((c) => contrast(c.hex, surface.hex) >= 3);\n return candidates.length ? pick(candidates) : { label: 'accent-peach', hex: accent.peach.hex };\n}\n\nfunction makeCombo() {\n const surface = pick(surfaces);\n const orient = pick(orients);\n const logo = logoFor(surface, orient);\n const acc = legalAccent(surface);\n // any text color that passes WCAG AA on the surface is legal — shuffle picks\n const textCandidates = [\n { label: 'neutral-ink', hex: neutral.ink.hex },\n { label: 'white', hex: '#FFFFFF' },\n ].filter((t) => contrast(t.hex, surface.hex) >= 4.5);\n const text = pick(textCandidates);\n const arrangement = pick(arrangements);\n return { surface, orient, logo, acc, text, arrangement };\n}\n\nfunction prompt(c: ReturnType<typeof makeCombo>): string {\n return [\n 'Compose a Praecipio-branded graphic using @praecipio/brand:',\n `- surface: ${c.surface.label} (${c.surface.hex}) — keep prime coverage >= 60%`,\n `- logo: ${c.orient} orientation, ${c.logo.visual} treatment (build/logo/${c.logo.dir}), min width 80px, clearspace = logomark height`,\n `- text: ${c.text.label} (${c.text.hex}), headings Freight Sans Pro, body Nunito Sans`,\n `- accent: ${c.acc.label} (${c.acc.hex}) for graphic elements only — never as text on white`,\n `- arrangement: ${c.arrangement}`,\n '- rules: no gradients, no drop shadows, no rotation, patterns <= 15% opacity multiply',\n ].join('\\n');\n}\n\nexport function Combinator({ assetBase }: { assetBase: string }) {\n const [combo, setCombo] = useState(makeCombo);\n const [copied, setCopied] = useState(false);\n const text = useMemo(() => prompt(combo), [combo]);\n\n const copy = () => {\n navigator.clipboard.writeText(text).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n });\n };\n\n const logoSrc = `${assetBase}assets/gallery/logo/${combo.logo.dir}/${combo.logo.file}`;\n return (\n <div className=\"combinator\">\n <div className=\"combinator-bar\">\n <button onClick={() => setCombo(makeCombo())}>⟳ shuffle</button>\n <button onClick={copy}>{copied ? 'copied ✓' : 'copy prompt'}</button>\n <span className=\"combinator-meta\">\n {combo.surface.label} · {combo.orient}/{combo.logo.visual} · {combo.acc.label}\n </span>\n </div>\n <div className=\"combinator-preview\" style={{ background: combo.surface.hex }}>\n <img src={logoSrc} alt=\"logo\" style={{ maxWidth: 180, maxHeight: 90 }} />\n <div style={{ color: combo.text.hex, fontWeight: 800, fontSize: '1.3rem' }}>\n Building Connected Enterprises\n </div>\n <div style={{ color: combo.text.hex, opacity: 0.85, fontSize: '0.8rem' }}>\n Real solutions for real challenges — strategy, process, and people, aligned.\n </div>\n <div\n style={{\n background: combo.acc.hex,\n height: 8,\n width: 96,\n borderRadius: 4,\n }}\n />\n <div style={{ color: combo.text.hex, opacity: 0.6, fontSize: '0.65rem' }}>\n {combo.arrangement}\n </div>\n </div>\n <pre className=\"combinator-prompt\">{text}</pre>\n </div>\n );\n}\n","// Sampler: a mock product UI composed ONLY from the published consumer\n// surface — `@praecipio/brand/css` custom properties and the library's\n// legality rules. What this renders is exactly what an external build\n// (a Cloudflare container UX, the marketing site) gets from the package:\n// no portal-private styles, no assets, just tokens.\nimport type { CSSProperties, ReactNode } from 'react';\n\nconst v = (token: string) => `var(--praecipio-${token})`;\n\nconst button = (bg: string, fg: string, outline?: string): CSSProperties => ({\n background: bg,\n color: fg,\n border: outline ? `2px solid ${outline}` : 'none',\n borderRadius: 6,\n padding: '0.55rem 1.2rem',\n fontFamily: v('font-body'),\n fontWeight: 700,\n fontSize: '0.85rem',\n cursor: 'pointer',\n});\n\nconst heading: CSSProperties = { fontFamily: v('font-heading'), fontWeight: 800, margin: 0 };\n\nfunction Card({ title, children }: { title: string; children: ReactNode }) {\n return (\n <div\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 8,\n padding: '1rem 1.1rem',\n background: '#fff',\n flex: '1 1 180px',\n }}\n >\n <h4 style={{ ...heading, color: v('prime-maroon'), fontSize: '1rem', marginBottom: '0.4rem' }}>\n {title}\n </h4>\n <p style={{ margin: 0, fontSize: '0.8rem', color: v('neutral-ink'), lineHeight: 1.5 }}>\n {children}\n </p>\n <a href=\"#sampler\" style={{ color: v('prime-teal'), fontWeight: 700, fontSize: '0.8rem' }}>\n Learn more →\n </a>\n </div>\n );\n}\n\n// Prime coverage stays >= 60% (navy bar, teal hero, navy footer dominate);\n// accents appear only as graphic elements on dark primes; no gradients.\nexport function Sampler() {\n return (\n <div\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 10,\n overflow: 'hidden',\n fontFamily: v('font-body'),\n }}\n >\n {/* app bar */}\n <div\n style={{\n background: v('prime-navy'),\n color: '#fff',\n display: 'flex',\n alignItems: 'center',\n gap: '1.4rem',\n padding: '0.7rem 1.2rem',\n }}\n >\n <span style={{ ...heading, fontSize: '1.05rem' }}>Praecipio</span>\n {['Products', 'Solutions', 'Docs'].map((l) => (\n <span key={l} style={{ opacity: 0.8, fontSize: '0.8rem' }}>\n {l}\n </span>\n ))}\n <button style={{ ...button(v('prime-orange'), '#fff'), marginLeft: 'auto' }}>\n Get started\n </button>\n </div>\n\n {/* hero */}\n <div style={{ background: v('teal-shade-80'), color: '#fff', padding: '2.2rem 1.4rem' }}>\n <h2 style={{ ...heading, fontSize: '1.7rem', maxWidth: '24ch' }}>\n Intelligence Gateway\n </h2>\n <p style={{ opacity: 0.85, maxWidth: '52ch', fontSize: '0.9rem', lineHeight: 1.55 }}>\n One consistent surface for every product we ship — because the colors, type, and\n rules on this page are imported, not copied.\n </p>\n <div style={{ background: v('accent-mint'), height: 6, width: 88, borderRadius: 3, margin: '0.9rem 0 1.1rem' }} />\n <div style={{ display: 'flex', gap: '0.7rem' }}>\n <button style={button(v('prime-orange'), '#fff')}>Try it now</button>\n <button style={button('transparent', '#fff', '#fff')}>Read the docs</button>\n </div>\n </div>\n\n {/* content */}\n <div style={{ background: '#fff', padding: '1.4rem', display: 'flex', flexDirection: 'column', gap: '1.1rem' }}>\n <div style={{ display: 'flex', gap: '0.9rem', flexWrap: 'wrap' }}>\n <Card title=\"Typed tokens\">\n <code>primeLadder('orange')</code> reproduces the guide exactly — in TypeScript,\n CSS, or JSON.\n </Card>\n <Card title=\"Rules as code\">\n Contrast, coverage, and colorway legality ship as functions and tests, not PDFs.\n </Card>\n <Card title=\"One version\">\n The portal, asset bundles, and this package all build from the same tag.\n </Card>\n </div>\n\n <div\n style={{\n background: v('orange-tint-30'),\n color: v('prime-maroon'),\n borderRadius: 6,\n padding: '0.7rem 1rem',\n fontSize: '0.8rem',\n fontWeight: 700,\n }}\n >\n Heads up — this entire mock is styled from @praecipio/brand/css custom properties.\n View source: there is not a single hard-coded brand hex here.\n </div>\n\n <form style={{ display: 'flex', gap: '0.6rem', alignItems: 'center', flexWrap: 'wrap' }} onSubmit={(e) => e.preventDefault()}>\n <label style={{ fontSize: '0.8rem', fontWeight: 700, color: v('neutral-ink') }}>\n Stay in the loop\n </label>\n <input\n placeholder=\"you@praecipio.com\"\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 6,\n padding: '0.5rem 0.8rem',\n fontFamily: v('font-body'),\n fontSize: '0.8rem',\n flex: '1 1 160px',\n }}\n />\n <button style={button(v('prime-navy'), '#fff')}>Subscribe</button>\n </form>\n </div>\n\n {/* footer */}\n <div\n style={{\n background: v('prime-navy'),\n color: '#fff',\n padding: '0.8rem 1.2rem',\n fontSize: '0.7rem',\n opacity: 0.95,\n }}\n >\n © Praecipio — every color, font stack, and spacing decision above came from{' '}\n <code>@praecipio/brand</code>.\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","surface","jsx","jsxs"]}
1
+ {"version":3,"sources":["../../src/react/SwatchGrid.tsx","../../src/react/Combinator.tsx","../../src/react/Sampler.tsx"],"sourcesContent":["// Swatch grid rendered FROM the library — the portal documents the palette\n// with the palette. If @praecipio/brand changes, this page changes.\nimport { palette, prime, primeLadder, CMYK_INTENT } from '../index.js';\n\nexport function SwatchGrid() {\n return (\n <div className=\"swatch-grid\" title={`CMYK: ${CMYK_INTENT}`}>\n {palette.map((c) => {\n const isPrime = c.tier === 'prime';\n const l = isPrime ? primeLadder(c.name as keyof typeof prime) : null;\n return (\n <div className=\"swatch\" key={c.name}>\n <div className=\"swatch-chip\" style={{ background: c.hex }} />\n {l && (\n <div className=\"swatch-ladder\">\n {[...l.shades].reverse().map((hex) => (\n <span key={hex} style={{ background: hex }} />\n ))}\n <span style={{ background: l.base }} />\n {l.tints.map((hex) => (\n <span key={hex} style={{ background: hex }} />\n ))}\n </div>\n )}\n <div className=\"swatch-meta\">\n <strong>{c.name}</strong> <em>({c.tier})</em>\n <br />\n {c.hex} · {c.pantone}\n <br />\n CMYK {c.cmyk.join('.')}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","// Brand combinator: shuffles LEGAL combinations of surface, logo variant,\n// accent, and arrangement — legality comes from the same @praecipio/brand\n// rules the packages ship, so illegal combos are unrepresentable. Each\n// result includes a copy-pastable prompt for asking Claude to compose it.\nimport { useMemo, useState } from 'react';\nimport { prime, accent, neutral, primeLadder, contrast, luminance } from '../index.js';\n\ninterface Surface {\n label: string;\n hex: string;\n kind: 'light' | 'dark';\n}\n\n// kind is derived, not hand-labeled — the library's luminance() decides\nconst surface = (label: string, hex: string): Surface => ({\n label,\n hex,\n kind: luminance(hex) > 0.35 ? 'light' : 'dark',\n});\n\nconst surfaces: Surface[] = [\n surface('white', '#FFFFFF'),\n surface('prime-teal', prime.teal.hex),\n surface('prime-maroon', prime.maroon.hex),\n surface('prime-navy', prime.navy.hex),\n surface('teal-shade-80', primeLadder('teal').shades[1]),\n surface('navy-shade-80', primeLadder('navy').shades[1]),\n surface('orange-tint-30', primeLadder('orange').tints[2]),\n surface('teal-tint-40', primeLadder('teal').tints[3]),\n surface('gray-faint', neutral['gray-faint'].hex),\n];\n\n// digital-legal logo treatments only (black/white are print-only)\nconst logoFor = (s: Surface, orient: string) => {\n const name = { hori: 'Hori', verti: 'Verti', logomark: 'Logomark' }[orient];\n return s.kind === 'light'\n ? { file: `Praecipio_${name}_RGB.png`, visual: 'primary', dir: `${orient}/primary` }\n : orient === 'logomark'\n ? { file: 'Praecipio_Logomark_White.png', visual: 'white (logomark exception on dark)', dir: 'logomark/white' }\n : { file: `Praecipio_${name}_RVRS_Light_RGB.png`, visual: 'reverse', dir: `${orient}/reverse` };\n};\n\nconst orients = ['hori', 'verti', 'logomark'];\nconst arrangements = [\n 'hero: logo top-left, headline centered-left, accent callout chip lower-right',\n 'centered: logomark above headline, generous clearspace, single accent rule below',\n 'split: left half surface color with logo + headline, right half white with body text',\n 'badge: content leads, logomark discreet in the corner (after the full logotype)',\n];\n\nconst pick = <T,>(arr: T[]): T => arr[Math.floor(Math.random() * arr.length)];\n\nfunction legalAccent(surface: Surface): { label: string; hex: string } {\n const candidates = Object.values(accent)\n .map((c) => ({ label: `accent-${c.name}`, hex: c.hex }))\n // accents never as text on white; as graphic elements require 3:1 on the surface\n .filter((c) => contrast(c.hex, surface.hex) >= 3);\n return candidates.length ? pick(candidates) : { label: 'accent-peach', hex: accent.peach.hex };\n}\n\nfunction makeCombo() {\n const surface = pick(surfaces);\n const orient = pick(orients);\n const logo = logoFor(surface, orient);\n const acc = legalAccent(surface);\n // any text color that passes WCAG AA on the surface is legal — shuffle picks\n const textCandidates = [\n { label: 'neutral-ink', hex: neutral.ink.hex },\n { label: 'white', hex: '#FFFFFF' },\n ].filter((t) => contrast(t.hex, surface.hex) >= 4.5);\n const text = pick(textCandidates);\n const arrangement = pick(arrangements);\n return { surface, orient, logo, acc, text, arrangement };\n}\n\nfunction prompt(c: ReturnType<typeof makeCombo>): string {\n return [\n 'Compose a Praecipio-branded graphic using @praecipio/brand:',\n `- surface: ${c.surface.label} (${c.surface.hex}) — keep prime coverage >= 60%`,\n `- logo: ${c.orient} orientation, ${c.logo.visual} treatment (build/logo/${c.logo.dir}), min width 80px, clearspace = logomark height`,\n `- text: ${c.text.label} (${c.text.hex}), headings Freight Sans Pro, body Nunito Sans`,\n `- accent: ${c.acc.label} (${c.acc.hex}) for graphic elements only — never as text on white`,\n `- arrangement: ${c.arrangement}`,\n '- rules: no accent-color gradients, no drop shadows, no rotation, patterns <= 15% opacity multiply',\n ].join('\\n');\n}\n\nexport function Combinator({ assetBase }: { assetBase: string }) {\n const [combo, setCombo] = useState(makeCombo);\n const [copied, setCopied] = useState(false);\n const text = useMemo(() => prompt(combo), [combo]);\n\n const copy = () => {\n navigator.clipboard.writeText(text).then(() => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1500);\n });\n };\n\n const logoSrc = `${assetBase}assets/gallery/logo/${combo.logo.dir}/${combo.logo.file}`;\n return (\n <div className=\"combinator\">\n <div className=\"combinator-bar\">\n <button onClick={() => setCombo(makeCombo())}>⟳ shuffle</button>\n <button onClick={copy}>{copied ? 'copied ✓' : 'copy prompt'}</button>\n <span className=\"combinator-meta\">\n {combo.surface.label} · {combo.orient}/{combo.logo.visual} · {combo.acc.label}\n </span>\n </div>\n <div className=\"combinator-preview\" style={{ background: combo.surface.hex }}>\n <img src={logoSrc} alt=\"logo\" style={{ maxWidth: 180, maxHeight: 90 }} />\n <div style={{ color: combo.text.hex, fontWeight: 800, fontSize: '1.3rem' }}>\n Building Connected Enterprises\n </div>\n <div style={{ color: combo.text.hex, opacity: 0.85, fontSize: '0.8rem' }}>\n Real solutions for real challenges — strategy, process, and people, aligned.\n </div>\n <div\n style={{\n background: combo.acc.hex,\n height: 8,\n width: 96,\n borderRadius: 4,\n }}\n />\n <div style={{ color: combo.text.hex, opacity: 0.6, fontSize: '0.65rem' }}>\n {combo.arrangement}\n </div>\n </div>\n <pre className=\"combinator-prompt\">{text}</pre>\n </div>\n );\n}\n","// Sampler: a mock product UI composed ONLY from the published consumer\n// surface — `@praecipio/brand/css` custom properties and the library's\n// legality rules. What this renders is exactly what an external build\n// (a Cloudflare container UX, the marketing site) gets from the package:\n// no portal-private styles, no assets, just tokens.\nimport type { CSSProperties, ReactNode } from 'react';\n\nconst v = (token: string) => `var(--praecipio-${token})`;\n\nconst button = (bg: string, fg: string, outline?: string): CSSProperties => ({\n background: bg,\n color: fg,\n border: outline ? `2px solid ${outline}` : 'none',\n borderRadius: 6,\n padding: '0.55rem 1.2rem',\n fontFamily: v('font-body'),\n fontWeight: 700,\n fontSize: '0.85rem',\n cursor: 'pointer',\n});\n\nconst heading: CSSProperties = { fontFamily: v('font-heading'), fontWeight: 800, margin: 0 };\n\nfunction Card({ title, children }: { title: string; children: ReactNode }) {\n return (\n <div\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 8,\n padding: '1rem 1.1rem',\n background: '#fff',\n flex: '1 1 180px',\n }}\n >\n <h4 style={{ ...heading, color: v('prime-maroon'), fontSize: '1rem', marginBottom: '0.4rem' }}>\n {title}\n </h4>\n <p style={{ margin: 0, fontSize: '0.8rem', color: v('neutral-ink'), lineHeight: 1.5 }}>\n {children}\n </p>\n <a href=\"#sampler\" style={{ color: v('prime-teal'), fontWeight: 700, fontSize: '0.8rem' }}>\n Learn more →\n </a>\n </div>\n );\n}\n\n// Prime coverage stays >= 60% (navy bar, teal hero, navy footer dominate);\n// accents appear only as graphic elements on dark primes; no accent gradients.\nexport function Sampler() {\n return (\n <div\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 10,\n overflow: 'hidden',\n fontFamily: v('font-body'),\n }}\n >\n {/* app bar */}\n <div\n style={{\n background: v('prime-navy'),\n color: '#fff',\n display: 'flex',\n alignItems: 'center',\n gap: '1.4rem',\n padding: '0.7rem 1.2rem',\n }}\n >\n <span style={{ ...heading, fontSize: '1.05rem' }}>Praecipio</span>\n {['Products', 'Solutions', 'Docs'].map((l) => (\n <span key={l} style={{ opacity: 0.8, fontSize: '0.8rem' }}>\n {l}\n </span>\n ))}\n <button style={{ ...button(v('prime-orange'), '#fff'), marginLeft: 'auto' }}>\n Get started\n </button>\n </div>\n\n {/* hero */}\n <div style={{ background: v('teal-shade-80'), color: '#fff', padding: '2.2rem 1.4rem' }}>\n <h2 style={{ ...heading, fontSize: '1.7rem', maxWidth: '24ch' }}>\n Intelligence Gateway\n </h2>\n <p style={{ opacity: 0.85, maxWidth: '52ch', fontSize: '0.9rem', lineHeight: 1.55 }}>\n One consistent surface for every product we ship — because the colors, type, and\n rules on this page are imported, not copied.\n </p>\n <div style={{ background: v('accent-mint'), height: 6, width: 88, borderRadius: 3, margin: '0.9rem 0 1.1rem' }} />\n <div style={{ display: 'flex', gap: '0.7rem' }}>\n <button style={button(v('prime-orange'), '#fff')}>Try it now</button>\n <button style={button('transparent', '#fff', '#fff')}>Read the docs</button>\n </div>\n </div>\n\n {/* content */}\n <div style={{ background: '#fff', padding: '1.4rem', display: 'flex', flexDirection: 'column', gap: '1.1rem' }}>\n <div style={{ display: 'flex', gap: '0.9rem', flexWrap: 'wrap' }}>\n <Card title=\"Typed tokens\">\n <code>primeLadder('orange')</code> reproduces the guide exactly — in TypeScript,\n CSS, or JSON.\n </Card>\n <Card title=\"Rules as code\">\n Contrast, coverage, and colorway legality ship as functions and tests, not PDFs.\n </Card>\n <Card title=\"One version\">\n The portal, asset bundles, and this package all build from the same tag.\n </Card>\n </div>\n\n <div\n style={{\n background: v('orange-tint-30'),\n color: v('prime-maroon'),\n borderRadius: 6,\n padding: '0.7rem 1rem',\n fontSize: '0.8rem',\n fontWeight: 700,\n }}\n >\n Heads up — this entire mock is styled from @praecipio/brand/css custom properties.\n View source: there is not a single hard-coded brand hex here.\n </div>\n\n <form style={{ display: 'flex', gap: '0.6rem', alignItems: 'center', flexWrap: 'wrap' }} onSubmit={(e) => e.preventDefault()}>\n <label style={{ fontSize: '0.8rem', fontWeight: 700, color: v('neutral-ink') }}>\n Stay in the loop\n </label>\n <input\n placeholder=\"you@praecipio.com\"\n style={{\n border: `1px solid ${v('neutral-gray-faint')}`,\n borderRadius: 6,\n padding: '0.5rem 0.8rem',\n fontFamily: v('font-body'),\n fontSize: '0.8rem',\n flex: '1 1 160px',\n }}\n />\n <button style={button(v('prime-navy'), '#fff')}>Subscribe</button>\n </form>\n </div>\n\n {/* footer */}\n <div\n style={{\n background: v('prime-navy'),\n color: '#fff',\n padding: '0.8rem 1.2rem',\n fontSize: '0.7rem',\n opacity: 0.95,\n }}\n >\n © Praecipio — every color, font stack, and spacing decision above came from{' '}\n <code>@praecipio/brand</code>.\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","surface","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praecipio/brand",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "Praecipio brand as code: palette, typography, logo rules, React components, and generated CSS tokens. Decompiled from Brand Style Guide v2.01.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "repository": {
@@ -26,6 +26,7 @@
26
26
  "./css": "./dist/praecipio.css",
27
27
  "./mkdocs.css": "./dist/praecipio-mkdocs.css",
28
28
  "./tokens.json": "./dist/praecipio.json",
29
+ "./themes.json": "./dist/praecipio-themes.json",
29
30
  "./hubspot/*": "./dist/hubspot/*",
30
31
  "./tokens": {
31
32
  "types": "./dist/index.d.ts",
@@ -46,7 +47,7 @@
46
47
  }
47
48
  },
48
49
  "scripts": {
49
- "build": "tsup src/index.ts src/react/index.ts --format esm --dts --sourcemap --external react && pnpm run generate && cp ../../build/tokens/praecipio.css ../../build/tokens/praecipio-mkdocs.css ../../build/tokens/praecipio.json dist/ && rm -rf dist/hubspot && cp -r ../../build/hubspot dist/hubspot",
50
+ "build": "tsup src/index.ts src/react/index.ts --format esm --dts --sourcemap --external react && pnpm run generate && cp ../../build/tokens/praecipio.css ../../build/tokens/praecipio-mkdocs.css ../../build/tokens/praecipio.json ../../build/tokens/praecipio-themes.json dist/ && rm -rf dist/hubspot && cp -r ../../build/hubspot dist/hubspot",
50
51
  "test": "vitest run",
51
52
  "generate": "tsx generate/css.ts && tsx generate/ase.ts && tsx generate/mkdocs-css.ts && tsx generate/hubspot.ts",
52
53
  "generate:pattern": "tsx generate/pattern-cover.ts"
@@ -1 +0,0 @@
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"]}