Files
adr-sml/docs/reference/brand-assets.md
T
Pouya LajevardiandClaude Opus 5 67847d94fa fix: regenerate favicon.ico with a transparent ground; tick Pouya's read-through
public/favicon.ico shipped with no transparency: all three frames declared a
32-bit alpha channel and then carried alpha=255 on every one of their 256/1024/
2304 pixels, ground opaque cream rgba(250,247,242,255). Pouya's read-through
finding, confirmed by parsing the ICO container directly.

The render source carries true alpha (2,272,386 transparent px, 20,795 partial),
so this is an export, not a mask derived from the cream ground — R13's harder
branch did not fire and R13 is unchanged on its own terms.

New scripts/icons.mjs + npm run icons re-derives the icon from the committed
master: asserts the source is still the documented crop (R14), verifies a
candidate file and renames on success so a rejected build cannot replace a good
favicon, and runs a boundary-colour halo test. Composition is unchanged —
ink bbox and pixel count identical at all three sizes.

apple-touch-icon.png is byte-identical and stays opaque cream deliberately; the
reason lives in docs/reference/brand-assets.md §The icon set, with the bar and a
pointer in BaseLayout.astro, docs/06 and R13.

docs/06: the read-through is ticked, and the cutover callout drops to ONE
blocker — Q60's waiting period.

Two adversarial review rounds, 15 findings, all resolved, none declined; stopped
at two per D19. claims-auditor correctly deferred to cutover per D20. Gates on
the committed bytes, exit status read: check 0, build 0 (23 pages),
check:claims 0, check:intake 0, og:proof 0, lint 0, lighthouse 0 (worst of 23
99/100/100/100). Nothing deployed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
2026-09-02 16:14:35 -04:00

15 KiB
Raw Blame History

Brand assets — provenance

The repository holds the artwork it makes claims about. That is not tidiness: it is CLAUDE.md's rule and AGENTS.md R14, and this file exists because the infinity mark was reconstructed wrongly and two adversarial review passes could not catch it, since the real artwork was not in the repo to compare against.

The measurements here are computed with sharp against the files in this repository, and are re-derivable by anyone from the commands given.

Unless a section says otherwise, every figure below is [verified 2026-08-26]. Where a section carries its own stamp, that stamp wins — the render ladders are [measured 2026-08-27] and §The icon set is [verified 2026-09-02]. ⚠️ This line has been wrong in both directions in one week: first as a blanket 2026-08-26 that was already stale for the ladders, then as "each section carries its own stamp" when five sections carry none. It is a floor plus overrides because that is the only shape that covers every section without mis-dating one (adversarial-reviewer, rounds 1 and 2).

⚠️ Two things in §The icon set are NOT read off this repository and are labelled where they appear: the tab-strip colours used in the contrast figures, and iOS's handling of a transparent touch icon. Neither is derivable from anything committed, so neither is stamped as if it were.

Files

File What it is Use
src/assets/brand/sml-infinity-mark-master.png The mark as supplied: 3000 × 3000, alpha, mark inset within the canvas The master. Committed so the crop below can be re-derived and checked in-repo, not taken on trust
src/assets/brand/sml-infinity-mark.png The same mark tight-cropped to its ink bounding box: 2668 × 1704, alpha, 1.5657:1 The render source. InfinityMark.astro feeds it to Astro's <Picture>
src/assets/brand/sml-logo-full.png Mark plus the "SML Company" wordmark, 3000 × 3000, alpha; ink bbox 2414 × 1440 = 1.676:1 Not currently rendered. Held for the OG-image template (docs/04) and print
src/assets/brand/sml-logo-source.svg 1500 × 1500 viewBox, 257,278 bytes Reference. Faithful, but not what is served — see below

Reproducing the crop, in-repo

The crop is derived, so it is re-derivable — and now from a file that is here, which is the whole point of R14. Scan the master for the first and last pixel that is neither transparent (alpha < 24) nor near-white (r,g,b > 243):

ink bbox of sml-infinity-mark-master.png -> 2668 x 1704 at (159, 646)
sharp(master).extract({ left: 159, top: 646, width: 2668, height: 1704 })

Crop to that box and the file's own aspect ratio becomes the mark's, so layout can be tuned against the asset directly rather than against a number written down beside it. InfinityMark.astro pins aspect-ratio: 667 / 426, which is 2668 / 1704 reduced — 1.56573.

Why the SVG is held but not served

It renders faithfully. Rasterised at 8333 px it reproduces the master exactly, at the same 1.566:1. It is not bad artwork, and an earlier version of this file implied it was; that was wrong.

What rules it out is weight and composition:

  • 257,278 bytes, against 3,063 bytes for the AVIF a Retina device actually takes in the header. 84×. (This line said "9,468 bytes... 27×" until 2026-08-27. 9,468 was the DPR-1 figure — the number for the devices the performance budget does not target. Quote the figure for the device the budget is written for.)
  • 7 embedded base64 PNGs (<image> elements), so it is a hybrid rather than pure vector — inlining it would breach CLAUDE.md's rule against base64-inlining images, which is one of the specific faults of the build this project replaces.
  • 10 <linearGradient> carrying 1,225 <stop> elements, 64 <path>, 59 <clipPath>, 23 <mask>, 1 <filter>. Expensive to rasterise.

What AGENTS.md Q38 asks for is a master that is faithful and light.

What the browser actually downloads

<Picture> emits AVIF, WebP and a PNG fallback at densities 1×, 2× and 3× of whatever intrinsic width the call site passes. There are now TWO ladders, because there are two sizes of call site [measured 2026-08-27 — every figure below read from the file on disk].

width={64} — the default. The header (50.1 px wide) and footer (56.4 px).

1× (64 px) 2× (128 px) 3× (192 px)
AVIF 1,720 B 3,063 B 4,843 B
WebP 2,368 B 5,368 B 8,664 B
PNG (fallback) 6,137 B 16,996 B 29,780 B

width={232} — the home page's approach section, which renders at 225.5 px.

1× (232 px) 2× (464 px) 3× (696 px)
AVIF 6,017 B 14,555 B 22,639 B

That instance is loading="lazy": it sits roughly a screen and a half down, so it is not on the LCP path. The header and footer marks stay eager.

THE LADDER HAS NOW BEEN WRONG IN BOTH DIRECTIONS, which is why width is a prop rather than a constant.

  • Too big, 2026-08-26. Sized at 320 px, justified by a 4 rem sample on the proof sheet (a page step 2 has since deleted), with densities stacked on top — so the ladder double-counted its own headroom and every DPR-2 device pulled a 640 px image into a 56 px slot: 20,629 B, while the docs claimed 9 KB because that is what DPR 1 took.
  • Too small, 2026-08-27. The home page added a 225.5 px call site and inherited the 64 px ladder, whose largest file is 192 px: 3.52× upscale at DPR 3. Now 232/464/696, and 696 covers the 676 device px a DPR-3 screen asks for. All three instances measure ≤1.0× upscale at DPR 1, 2 and 3.

Do not measure this with img.naturalWidth. For an image chosen from a srcset with an x descriptor it is density-corrected: the 192 px file selected at 3x reports 64, so reading it at DPR 1, 2 and 3 returns 64 every time — which looks exactly like the ladder not being generated at all. Read the files on disk.

Passing an explicit width is load-bearing: without it Astro emits the untouched 2668 px master as the <img src> fallback — 1,146,406 bytes — which any client without AVIF or WebP support would actually download.

The icon set

[verified 2026-09-02 — every figure below read off the icon files in this repository, EXCEPT the two external constants flagged inline]

File What it is Ground
public/favicon.ico 16, 32 and 48 px frames, each a PNG-encoded 32-bit RGBA image inside the ICO container Transparent
public/apple-touch-icon.png 180 × 180 Opaque cream #faf7f2, and that is deliberate — see below

The two grounds differ on purpose, and this is the line that stops someone "fixing" it. ⚠️ The reason is an external platform behaviour, not a repository fact, and it is recorded here as what it is: iOS does not honour transparency in a touch icon — it composites it onto black, so a transparent touch icon ships a black tile on the home screen. Stated by Pouya in his ruling of 2026-09-02 and not independently re-tested here; it has not been checked on a handset in this repository, and the place that does check it is the unticked docs/06 item "Tested on iOS Safari…". The tab favicon has the opposite requirement: a tab strip is dark for many readers, and an opaque ground shows there as a visible rectangle around the mark. So the favicon is transparent, the touch icon is matted, and neither should be changed to match the other.

Composition

The mark spans 7/8 of the canvas width, centred on both axes — 14/16, 28/32, 42/48, and 158/180 on the touch icon. That was measured off the icons as they already shipped, so a regeneration reproduces the composition rather than restyling the mark.

Regenerating

npm run icons

scripts/icons.mjs resizes src/assets/brand/sml-infinity-mark.png onto a transparent square canvas and assembles the ICO container itself, because sharp does not write .ico. It writes the favicon only and never touches the touch icon. It refuses to run if the render source has no alpha channel, and it asserts that the source is still byte-identical to the documented crop of sml-infinity-mark-master.png — R14, so the icon stays traceable to committed artwork. It verifies a candidate file and renames it into place only on success, so a rejected build cannot replace a good favicon.

It also carries the halo test, because the check that matters was living only in prose here while the generator could not run it (adversarial-reviewer, round 2). For each frame it takes every painted pixel touching a fully transparent one and measures how many sit within 20 of cream:

boundary px near cream share
correct, 16 / 32 / 48 px 61 / 146 / 258 1 / 2 / 5 1.6 / 1.4 / 1.9 %
haloed fixture, 16 px 56 11 19.6 %

The gate is 10 %, roughly 5× clear of both. ⚠️ The first version of this guard inspected only partial-alpha pixels and MISSED the fixture completely — a knockout sets alpha per pixel and leaves no partial alpha at all, so there was nothing for it to look at. The fixture is built by matting the mark on cream and then knocking the ground out by alpha, which is the defect exactly; it fires at 19.6 % and leaves public/favicon.ico untouched. A guard that cannot see the defect it is named for is worse than none, and this one passed the real icon while blind, which is the shape that ends a check instead of starting one.

Why the favicon was regenerated, 2026-09-02

It had no transparency at all: all three frames declared a 32-bit alpha channel and then carried alpha = 255 on every one of their 256 / 1,024 / 2,304 pixels, with the ground opaque cream rgba(250,247,242,255). Found by Pouya on a read-through, confirmed by parsing the container directly.

Three measurements stand behind the replacement.

1. The composition did not change. Composited back onto cream, the new icon reproduces the old matted one to within 1 of 255 on every channel of every pixel at all three sizes (mean delta 0.010.02, 0 pixels over a delta of 8). So the regeneration did not restyle, rescale or reposition the mark.

⚠️ That is NOT a test for a halo, and an earlier draft of this file filed it as one. Composite-onto-cream returns ~0 whether the edge is correct or is a cream-matted edge that has merely had its background knocked out — the second case composites straight back to what it came from. Both branches pass, so the test cannot discriminate. Found by adversarial-reviewer, 2026-09-02.

2. No halo — the measurement that does discriminate. Read the RGB the partial-alpha pixels actually carry. A cream halo means that RGB is near cream; a correct export means it is the ribbon's own colour. Of the partial-alpha pixels, 0 of 94 / 300 / 603 are within 12 of rgb(250,247,242); the nearest is 13 away, the mean distance is 174.0 / 178.3 / 177.0, and the mean colour per frame is about rgb(118,86,74) — maroon-brown, not cream and not black.

3. Legible on dark and on light, and NOT at the same cost. ⚠️ The ground colours below are external constants, not repository facts: #202124 is Chrome's dark tab strip and #f1f3f4 its light one, both [observed 2026-09-02]. All ratios are computed on composited pixels, and the ink colours are fully opaque pixels only — a ratio taken from a raw channel value is a claim about a colour that is never painted, which is how an earlier draft came to quote 14.02:1 for a pixel whose alpha is 251.

darkest opaque ink lightest opaque ink vs #202124 vs #f1f3f4
16 px rgb(70,33,33) rgb(216,188,143) champagne 8.82:1 maroon 12.58:1
32 px rgb(60,29,29) rgb(234,214,172) champagne 11.28:1 maroon 13.62:1
48 px rgb(61,26,26) rgb(238,219,175) champagne 11.80:1 maroon 13.86:1

Whichever ground it sits on, one end of the ribbon carries the silhouette. But the other end does not merely dim — on dark it goes. The maroon lobe composites to 1.041.15:1, and counting pixels that reach 3:1 against each ground gives 23 / 87 / 189 on dark against 40 / 168 / 378 on light, at 16 / 32 / 48 px. So about half as many pixels reach 3:1 on dark as on light. ⚠️ Those pixels are not absent — they are painted and fall below 3:1, and the mark's full outline is still there, dim. An earlier draft said "roughly half the mark's visible pixels are absent", which is neither what was counted (pixels at alpha > 0 are 109 / 388 / 805) nor what a render showsadversarial-reviewer, round 2. The previous opaque-cream icon was still more legible on dark.

That is the price of the change and it was accepted, not overlooked. What was bought is the removal of a cream rectangle from every dark tab strip and from white. Raised by adversarial-reviewer, 2026-09-02, against a draft that recorded the change as costless.

The obvious alternative is an icon pair keyed on prefers-color-scheme, and it was NOT ruled out on measurement. ⚠️ An earlier draft dismissed it on a mechanism that is wrong: it said the query keys off the page's colour scheme. It does not — it reports the user's system or browser preference, and this site declares color-scheme nowhere (git grep -n color-scheme -- src, exit 1), so it would resolve to the same preference that makes the tab strip dark. The real objections are untested here and are recorded as such: media on <link rel="icon"> is unevenly supported for raster icons, a browser theme can be set independently of the system preference, and it doubles the artefact npm run icons has to keep in sync. If this cost is ever revisited, that is the option to test — do not re-dismiss it on the reason struck above.

The colours are the artwork's, not the palette's

tokens.css is not involved. The ribbon carries its own gradient and it is close to but not identical with --maroon #5a1a1c and --gold #c9a876. Do not "correct" the artwork toward the tokens, and do not derive tokens from the artwork — D7 keeps the palette and the mark, as they are.

Where these came from

Supplied by Pouya. sml-logo-source.svg was added by him directly to the repo; the PNGs were taken from the smlcompany.ca Google Drive, under SML/Designs/ and Research/Law/ADR Personal Branding Project/. The Drive copies are not the record — these files are. That is the point of R14: an artefact that lives only in Drive cannot be compared against a claim by any reviewer, which is exactly how the traced mark survived two review passes.