Packaging artwork review. One label proof on a canvas, annotated, with its colour separations. Brief #10.
Direction
| Lever | Decision |
|---|---|
| Archetype | Canvas. The tool rail is the only permanent chrome. The dock ships open, since the thread is the content, and closing it hands its width back to the proof — 40 % → 89 % at 375 px, 95 % → 102 % at 1280. Above 1400 px the fit is height-bound and closing it changes nothing but the pasteboard, which is what a portrait document does. |
| Data stance | Prose-first. An entry leads with the sentence somebody wrote and carries the replies to it; note 1 is an argument between prepress, account and label compliance, not a finding. The selection is shared: picking an entry draws its measurement on the artwork, picking a pin brings its entry up. |
| Density | Spectrum desktop scale — 32 px controls, 14 px body. The Interface scale control switches the whole page to the mobile scale (40 px, 17 px). |
| The one bold thing | Keyboard access designed rather than inherited. Arrows pan, +/- zoom, 0 fits. Escape closes the dock and returns focus to whichever control opened it. |
Second state
Desktop → mobile is a whole-interface rescale, not a touch-target patch. spectrum_tokens.py --platform-diff reports 922 of 922 platform tokens differ. The page carries the ones it uses:
| Token | Desktop | Mobile |
|---|---|---|
component-height-100 | 32px | 40px |
component-height-75 | 24px | 30px |
font-size-100 | 14px | 17px |
font-size-75 | 12px | 15px |
line-height-font-size-100 | 18px | 22px |
workflow-icon-size-100 | 20px | 24px |
text-to-control-100 | 10px | 13px |
text-to-visual-100 | 6px | 8px |
Measured in Chromium at all three widths: the Undo control goes 32 → 40 px and the body font 14 → 17 px. The page reads the scale from (pointer: coarse) and the control overrides it, which is what the skill asks for.
The sheet is a separate decision, and it is made on width. It was made on the scale, and at 1440 px the Mobile control therefore produced a 1383 px-wide sheet lying over the canvas with the zoom stack underneath it — which is the one thing SKILL.md line 52 forbids ("nothing permanently occludes the work"). Below 760 px the dock floats; the canvas counts the height it takes as spent, so the artwork centres above the sheet and the zoom stack rides on top of it. At 1440 the mobile scale is a rescale and the dock stays a 364 px dock.
Generator
spectrum_tokens.py --both > tokens.css
spectrum_tokens.py --platform-diff
spectrum_tokens.py --theme desktop --format css
spectrum_tokens.py --theme mobile --format css
spectrum_tokens.py --theme default --format css
spectrum_tokens.py --contrast
The generator wrote tokens.css; nothing here edits it. --both emits the colour axis only (671 tokens per set), so the page declares the sizing tokens it uses in its own <style>, from the desktop, mobile and default runs.
Zoom
The artwork is 90 × 130 mm, drawn at 340 px per 90 mm — 96 dpi, so --zoom: 1 is the label at print size. On load the page fits the artwork to whatever canvas the open dock leaves, measured: 40 % at 375, 44 % at 390, 95 % at 1280, 119 % at 1440, 149 % at 1920. + and - step the 25 / 50 / 75 / 100 / 150 / 200 / 300 ladder from there and disable at its ends, 0 refits, and a resize — or opening, closing or resizing the dock — refits only until the reader picks a zoom. The pan is clamped so 48 px of the proof is always on screen: a canvas that can lose the document has lost it, and nothing on the status bar would say so.
Guides
The pasteboard carries trim marks and the 3 mm safety margin, and the selected pin draws its own measurement on the proof. That is what closes the gap between the thread and the canvas: note 1 says the net weight sits 1.4 mm from the trim, and the artwork now visibly breaks the safety margin at that corner. Without the guides "Show pin 1" moved a coloured dot and the reader had to take the sentence on trust.
The box, the leader and the dimension ticks are in the artwork's coordinate system and scale with it. The label is too — font-size: 3px, three millimetres of proof — but it carries a floor. a11y-probe.mjs --width 390 measured the first version at 7.7 px: 3 units times the 44 % fit is illegible, and a measurement nobody can read is not a measurement. --anno-k counter-scales the glyphs through the scale property, so the label grows with the proof and stops shrinking with it at --anno-floor — 12 px desktop, 15 px mobile, alongside every other sizing token. Measured: 12 px at 390 and at 1280, 13.5 px at 1440, 16.9 px at 1920, 34 px at 300 %. The floor is on the type only; the geometry still belongs to the page, which is what Acrobat and every other proofing tool do with review markup.
Measured contrast
| Pair | Dark | Light |
|---|---|---|
neutral-content-color-default on background-layer-1-color (dock prose, 16px) | 12.44:1 | 13.70:1 |
accent-content-color-default on background-layer-1-color (links, 14px) | 4.91:1 | 4.53:1 |
gray-25 on accent-background-color-default (selected pin) | 4.51:1 | 4.81:1 |
gray-600 control boundary on layer 1 | 4.99:1 | 3.31:1 |
negative / notice / positive visual marks | 4.90–4.92:1 | 3.72–3.73:1 |
Every pair clears WCAG 2.2 AA. The three accent pairs fail APCA at 14 px — that is Spectrum's own semantic accent, which the system's own audit records at 4.81:1 with the note that it passes "without much room". No accent-coloured text on this page is smaller than 14 px.
Deviations from CONTRACT.md
- Raw hex inside the artwork and the ink swatches. The label SVG and the six plate chips carry the customer's colour data. Spectrum's own rule for a creative tool forbids a UI theme reaching into it (
references/color-theming.md§ Never color-manage the user's content). Every pixel of chrome is avar(--spectrum-*). - Sizing tokens declared in the page rather than linked.
--bothemits no sizing token; the values are the verbatim output of the three runs in the Generator section. - Durations authored at 90–190 ms.
spectrum_tokens.py --grep durationreturns nothing — the set carries no motion token. The range is the system's published 100–250 ms (references/scales-typography.md§ Motion). - Source Sans 3 in place of Adobe Clean, which Adobe licenses to its own products. The stack names Adobe Clean first.
- Two
copy_lintrules kept, recorded incopy-lint.ignorewith the reason per occurrence:shouty-capsandtitle-casefire on the printed cider label inside the SVG, on three one-word table headers read as one string, and on a heading that is already sentence case.