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
266 lines
15 KiB
Markdown
266 lines
15 KiB
Markdown
# 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.01–0.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.04–1.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 shows* — `adversarial-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.
|