Repository navigation
v1.4.0: Brand Book and website tokens, color roles, a shared brand guard, the Brand Book highlighter, supergraphics that follow the book, and the spec in the package - #5
Merged
Conversation
tokens.json has carried fontWeight (regular 400, medium 500, semibold 600) since v1.0.0, but no output exposed it, so consumers hand-wrote their own aliases. - brand.css and the supergraphics prelude: --mfb-weight-regular/-medium/-semibold - theme.css (Tailwind 4): --font-weight-regular/-medium/-semibold, plus --font-weight-normal with the regular value (Tailwind's own name for 400) - tailwind.js (Tailwind 3): theme.extend.fontWeight with the same names; it extends Tailwind's scale, so font-normal and font-bold keep working - index.js: export fontWeight Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Brand Book Halftones slide (918:3730, text 918:3737) gives two highlight caps: #F7E6FF for cutout portraits and #EEEEEE for full portraits, both with shadow #45265B. tokens.json had the cutout pair only. - tokens.json: geometry.halftone-highlight-full #EEEEEE (prose, figma:918:3730) - brand.css and the supergraphics prelude: --mfb-halftone-highlight, --mfb-halftone-highlight-full, --mfb-halftone-shadow (kept out of the palette and the Tailwind colour utilities, as the tokens say) - canon: .sg-halftone-cutout reads the variables instead of hex literals - brand-spec Rule 4: the full-portrait highlight comes from the token Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
.sg-headline, .sg-body, .sg-label, .sg-cta, .sg-info-bar (and its date and location) and .sg-cover__title wrote 'IBM Plex Sans', sans-serif and numeric weights by hand. They now read var(--mfb-font-heading|body) and var(--mfb-weight-*), so the Brand Book's system fallback, Arial (918:2375), applies and consumers no longer need local font-family overrides. .sg-cover__title read var(--mfb-font-h2, 58px), a variable that never existed, so it always fell back to the literal. It now reads var(--mfb-size-h2) (58px, the same rendered size). The supergraphics prelude now carries the non-deprecated font families and the font sizes, so the file stays standalone. Mono is left out of it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Brand Book Highlighter slide (918:2874) says: one word per heading, "covering up to 80% of the word length. Do not alter its appearance". Its vectors draw a thin tapered line at the baseline, behind the glyphs, starting a little in from the first letter. The package had no base class, and the written rule (a linear-gradient band) painted a band about twice as thick, lower and across the whole word. - tokens.json, geometry: highlighter-coverage 80% (prose, figma:918:2874); highlighter-aspect 26.6, highlighter-offset 0.03em and highlighter-shape (measured from the vectors 918:2883, 918:2887, 918:2893, 918:2898 and the Brand in Use copies; node ids and ranges in each note). The $verification text defines the new sourceKind "measured". - build: the four values join the geometry gate, so the build refuses when the canon's --sg-highlighter-* declarations disagree with tokens.json, and they are emitted into brand.css and the supergraphics prelude. - canon: a base .highlighter (inline-block) whose ::after is an inline-block line sitting on the baseline: width 80% of the word, centred by a negative margin, thickness from aspect-ratio (so it scales with the word, as in the book), shape from clip-path, moved down by the measured offset, painted behind the text. Orange-300 by default; white inside the existing orange contexts (.sg-spotlight--orange, .sg-bg-orange, which keep their white text), .sg-cover--orange and .sg-bg-gray. --sg-highlighter-color overrides it on other orange or grey surfaces. - brand-spec Rule 2 and checklist item 4 describe the measured construction. - verify-figma.mjs lists measured tokens in its coverage census. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Both corrections derive only from --sg-angle-base and --sg-aspect; no new numbers. - .sg-para-pattern: each .sg-para is skewed about its centre, so the first shape of a row reaches tan(angle) x row height / 2 past the row's left edge, where the pattern's overflow: hidden cut its corner off. Rows now take that inset as padding-left. Row height moves to --sg-row-h so the progressive rows (x1.25, x1.55) get their own inset. - .sg-para-frame: the counter-skewed photo used a fixed scale(1.12), which covers the parallelogram only when the frame is at least 1.92 times as wide as it is tall; at the default aspect 1.5, and on square or portrait frames, the corners showed through. The scale is now 1 + tan(angle) / --sg-aspect, the smallest that covers the frame, so --sg-aspect must be the frame's real width over height (as for the spotlight, book and halftone frames). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The colour quick reference said "Links: orange-300". The Brand Book's Colour contrast slide (918:2588) says light text goes on dark colours and dark text on light colours, and orange is a light colour. Links on light backgrounds now use purple-300 with an orange-300 underline; on dark backgrounds, orange-300 or white. Heading colours are not changed here (see the pull request description). The CSS Variables paragraph now lists the weight, halftone and highlighter variables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brand-spec.md was public in the repository but not installed, so consumer projects and their AI tools had to fetch the rules from GitHub, at whatever version master happened to be. It is now in package.json's files and in the exports map as ./brand-spec.md, so it arrives in node_modules at the pinned version. CONTRIBUTING's table and install list, the spec generator's header, the spec's Section 5 and the workflow's published-file lists (version-check and release warnings) say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README said the package was generated "Figma -> sync-brand.js". Since the build moved into this repository (the point of the closed PR #4), it is scripts/build-design-package.mjs here, from tokens.json. The README now says so, and: - documents the weight, halftone and highlighter variables and the geometry list, read from tokens.json (angles, weights, coverage) rather than written by hand - explains the base highlighter and that a consumer's own .highlighter band must go when it upgrades, or the two draw on top of each other - states the --sg-aspect rule: spotlight, book, halftone and parallelogram frames need it set to the frame's real width over height - marks as deprecated, without removing anything, the brand gradient (--mfb-gradient-brand, --mfb-gradient, bg-brand-gradient, .sg-bg-gradient: use a solid palette fill), .sg-photo-zone and the mono font (use the brand sans, whose fallback is Arial per Brand Book 918:2375) - points to brand-spec.md in node_modules This is a release pull request, so the README is reworded to the public conventions: no em-dash, "My First Bitcoin" in full. CONTRIBUTING says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re taken halftone-highlight and halftone-shadow cited figma:918:4126, the Parallelogram Frames slide, which has no halftone text. Both now cite the Halftones slide 918:3730 (text node 918:3737), as halftone-highlight-full does, verified 2026-10-06. The quotes in the token notes are now verbatim: the Highlighter sentence goes on past "Do not alter its appearance", and the Halftones text is two lines, not one sentence. The measured source kind said the values were read off "by a person"; they were read through the Figma MCP by an AI session. $verification and the Figma check's coverage line now say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…color
- .highlighter sets text-align: left and text-indent: 0. The line takes
10% less room than the word, so an inherited center or right alignment
moved the word right by 5% or 10% of its width and ate the space after it.
- The white line no longer applies on .sg-bg-gray: that is gray-200, and a
white line on it cannot be seen. The Brand Book's white-on-grey example is
a mid grey (close to gray-500); README and spec say to set
--sg-highlighter-color there.
- The white line now applies on every orange-300 surface of the package:
.sg-spotlight-frame--orange, .sg-book-frame--orange and
.sg-halftone-cutout--orange-bg join the list.
- The orange variants no longer turn the word itself white. On the
Highlighter slide the word stays dark on orange and only the line is
white ("Do not alter its appearance"; Color Contrast 918:2588).
- highlighter-offset is 0.054em: the distance from the baseline to the
center of the line's box, which is what the CSS positions, on the cited
node 918:2883 (checked against a raster of the slide). 0.03em measured
to the shape's average centerline, so the line sat about 1px high at 48px.
- Spec Rule 2 wording: the twelve copies have small variants, thickness is
proportional to the word's width, and the quote is the full sentence.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- README gains "Upgrading from v1.3.0": delete a local .highlighter band and any display or text-align override on it; remove local padding added around .sg-para-pattern for the slant (rows now inset themselves); set --sg-aspect on parallelogram frames, whose photo scale now depends on it; the :root prelude of supergraphics.css now also sets the font, size, weight and halftone variables; .sg-cover__title reads --mfb-size-h2; and Tailwind 4 projects that reset --font-weight-* must do it before importing theme.css, or the package's weights go too. - The links rule cites the Color Contrast slide's evidence (every orange is paired with dark text) and marks the orange-300 underline as this package's recommendation, not a Brand Book rule. - New prose uses US spelling, as the Brand Book and the rest of the spec do. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… is silent) - Where the Brand Book defines a value, its value is the token, cited by node. - Where the book is silent, the value the live website myfirstbitcoin.org uses may become the token, declared with its exact origin on the site's main branch: sourceKind "declared", source "myfirstbitcoin.org@<commit>:<file>:<line>". The site was built following the Brand Book, and its CSS is public. - A website value that contradicts the Brand Book is never imported; where the site has several near-duplicates, no token is made until someone picks one; Quentin or Patrick decides, as for any change here. - The source kinds are restated as tokens.json's $verification defines them, with "measured" covering a node's rendered fill as well as its geometry, and "declared" covering a website value or a value this package recommends. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Under the source rule (CONTRIBUTING), tokens.json gains what the Brand Book defines and the package did not carry, and the values the book is silent on as the live website (main branch at 6368b2a) uses them, each with its source. No existing value, variable, utility or export changes. From the Brand Book (figma provenance, prose or measured): - lineHeight and letterSpacing per type level (specimen 918:2323: 1 for h1 to h4 and quote, 1.1 for h5 and h6, 1.2 for body and label; no tracking on any brand text style). - logo: minimum 120px wide (63px tall) on screen, 25mm in print, aspect 1.904, clear space and corner margin 0.5 x the logo height (918:2681, 918:2714). - colorRole: heading, body, link, muted, border, highlighter and logo colors on light, dark and orange backgrounds, as aliases of palette colors only. Headings and body on light: black (918:2990); on dark: white; on orange: black, CTAs included (918:4183 to 918:4185). Links on light: purple-300 with an orange-300 underline, declared as this package's recommendation; on dark: orange-300, the website's. - shapeTone: a shape one step lighter than its base (918:3604). - CMYK for all 17 colors, and geometry: para-edge-ratio 0.572, pattern-row-step 1.2, pattern-row-gap 0, halftone-scale 2.5. - Provenance: angle-base is measured (13.00deg on 918:4200, the logo icon and five photo frames); base-h-ratio cites the visible 918:4219; logo-icon-h (40px) is declared, as the book states no pixel value. - Color descriptions the book contradicts are corrected: purple-300 is the primary color for surfaces and shapes, not a heading color; text on light backgrounds is black, not gray-900; orange is never text on light. Declared from the website (myfirstbitcoin.org@6368b2a:<file>:<line>): spacing scale and semantic spacing (gutter, section, header gap, block end), radius, three shadows tinted with palette colors, easing and durations, container widths, fluid type floors and slopes (the caps are the book's sizes and the build refuses any other), breakpoints, layers, media ratios, the touch target and the link underline offset. Website values that contradict the book (10 degree slant, the hero cut, the thick animated highlighter, duotone, IBM Plex Mono, off-palette tiles, uppercase labels, orange text on light, white text on orange) are not imported. Build: one GROUP_MAP says where each new group is emitted (brand.css as --mfb-<family>-<key>; theme.css and tailwind.js with mfb- prefixed keys, type levels or <element>-on-<surface> roles; index.js named exports). The build refuses an unmapped group, a geometry token that is neither gated against the canon nor listed as token-only, a key equal to a Tailwind 3 or 4 default, overlapping keys, a role that is not a palette alias, a fluid size whose cap is not the book's, and a hex in a new brand.css variable. Checked against the class names of ten consumer projects: 0 utilities or theme values changed in Tailwind 4.2.2, 4.3.3 and 3.4.19. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ack text on light brand-spec.md gains, each value filled from tokens.json with its source (a Brand Book node, or the website file and line it was declared from): - Color roles by background, shape tones, and CMYK in the color table. - Type relationships: line height, letter spacing and the fluid size per level, weights per role, 40px between a heading and its text and 48px between a quote and its label (measured on 918:2990 and 918:3005). - Logo: minimum size, clear space, corner margin and color by background. - Layout and spacing, radius and shadow, motion, breakpoints, layers, media ratios, and the website values that are not imported because they contradict the Brand Book. Corrections: - Headings and text on light backgrounds are black (Type Relationships 918:2990), not purple-300 headings and gray-900 text; text on orange is black, buttons included. The quick reference says which supergraphics classes still set white text on orange. - Logo files: the purple logo on greys up to gray-500, the black one on orange; clear space is half the logo height, not the height of the B. - Halftone cutouts also sit on purple-200; the Canva scale is a token. - Rule 7 states the measured pattern step (1.2) and row gap (0), and that .sg-para-pattern does not follow them yet. - Slide labels: Parallelogram 918:4189, Patterns 918:4212, Frames 918:4126, Book Panel 918:3757, Spotlights and Books in Use 918:3716. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A zero-dependency Node script in the package's files (not a package.json script), which a project runs after its build: node node_modules/@myfirstbitcoin/design/brand-check.mjs [--src src] [--dist dist] It generalises the guards two of My First Bitcoin's sites already ran, and reads every value it compares with from the tokens.json next to it. It fails on color literals and named colors, font families other than the brand variables, skew, rotate and angle literals that are not quarter turns, hand-rolled clip-path shapes, uppercase, gradients (the deprecated brand gradient included) and smooth color filters, Tailwind color utilities outside the palette and the roles, weights above 600, translucent brand shapes, and raw values that have a token (a spacing, radius, duration, easing, container width, font size, font weight or shadow literal equal to a token value, with the token to use). In the built CSS it fails when --sg-angle-base is missing or not the token value, when a --color-* is not a palette color or a role, and on uppercase or the mono family. An allowlist (each entry with its reason) covers third-party marks; --warn reports a rule without failing, for a step-by-step adoption. scripts/brand-check.test.mjs plants one violation per rule on known lines, a clean file that must pass, an allowlist and --warn; scripts/check.mjs runs it. README documents the guard; CONTRIBUTING lists it with the published files; the workflow counts it as a published file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ences listed Sources (tokens.json, under the source rule): - muted-on-dark is this package's recommendation (source "declared"): the website's value at the cited line is white at 72%, which is not imported. - link-on-dark names global.css:47, where the link color resolves, and its description is limited to purple-300 and purple-400; links on purple-200 and the dark greys are white and underlined. - mediaRatio.square cites a line that carries 1 / 1; container.measure cites the article width. Every website-declared note gives its use count, all counted the same way (git grep over src at 6368b2a); the spacing scale's notes say the site declares it but never reads it. - The breakpoint tokens are held back: the site has 13 max-width values and no convention, so under rule 4 none is a token until one is picked. - base-h-ratio quotes 918:4219 word for word. Surfaces are named exactly for heading-on-dark, the highlighter roles and the link underline; logo-on-orange says the Brand Book also shows white. - Two older notes no longer name a person or an internal project, and the supergraphics.css header and a canon comment no longer name internal places; published comments and the tokens.json description write My First Bitcoin in full. CONTRIBUTING names roles, not people, in the new source rule. Build: font weights that Tailwind already names must keep Tailwind's value, and the README says so. README: the brand guard's rules, its default warnings and what it does not check; Tailwind 4 notes for code blocks and shadows; text on orange; no "typed --sg-aspect". package.json exports brand-check.mjs. Spec: a table of the supergraphics classes that differ from the Brand Book and what to set instead; links on light always underlined; label size against body text on small screens; breakpoints not declared yet. brand-check.mjs: fewer false positives (@font-face, family names in data, palette words in script data, Inkscape metadata, scale-only matrices, zero skew, var(--font-sans), Tailwind utility definitions and its --default-mono-font-family in built CSS) and more drift caught (SVG rotations, blend modes, arbitrary named colors, translucent sg-* via opacity-[...] or inline style, small-cap features, redefined package variables, built angle overrides, slant geometry computed from the angle, hand-rolled highlighter bands and bars). Spacing literals, orange text, purple headings and typed capitals warn by default; --error makes them fail. The test plants a line for each. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ok type relationships The supergraphics canon now reads the color roles and the type relationships: - .sg-cta, .sg-bg-orange and .sg-cover--orange set black text on orange-300 (9.2:1; white was 2.3:1) - .sg-bg-white, .sg-bg-gray and .sg-info-bar--on-light set black instead of gray-900 - the light info bar's date is black instead of orange-300; the date's small line loses its 75% opacity and takes gray-700 on light and gray-400 on dark - .sg-headline and .sg-cover__title: line height 1 and no tracking (were 1.05 and -0.03em); the comment that called -0.03em book tracking is corrected - .sg-label: Regular, line height 1.2, no tracking (was Medium, 1.5px); .sg-body reads the token The 6px radius on .sg-para-frame and .sg-para-accent and the 40px radius on .sg-cta have no radius token of that value, so they stay and the spec lists them. New declared token lineHeight.body-long (1.7), from the website's article prose, for long reading only and flagged for review; the Brand Book's body line height is for body copy next to a heading. The build allows it as a level variant and refuses a canon that reads a variable the supergraphics prelude does not set; the prelude now carries the roles, line heights and letter spacing. README upgrade notes and the spec list every visible change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… Tailwind builds Source rules now also report: - angles in SVG patternTransform and gradientTransform attributes, unitless rotate and skew props in script code (rotate: -15), and rotate-x/y/z classes - named colors in custom properties, canvas fillStyle and style objects (a CSSProperties object, or a second property on the same line) - hex colors inside arbitrary utilities (after an underscore) and in values continued on the next line, which were taken for id selectors - translucent orange or purple fills: opacity or fill-opacity beside the fill, alpha modifiers such as bg-orange-200/10, color-mix with transparent - hand-rolled highlighters drawn as orange pseudo-elements sized in em or %, put behind the text or named like a highlight, inset orange shadows, and after:/before: orange utilities The built CSS is now read declaration by declaration, nesting included: every declaration of --sg-angle-base and --sg-angle-alt must have the token value (rules, @Property initial-value, style attributes in built HTML); uppercase is reported outside utility class definitions, whatever variant or important marker Tailwind 3 or 4 gives them, since the source check reports where a class is used; the mono rule reads only font-family declarations, so Tailwind 4's --default-mono-font-family and code element base styles pass. Built findings carry line numbers. The test plants each case on its own line, in the source and the built CSS, and keeps Tailwind 3 and Tailwind 4 build output as clean controls. The README documents every option and exit code. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ard that sees more and reads prose as prose
Canon (src/supergraphics.canon.css, no comment added):
- An .sg-info-bar without a variant sitting directly in .sg-bg-white or
.sg-bg-gray, or in one of the package's orange surfaces, now has a black
date (heading-on-light, heading-on-orange). On orange its orange date was
invisible (1.0:1); on white it was 2.3:1. On purple surfaces and photos
it stays orange-300, and the --on-dark variant keeps its orange date.
- .sg-headline--h5 and .sg-headline--h6 set the book's 1.1 line height for a
headline set at those sizes; .sg-headline itself stays at 1 (H1 to H4,
quotes) and sets no size.
- .sg-body sets --mfb-tracking-body, so it no longer inherits tracking.
Brand guard (brand-check.mjs, with planted and clean lines in its test):
- Uppercase: any case, quoted style-object keys, and the class as a lone
string (clsx('uppercase'), a ternary, class:list).
- Prose is not read as values: hex and color functions in text between
markup tags are skipped, a color function needs its parenthesis directly
after the name, color() needs a color space, and a declared function
(function color(name)) is code. Names such as id and selector are skipped.
- New warnings: gray-900 text (text-color), translucent text, letter
spacing. Warn by default, like the other rules that cannot see the page.
- Also caught: the font shorthand and --font-* theme variables, SVG text
rotate, SVG gradient elements, SVG clipPath polygons, an inset orange
shadow without blur, a thick orange underline, an orange mark element,
filter: opacity() beside a brand fill, and orange or purple borders mixed
with transparent.
- No longer reported: hard-stop gradients that blend nothing (unless
orange), opacity in a disabled state, // comments in SCSS, Sass and Less,
an angle written 24.0deg; a built .uppercase compounded with another
class (.eyebrow.uppercase) is now reported instead of exempt.
Docs: README and brand-spec say all of this; the info bar's type values join
the spec's table of classes that differ from the Brand Book; gray-700 on
white is 5.1:1, not 5.2:1. CONTRIBUTING no longer says the website's source
is public: its repository is private, and what the site serves is public.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The website's source repository is private and this one is public, so a website-declared token no longer names a file, directory or line of it. Its source is now "myfirstbitcoin.org@<commit>, <CSS name>": the custom property, selector and property, or inline property (with where it is used) that carries the value in the CSS and pages the site serves, for example "myfirstbitcoin.org@6368b2a, --r-lg". The deciders named in CONTRIBUTING keep the exact lines outside the repository. - tokens.json: the 52 website sources move to the new form; notes drop file and line references and component names (use counts stay, counted with git grep in the site's source at 6368b2a). No value changes. - CONTRIBUTING source rule 2 and $verification describe the new form. - The spec generator reads the new form, shows the CSS name, and refuses a website source that names a file, a directory or a line. - README and brand-spec.md say what a website source names; regenerated. - The brand guard's test fixtures and allowlist example use src/ui and src/styles/site.css, generic consumer paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Who decides
The deciders named in CONTRIBUTING.md decide this pull request. Merging it releases v1.4.0 (package.json goes from 1.3.0 to 1.4.0, and the release job tags the merge commit). Nothing reaches a project until that project raises its pin.
Upgrading needs action from projects. The
.highlighterclass itself now draws the Brand Book's thin line, so a project that styles.highlighterwith its own band must delete that band in the same commit that raises its pin. The supergraphics classes also change how they look where they contradicted the Brand Book: black text on orange and on light surfaces (an info bar's date included), and the book's line height and tracking on headlines, labels and body text (item 6 below). No class, variable, export or Tailwind key is removed or renamed, and no variable or Tailwind key changes value; everything else is added. Three choices to make:.highlighteras it was in v1.3.0, deprecated.Four values are this package's own recommendations, neither Brand Book nor website values; each needs a yes or a different value (see "Package recommendations" below).
Why
The package did not carry much of what the Brand Book already defines (type relationships, logo size and clear space, color roles, CMYK, pattern geometry), and nothing at all for spacing, radius, shadow, motion or widths, so every project wrote those values by hand and they drifted. The live website, myfirstbitcoin.org, was built following the Brand Book, so where the book is silent its values are the best evidence there is, and they can come back into the pipeline with their source. Where the website contradicts the book, the book wins and the website value stays out.
21 commits;
node scripts/check.mjspasses on every commit.The source rule (CONTRIBUTING.md)
mFIc75UUSyftaqnNUQgjLX, page262:2) defines a value, its value is the token, cited by node."sourceKind": "declared","source": "myfirstbitcoin.org@<commit>, <CSS name>", with the number of uses in the note. The CSS name is what carries the value in the CSS and pages the site serves, which are public: a custom property (myfirstbitcoin.org@6368b2a, --r-lg), a selector and property (myfirstbitcoin.org@6368b2a, .article-prose line-height), or a property set inline, with where it is used (myfirstbitcoin.org@6368b2a, box-shadow (inline, media frames)). The site's source repository is private and this one is public, so no file, directory or line of it is named here; the deciders named in CONTRIBUTING keep the exact lines outside the repository. The spec generator refuses a website source in any other form, or one that names a file or a line.918:2588: dark text on light colors and on every orange), gray-900 headings and text (the book's are black), heading line height 1.05 and body line height 1.55 in page sections (the book's are 1 and 1.2; the website's 1.7 for article text is declared separately, for long reading only, and is an open question).tokens.json's$verificationand CONTRIBUTING define the source kinds and the website citation the same way:measurednow covers a node's rendered fill as well as its geometry (read through the Figma MCP, with node ids in the note), anddeclaredcovers a website value (with its site source) or this package's own recommendation ("source": "declared", with the reason).What changes
New in this round
Brand Book values in tokens.json, each with its Figma node:
lineHeightandletterSpacingper type level: 1 for h1 to h4 and quote, 1.1 for h5 and h6, 1.2 for body and label (type specimen918:2323); no tracking on any brand text style.logo: minimum 120px wide (63px tall) on screen and 25mm in print (918:2711), aspect 1.904, clear space and corner margin 0.5 x the logo height (measured on918:2681and918:2714).colorRole: heading, body, muted, link, link underline, border, highlighter and logo colors on light, dark and orange backgrounds, as aliases of palette colors only, each description naming the surfaces it holds on. Headings and body on light: black (Type Relationships918:2990, the specimen, the posters); on dark: white (on gray-600, 24px and up only); on orange: black, CTAs included (program card918:4183to918:4185). Links on dark: orange-300 on purple-300 and purple-400 (the website's link color); white and underlined on purple-200 and the dark greys, where orange-300 is too faint for text (3.8:1 on purple-200). Muted on light: gray-700 (the website's). Highlighter: orange-300 on white to gray-300, white on oranges and on gray-400 and gray-500, where an orange line all but disappears. Links on light, the link underline, muted on dark and the logo on orange are this package's recommendations (below).shapeTone: a shape one step lighter than its base (purple-200 on purple-300, orange-200 on orange-300, gray-600 on gray-700;918:3604).918:2258,918:2386,918:2465).para-edge-ratio0.572,pattern-row-step1.2,pattern-row-gap0 (measured on918:4200and918:4295),halftone-scale2.5 (918:3736). The canon does not read the pattern values yet (it uses a 10px gap and steps of 1.25 and 1.55), so the build lists them as token-only, with the reason, and refuses any new geometry that is neither gated against the canon nor listed.angle-basebecomesmeasured(13.00 degrees on the base parallelogram918:4200, the logo icon and five photo frames);base-h-ratioquotes the visible918:4219word for word ("The base parallelogram height equals 2× the height of the logo icon."; the old918:4196sits in a hidden frame), with the note that no drawing shows the 2x;logo-icon-h(40px) becomesdeclared, since the book states no pixel value.Website-declared tokens for what the book is silent on (table below): the spacing scale and semantic spacing, radius, three shadows tinted with palette colors, easing and durations, container widths, fluid type floors and slopes (the caps are the book's sizes, and the build refuses any other), layers, media ratios, the touch target and the link underline offset. Each cites the website commit and the CSS name that carries the value (rule 2 above). Every note gives its use count, all counted the same way:
git grepin the site's source at6368b2a.Emitted without touching any existing utility. One
GROUP_MAPin the build says where each new group goes:brand.cssas--mfb-<family>-<key>(roles as--mfb-<element>-on-<surface>, values byvar()andcolor-mix()of palette variables, never a hex);theme.cssandtailwind.js(theme.extendonly) withmfb-prefixed keys (rounded-mfb-lg,shadow-mfb-media,ease-mfb-out,duration-mfb-fast,max-w-mfb-page,py-mfb-section), type levels (leading-h1,tracking-h1,text-h1-fluid) or color roles (text-heading-on-light);index.jsnamed exports. The spacing scale equals Tailwind's own steps, so it gets no Tailwind keys; layers, ratios, logo and interface values go only tobrand.cssandindex.js. The build refuses an unmapped group, a key equal to a Tailwind 3 or 4 default or a static keyword, overlapping keys between groups, a role that is not a palette alias, a hex in a newbrand.cssvariable, and a font weight that would change Tailwind's value for its name (font-mediumstays 500).The spec (
brand-spec.md) gains color roles, shape tones and CMYK; type relationships (line height, tracking, fluid size per level, weights per role, 40px between a heading and its text and 48px between a quote and its label, measured on918:2990and918:3005); the logo's size, clear space and color by background; layout and spacing, radius and shadow, motion, layers and media, each value with its source; the list of website values not imported; and a table of the supergraphics classes that still differ from the Brand Book, with what to set instead (below). Corrected: headings and text on light are black (Section 3), text on orange is black, buttons included; links on light backgrounds always keep their underline; the logo files (purple logo on greys, black on orange; clear space is half the logo height, not the height of the B); halftone cutouts also sit on purple-200; Rule 7 states the measured pattern step and gap; and the slide labels (Parallelogram918:4189, Patterns918:4212, Frames918:4126, Book Panel918:3757, Spotlights and Books in Use918:3716).brand-check.mjs, one brand guard for every project. A zero-dependency Node script in the package'sfilesandexports(not a package.json script), run after a build:node node_modules/@myfirstbitcoin/design/brand-check.mjs [--src src] [--dist dist]. It generalises the guards two of My First Bitcoin's sites already ran and reads every value from the package'stokens.jsonat run time.#RRGGBBAAand hex inside arbitrary utilities included (text between markup tags is prose and is not read, so a block number such as#840000or "a color (any one)" is not a color), and named colors (in properties, custom properties, style objects, a canvasfillStyle, SVG attributes and arbitrary utilities such asbg-[teal]); font families other than the brand variables, in CSS, thefontshorthand, a--font-*theme variable or a React style object; skew, rotation and angle literals that are not quarter turns, in CSS, style objects, unitless animation props (rotate: -15), Tailwind classes, SVGtransform,patternTransformandgradientTransformattributes, or therotateattribute of SVG text, transform matrices that rotate or skew, and slant geometry computed from--sg-angle-*; hand-rolled clip-path shapes (an SVGclipPathpolygon included) and hand-rolled highlighters (atransparent 80%band, an orange pseudo-element drawn as a marker: sized in em or %, behind the text, or named like a highlight; an orangemark; an orange inset shadow, with or without blur; an orange underline 0.2em or 4px thick or more; orangeafter:orbefore:utilities); a redefinition of a variable the package defines (--mfb-*, the--sg-*geometry); uppercase (in any case, with quoted style-object keys, and the class as a lone string such asclsx('uppercase')orclass:list={['uppercase']}), small caps and small-cap font features; gradients in CSS and SVG gradient elements (the deprecated one included; a hard-stop split that blends nothing is not one, unless it draws in orange), smooth color filters and blend modes; Tailwind color utilities outside the palette and roles; weights above 600; translucent brand shapes (a class,opacity-[...], an inline style, or a highlighter color that is not a palette variable) and orange or purple fills that are not solid (opacity, fill-opacity orfilter: opacity()beside them outside a disabled state, alpha modifiers such asbg-orange-200/10, a fill or border mixed withtransparentincolor-mix()); and raw values that have a token (radius, duration, easing, container width, font size, font weight, shadow or semantic spacing, with the token to use).raw-spacing), orange text, purple headings and gray-900 text (text-color, the last also through a value given to a name such astextColor), translucent text (translucent-text: white mixed withtransparent,text-white/85), letter spacing (letter-spacing: a non-zeroletter-spacing,letterSpacingortracking-*), and words typed in capitals (typed-caps).--error RULESmakes them fail;--warn RULESturns any other rule into a warning, for step-by-step adoption.--sg-angle-baseis missing, or when any declaration of--sg-angle-baseor--sg-angle-alt(a rule, a nested rule, an@propertyinitial value, a style attribute in built HTML) has another value; when a--color-*is not a palette color or role; on uppercase or small caps outside a utility class definition (a utility that shares its compound selector with another class,.eyebrow.uppercase, is the page's own rule and is reported); and on afont-familyin the mono or serif family outside a utility class definition and the base styles of code elements. A utility definition is not a use (Tailwind 3 emits.uppercasewhen its content scanner sees the word in a comment; the source check reports the class where a page uses it), nor is Tailwind 4's--default-mono-font-family: var(--font-mono). Built findings carry line numbers.@font-facedescriptors, family names and palette words in data, Inkscape metadata in SVG files, scale-only matrices, zero skews, prose between markup tags, a function a script declares (function color(name)),//comments in SCSS, Sass and Less, and an angle written another way (24.0deg).scripts/brand-check.test.mjsplants each case on its own line, in the source and in the built CSS, plus clean controls (a clean source file and the output of correct Tailwind 3 and Tailwind 4 builds), an allowlist,--warnand--error, andscripts/check.mjsruns it. The README documents every option and exit code.The supergraphics canon follows the Brand Book where it contradicted it, reading the roles and type relationships above instead of literals (
src/supergraphics.canon.css; no comment added, one corrected):918:2588):.sg-ctasets--mfb-link-on-orange,.sg-bg-orange--mfb-body-on-orange,.sg-cover--orange(and so its title)--mfb-heading-on-orange. Black on orange-300 is 9.2:1; the white it replaces was 2.3:1.918:2990):.sg-bg-white,.sg-bg-grayand.sg-info-bar--on-lightset--mfb-body-on-lightinstead of gray-900.--mfb-heading-on-light(black) instead of orange-300 (2.3:1 on white). A bar without a variant has no background of its own, so its orange date vanished on the package's orange surfaces (1.0:1) and failed on white (2.3:1); placed directly in.sg-bg-white,.sg-bg-grayor one of the package's orange surfaces, its date is now black, and on purple surfaces and photos it stays orange-300 (selectors wrapped in:where(), so--on-darkand--on-lightstill win; checked in a headless render, nested surfaces included). Itssmallline loses its 75% opacity and takes a palette color that passes AA:--mfb-muted-on-light(gray-700, 5.1:1) on the light bar,--mfb-muted-on-dark(gray-400, 8.3:1 on purple-400; orange-300 at 75% was 4.2:1) on the dark bar..sg-headlinereads--mfb-leading-h1and--mfb-tracking-h1(1 and none, where it had 1.05 and -0.03em), and its comment, which called -0.03em the book's heading tracking, now says the book has none. The class sets no size, and 1 is the book's line height for H1 to H4 and quotes only, so two new modifiers,.sg-headline--h5and.sg-headline--h6, set the book's 1.1 for a headline set at those sizes..sg-cover__titlereads the h2 values the same way..sg-labelis Regular with--mfb-leading-label(1.2) and--mfb-tracking-label(none), where it was Medium with 1.5px;.sg-bodyreads--mfb-leading-body(1.2, unchanged) and now sets--mfb-tracking-body(none), so it no longer inherits a parent's tracking..sg-para-frameand.sg-para-accentand the 40px of.sg-ctastay, and the spec lists them with what to set.--mfb-*variable the prelude does not set.lineHeight.body-long(1.7), declared from the website's article prose (.article-prose line-height), emitted as--mfb-leading-body-longandleading-body-long. The spec says the book's body line height is for body copy paired with a heading and this one is a website declaration for articles, flagged for review (open question 1). The build allows it as a named variant of the body level.Earlier on this branch
--mfb-weight-regular|medium|semibold(brand.css and the supergraphics prelude),--font-weight-*in theme.css (plusnormalfor 400),theme.extend.fontWeightin the Tailwind 3 preset (extending, sofont-boldkeeps working), andexport const fontWeight.font-normal,font-mediumandfont-semiboldrestate Tailwind's own values;font-regularis new.#EEEEEE) is added, and their source is corrected to the Halftones slide (918:3730, text node918:3737). They are not palette colors and get no Tailwind utilities..sg-halftone-cutoutreads the variables.var(--mfb-font-heading|body),var(--mfb-weight-*)), so the Brand Book's system fallback, Arial (918:2375), applies..sg-cover__titlereads--mfb-size-h2instead of the never-defined--mfb-font-h2. The supergraphics prelude carries the font families (not the deprecated mono), sizes and weights.918:2874): a thin tapered line at the baseline, beneath the glyphs, under 80% of the word, centered, orange-300 by default and white inside the package's orange surfaces; the word keeps its heading's color. Geometry tokenshighlighter-coverage(prose),highlighter-aspect,highlighter-offsetandhighlighter-shape(measured) join the geometry gate.--sg-angle-baseand--sg-aspectonly:.sg-para-patternrows inset themselves so their first shape is no longer clipped, and.sg-para-framescales its photo by1 + tan(angle) / --sg-aspect, the smallest scale that covers.brand-spec.mdships in the package (filesandexports), so projects and their AI tools read the rules at the version they pin.--sg-aspecton every frame, the brand guard, and the upgrade steps; values in it are read from tokens.json. Its prose follows AGENTS.md..sg-photo-zoneand the mono font are marked deprecated with what to use instead.Website-declared tokens
All from myfirstbitcoin.org at
6368b2a(main), each cited intokens.jsonasmyfirstbitcoin.org@6368b2a, <CSS name>; the Source column gives the CSS name. Each token's note gives the number of uses, counted withgit grepin the site's source at that commit.spaceScale.1to.32--s-1to--s-10space.gutterclamp(20px, 4vw, 64px)--container-px.containerpadding; 50 lines setcontainerspace.sectionclamp(64px, 9vw, 128px).section paddingsection(one page overrides it)space.section-tightclamp(48px, 6vw, 96px).section--tight paddingspace.header-gapclamp(32px, 4vw, 56px)margin-bottom (inline, section headers)space.block-endclamp(32px, 4vw, 48px)margin-top (inline, section calls to action)radius.sm,.md,.lg,.pill--r-sm,--r-md,--r-lg,--r-pillshadow.media0 20px 60px -20px, purple-400 at 25%box-shadow (inline, media frames)shadow.media-control0 12px 32px -8px, black at 40%box-shadow (inline, video play buttons)shadow.overlay0 40px 80px -20px, black at 50%.mfb-overlay__dialog box-shadoweasing.out,.in-outcubic-bezier(0.16, 1, 0.3, 1),cubic-bezier(0.65, 0, 0.35, 1)--ease-out,--ease-in-outduration.fast,.med--dur-fast,--dur-medduration.slidetransition (inline, carousel tracks)duration.reveal.reveal transitionrevealcontainer.page--containercontainercontainer.widemax-width (inline, wide frames)container.measurearticle width(the article width)fontSizeFluid.h1to.h6,.quote,.labelclamp(44px, 6vw, 70px)... (caps are the book's sizes)--fs-h1to--fs-h6,--fs-quote,--fs-labelzIndex.header,.dropdown,.overlay.mfb-header z-index,.mfb-dropdown z-index,.mfb-overlay z-indexmediaRatio.video,.photo,.portrait,.square.video-tile aspect-ratio;aspect-ratioinline on gallery images, educator photos and supporter photosui.touch-targetwidth and height (inline, icon buttons)ui.link-underline-offset.article-prose a text-underline-offsetlineHeight.body-long.article-prose line-height(the page default, thebodyline height, is the same)colorRole.muted-on-light--gray-700 (inline text color)colorRole.border-on-light--gray-200 (inline border color)colorRole.link-on-dark--accent (the color of every link), which the site sets tovar(--orange-300)Package recommendations (a decision each)
Neither the Brand Book nor the website gives these; each is
"source": "declared"(or, for the logo, a selection between two book variants) and says so in its note.link-on-light, 11.5:1 on white). The website's orange link text is 2.3:1 and breaks918:2588.link-underline-on-light), on white to gray-300; on gray-400 and gray-500, where orange cannot be seen, the underline is in the link's own color. Links on light backgrounds always keep their underline (purple-300 is only 1.8:1 from black text).muted-on-dark, 6.4:1 on purple-300). The website uses white at 72% (35 lines), which is translucent text and is not imported; gray-400 is the nearest palette color to it, and the site never uses gray-400 as text on dark.logo-on-orange). The Brand Book shows both a black (918:2978) and a white (918:2980) logo on orange-300; black is the one that keeps to the contrast rule.What a project sees when it raises its pin
The README's "Upgrading from v1.3.0" section says what to do. In short:
.highlighterband draws together with the new line until it is deleted. The span is aninline-blocksized from its own width, so a localdisplayortext-alignoverride breaks it. The brand guard reports a local band ashand-rolled-highlighter.1 + tan(13°) / --sg-aspect(1.154 at the default 1.5); pattern rows gain a left inset of about 0.115 x the row height, so local padding added for the slant should go. The brand guard reports such padding when it is computed from--sg-angle-*.--mfb-font-*,--mfb-size-*,--mfb-weight-*and--mfb-halftone-*in:root.--font-weight-*: initial,--radius-*: initial) must do it before importingtheme.css.--mfb-*variables of brand.css must refresh its snapshot (the three halftone variables are new); the other new variables carry no hex..sg-cta,.sg-bg-orangeand.sg-cover--orangeturn from white text to black;.sg-bg-white,.sg-bg-grayand.sg-info-bar--on-lightfrom gray-900 to black; the light info bar's date from orange to black, and its date line loses its 75% opacity (gray-700 on light, gray-400 on dark). An info bar without a variant placed directly in a light or orange surface of the package gets a black date; anywhere else it keeps its orange date. A local whitecolorset on those classes brings the old contrast back and should go..sg-headlineand.sg-cover__titleset line height 1 and no tracking instead of 1.05 and -0.03em, so multi-line headlines sit a little closer and every headline is a little wider (0.03em per letter): a headline that only just fitted its box may wrap. A headline set at the H5 or H6 size adds.sg-headline--h5or.sg-headline--h6for the book's 1.1..sg-labelturns from Medium with 1.5px tracking to Regular with none, at line height 1.2..sg-bodystops inheriting a parent's tracking.leading-body-long(1.7), for article text; nothing uses it until a page adopts it.--errormakes them fail.Per-project upgrade notes for My First Bitcoin's own projects are tracked internally.
How it was checked
node scripts/check.mjspasses on every commit; it also runs the brand guard's test.{color.teal-500}, a fluid h1 capped at 72px, an unmapped group, an ungated geometry token, a line height for a level that does not exist, a spacing key equal to a container key, and a medium weight of 550.text-heading-on-light/50gets its opacity;shadow-mfb-mediakeeps--tw-shadow-color);rounded-md,ease-out,duration-150andmax-w-xlare unchanged.6368b2aon the site's main branch, and the CSS name cited for it was taken from that line; every count was taken withgit grepin the site's source at that commit. The exact lines are kept outside this repository by the deciders named in CONTRIBUTING.base-h-ratio's quote was read from918:4219through the Figma MCP.import.meta.resolve('@myfirstbitcoin/design/brand-check.mjs')resolves in a scratch consumer.brand-check.mjsagainst two of My First Bitcoin's sites (built with v1.3.0): the first reports 3 problems (a local highlighter band that this release says to delete, a local pattern inset computed from the angle, androunded-[4px]) and 8 warnings; the second reports 114 problems (105 raw values that have a token, four slant computations from the angle and a local copy of the frame's counter-skew, 3 other gradients: a photo scrim, a dashed line and a hard purple and white split, and a local highlighter band) and 369 warnings, 324 of them spacing literals on the scale. The false positives found in review (a map SVG's editor metadata and scale-only matrix, a place name in content data, surface names in content props,@font-facedescriptors,var(--font-sans),skewX(0deg), Tailwind's.uppercasefrom a comment and its--default-mono-font-family) are gone. A scratch page that plants ten known website drifts gets all ten reported, seven as problems and three as warnings (orange text, a purple heading, typed capitals). A second review planted ten more (SVG attribute transforms, React style objects with camelCase properties, named and#RRGGBBAAcolors, angle literals inrotate()andskewY(), a hand-rolled highlighter pseudo-element, an override of--sg-angle-basein the built CSS) and found three reported, and found that the built-CSS rules failed correct Tailwind 3 and 4 builds; each case is now a line in the test, which fails on the earlier guard. Re-run after that change: the first site is unchanged; the second reports 126 problems, the 12 new ones translucent orange or purple fills (scrims and tints made withcolor-mix(), see open question 13). Scratch builds of a Tailwind 3 and a Tailwind 4 consumer with this branch: the built CSS passes in both; the Tailwind 3 one gains 30 tinted panels (bg-orange-200/10and similar). Both sites' built CSS passes (the angle is 13deg, every--color-*is a palette color). A third review found more forms that got past the guard (uppercase writtenUPPERCASE, with a quoted key, or as a lone string inclsx(), a ternary orclass:list; the font shorthand and--font-*theme variables; SVG textrotate, gradient elements andclipPathpolygons; an inset shadow without blur, a thick orange underline and an orangemark;filter: opacity()and translucent borders) and prose it failed (a block number#840000, "a color (any one)", a script'sfunction color(name),const id = '#feed', a//comment in SCSS), plus hard-stop gradients reported as gradients and a built24.0degreported as another angle. Each is now a planted or clean line in the test: on the previous guard the test reports 25 planted lines missed and 8 clean lines reported. Re-run on both sites after that change: the first still reports 3 problems, and 22 warnings (8 before; the new ones are 5 gray-900 text, 7 translucent white text, 2 letter spacing); the second reports 127 problems (126 before: the dashed line and the purple and white split are hard stops and no longer count as gradients, and three translucent orange or purple borders are new) and 554 warnings (369 before; the new ones are 54 gray-900 text, 36 translucent text, 95 letter spacing, among them the white-at-85% eyebrow with 0.12em tracking on the orange banner). Both sites' built CSS still passes. The scratch Tailwind 3 and 4 consumer builds were not rebuilt after this change; the test's Tailwind 3 and 4 controls pass.src/uipath. Every value intokens.jsonis unchanged by the citation change, checked token by token. With an old-style citation planted intokens.json, the spec generator refuses to write.getComputedStyle: a bare bar's date is black in an orange cover and in.sg-bg-white, orange in a purple cover (also when that cover sits inside.sg-bg-white), and--on-darkkeeps its orange date inside an orange cover;.sg-headline--h5at 36px gives a 39.6px line;.sg-bodyunder a parent with 5px tracking has none.--mfb-*variable, before writing any file. Contrast ratios for the canon changes were computed from the palette hex values (WCAG relative luminance). The website's line-height counts were taken withgit grepat6368b2a: 3 lines at 1.7 and 38 at 1.55. The published files name no internal project, person or place: the oldertokens.jsonnotes, the supergraphics.css header and those canon comments were reworded here, and the generated files and thetokens.jsondescription write My First Bitcoin in full.Open questions
918:2323) states 1 for H3 and 1.2 for body, and the tokens follow the specimen for every level. Type Relationships (918:2990) draws H3 at 1.1 (918:3035: four lines of 48px in 212px) and body copy under a heading at 1.22 (918:2994: four lines of 18px in 88px). One rule should decide both: the specimen's stated numbers (as now), or the Type Relationships drawing (H3 1.1, body 1.22). Separately, the website uses 1.7 for long articles (.article-prose line-height), shipped as a separate declared token,lineHeight.body-long, and 1.55 in section paragraphs (38 lines), which is not imported. The deciders named in CONTRIBUTING.md to confirm.--fs-body,clamp(15px, 1.2vw, 18px), read on 65 lines; its floor holds up to a 1250px viewport, so body text would be below the book's 18px on most laptops), or (b) raise the label clamp's floor to 18px, a package declaration. The spec says to use the fixed label size next to body text on small screens until then.clamp(24px, 3vw, 40px)(7 lines in 7 blocks). Keep 40px only, or add a fluid companion that reaches it.max-widthvalues: 720px 7 times, 900px 5, 600px 3, then 860, 768, 760 and 520px twice each and five single values, plus a JavaScript threshold at 760px; 600, 720 and 900px were proposed and are held back until someone picks), card padding (seven clamps), card shadow (two exact uses, five variants), a medium content width (1040, 960, 920 or 820px), a small text size (14px or 13px), the overlay scrim (six values). The site's--dur-slow(600ms) is never used; the practised slow step, 700ms, isduration.reveal.--s-1to--s-10but no line reads them; the values equal Tailwind's steps. The tokens stay, and the brand guard only warns on spacing literals; drop the scale if a read value is required..sg-cta; 18px in.sg-label(the book's label is 22px); the info bar's SemiBold 32px date (the book's 32px level is Medium) and its 15px and 17px lines at line height 1.3; a 6px radius on.sg-para-frameand.sg-para-accent(no radius token has either value); the pattern's 10px gap and 1.25 and 1.55 steps; and.sg-logoand.sg-cover__logoat 40px tall (logo-icon-h), below the book's 63px minimum, at fixed 40px and 44px offsets rather than half the logo height. Each can be fixed in one later release, or one at a time.angle-altstays at its declared 24 degrees until that earlier decision is revisited.918:2893, close to gray-500) and Brand in Use an orange one on grey twice. The package keeps orange on white to gray-300 (sg-bg-grayis gray-200) and uses white on gray-400 and gray-500, where white stands out more. Brand in Use covers 70% to 88% of the word against the slide's "up to 80%"; the slide is treated as normative.highlighter-shape(string),mediaRatio(string), the shadows'opacityfield and percent dimensions are not strict DTCG; tools that validate DTCG may warn.bg-orange-200/10,color-mix()withtransparent, or opacity beside the fill) astranslucent-shape, following the book's solid fills. Two of My First Bitcoin's projects use such tints for panels and hover states and such scrims over photos. If they are wanted, the book (or a declared token) should say which; until then a project can pass--warn translucent-shapeor list them in its allowlist with the reason.Not in this pull request
Brand Book gaps to settle in Figma first: a link style, status colors, a focus style, UI radii and shadows, breakpoints, and web layout. The website values in this pull request stand in for them, each with its source, until the book says otherwise; a book value then replaces the website value.
Package follow-ups. The parallelogram frame still leans out of its box by tan(13°) x height / 2.
--mfb-halftone-highlight-fullis exported but no class uses it yet. Folding line height intotext-h1waits for a major release. The deprecated gradient and mono stay until a major release. The internal copy of the canon (see CONTRIBUTING) is brought into line after merging. An info bar's orange top line still cannot be seen on an orange surface. The brand guard does not read Markdown or MDX files; a project's MDX pages hold no brand values today.Older wording on master, left for a separate clean-up: CONTRIBUTING.md's release and brand-change sections name the people who decide and internal routines, its canon section names the internal shared package, and two comments in
scripts/build-design-package.mjsname it too. Commit metadata: every commit on this branch has an internal author identity, and three earlier commit messages carry what the files no longer do: the source rule commit names the people who decide, as CONTRIBUTING on master already does; the first review-fixes commit cites a line of the website's style sheet and the directory the counts were taken over; and the tokens commit gives the old file and line citation format. The last commit replaced those citations in the files, not in the history. Master already holds commits by the same author, squash-merged and rebase-merged. The pull request's commit list shows them whatever the merge method; a squash merge with an edited message keeps them out of master's history, and rewriting the author and those messages before the first push would keep them out of the pull request as well. Whoever merges decides.🤖 Generated with Claude Code