Icons

A set is a grid with rules, not a sheet of pictures. Below: the anatomy of one cell, optical balance, and an audit of the glyphs against the paint, which is where the field turns out never to have been set and where the centre has drifted. The set was consolidated on 2026-08-09: 52 glyphs and two hands became 35 glyphs and one rule, and section 03 is what the rule turned out to be. 34 the same day, when the two warning marks were decided in favour of the triangle and the circle left with its last placement.

34 glyphs 30 filled 4 line marks, in the sprite since 2026-08-13 8 brand marks 52 to 34

Anatomy

cell 24 x 24, safe field 2, geometric centrepaint 18 x 20, field 2.0, centredre-measured 2026-08-09, filled. It was 15.6 x 18.6, field 2.2, centre off 0.0 / -0.5 when this cell was drawn by hand
  1. 1Cell 24 x 24 - viewBox="0 0 24 24" on the whole set. Not "about 24": one grid for every glyph is the only thing that lets a new one be drawn without being held up against its neighbours. This part the set already has, on 5,180 readings, and it is the reason the rest is fixable.
  2. 2Safe field 2 - paint lives in 2..22. Those two modules are not emptiness, they are headroom: the glyph stands beside text, inside a button and inside a circle, and with no headroom it touches the edge of the circle.
  3. 3The stroke paints outward from the contour - a 2.2 stroke puts 1.1 of paint past the geometry on every side. The boundary is checked against the PAINT, not against the curve, or the safe field is eaten by half a stroke and the audit reads a module too kind.
  4. 4Optical centre, not geometric. A glyph with a heavy bottom, a basket or a bell, is centred by eye: evenness is counted by sight and not by coordinates. The brass cross above is the geometric centre, so a deliberate optical shift can be seen rather than argued about.
  5. 5Ends on the grid. A stroke end lands on a whole module, or at 16px it smears across half a pixel and the glyph reads as dirty.

Optical balance

The same bounding box and the same weight are different things. A circle inscribed in the field a square fills looks smaller: the eye counts area, not the rectangle around it. So a set is deliberately not one size, and the four below are the argument, each measured against its paint.

check-circle, filledpaint 20 x 20, field 2.0, centred
tick, linepaint 18.2 x 14.2, field 2.9, centre off 0.0 / -1.0
grid, filledpaint 20 x 20, field 2.0, centred
chevron down, linepaint 14.2 x 8.2, field 4.9, centred

The chevron is the case. It is the second most used glyph in the product and it paints a third of the cell's height. Beside a full-height glyph it does not read as a smaller icon, it reads as a mistake. That is not a drawing to enlarge, it is a decision the set has never taken: either the chevron is drawn to the field like the rest, or the set declares a class of small marks and says which glyphs are in it.

TWO HANDS BECAME ONE RULE, AND THE RULE IS NOT THE ONE THAT WAS ASKED FOR

This page used to open here with a defect: two families, 52 glyphs, and four jobs drawn in both. The header carried the proof, because the same bookmark was stroked on one screen and filled on the next at two different inks, for the same meaning. The pairs are below, as they stood.

The instruction was "consolidate the stroked ones into filled", and it cannot be carried out. Not for want of a library: 33 stroked marks were read against Solar Bold and six of them have no filled form at all, because they have no interior to fill. A cross, a chevron, a plus, a tick and a hamburger are movements, not things. What a filled set offers for those is a disc or a plate with the mark knocked out of it, and a disc inside a round icon button is a disc inside a disc.

AND ON 2026-08-13 THE SIX MOVED INTO THE SPRITE, which they could not do on the day this rule was written. `base.css` said `svg.ic:has(use){fill:currentColor !important;stroke:none!important}`, which reads as "a mark from the one file is a FILLED mark", and it was true only because the file held nothing else: a two-stroke drawing arriving through that rule gets no area and no stroke and paints NOTHING. So the six stayed hand-written in the markup of 119 documents, 983 of them, which is the exact shape of the defect the sprite was built to end. The floor asks for #i- now and the line family is #l-, so a family is a property of the glyph and is carried by its name, which is the argument backlog 133 used against a class per icon size. It buys one source and not bytes, and the honest number says so: the markup lost 4,947 and the sprite gained 2,334. Proof it changed nothing: 238 full-page screenshots over 119 documents at two widths, 0 differing, against a control of 0.

A CELL IN THE GRID BELOW IS 3.18 TIMES LIFE SIZE, and it took a reader being misled to write that down. The cells are 70, 94 and 262px and they let the stroke scale with the box, so a 1.65px mark renders 4.67px here and looks like a heavier drawing than the one the product ships. It is not: the product's mark is the same path at 22px, and in PROPORTION it is 12% heavier than this cell, 7.5% of its box against 6.67%. Anything shown here is a magnification and its weight is constant in device pixels, never in units of the cell. On 2026-08-13 the plus was read off this page as a second, bolder drawing that the product was failing to use, and there was no second drawing.

A line is not an unfilled shape, it is a different kind of mark. Material and SF Symbols draw the same six as lines in their filled sets. An icon set that fills everything has either invented interiors or given up on the cross.

So the rule is: an object is filled, a movement is a line, and WEIGHT holds them together rather than style. 20 filled glyphs over 1,517 placements, 6 line marks over 990. The stroke was 1.6 against the solid mass of Solar Bold, and that gap is what the eye reads as "two sets": it is 2.2 now at 22px and 2.4 at 12px, chosen by standing a line mark next to a filled one at both sizes.

What did not move: the brand marks. Three sign-in providers and five social marks in the footer are logos, they keep their own drawing, and a generic glyph is not allowed to stand in for one, because a paper plane is not Telegram. Two of the four "pairs" this page named turned out to be brand marks caught by a shape census: the second cross was the X mark and the second chat bubble was Discord.

And the licence was being relied on rather than honoured. Fifteen Solar glyphs had shipped since the Vault pass with the set named in a comment and no attribution anywhere. Solar is by 480 Design under CC BY 4.0, which asks for exactly that. It is in NOTICE.md now, in DESIGN.md, and in the comment above the sprite on all 105 screens. Naming an asset is not crediting it.

the four jobs that crossed the two families, and what each one is now

i-bookmark-b303 uses
i-bell-b108 uses
i-shield-b106 uses
i-chat-b10 uses
jobthe stroked twin, until 2026-08-09the filled onenow
bookmarkM6 3h12v18l-6-4-6 4z, 88i-bookmark-b, 215303 filled
bellM6 9a6 6 0 0 1 12 0..., 35i-bell-b, 73108 filled
shieldM12 3l7 3v5c0 4.5..., 106i-shield-b, 106106 filled, and 106 against 106 was two decisions taken in two places
chatnot a twin. The 105 are the Discord mark in the footeri-chat-b, 910 filled, and a logo that stays a logo

The stroked twins are written here and not DRAWN here. This page stood all four of them as live specimens for a day after they left the tree, next to the filled ones, under a caption saying "as they stood until". A stand draws what exists: a reader who scans a grid of glyphs is reading the pictures, not the caption over them, and this one was read exactly that way. The path data is a record. The drawing was an offer.

All four now stand as the filled glyph only, and the stroked twin is gone from the tree. The rule this page proposed, filled for on and stroked for off, was considered and not taken: it is a good rule for a toggle and these four are not toggles, they are a destination, a destination, a claim and a count. A rule that would make the header's bookmark change shape when nothing about it is on or off is a rule about the wrong thing.

One ink per place, and it has to be written twice. A stroked mark takes its ink from stroke and a filled one from fill:currentColor, so every rule that paints an icon has to name both or half the set stops listening. Nine :has(use) rules already existed for the old filled handful and three of them disagreed with the stroke beside them, which is where the header's two bookmark inks came from. That is the standing cost of holding two kinds of mark in one family, and it is written in base.css where somebody will meet it.

The stroke slid, and it stopped on 2026-08-10

THE SET HAS ONE WEIGHT NOW, and the number is the one on screen rather than the one in the file. --stroke-mark is 1.65 in tokens.css, paired with vector-effect:non-scaling-stroke on the shapes, so the declared value no longer passes through the viewBox scale. Measured after: all 1,818 stroked marks in the painted tree render at 1.65px, a ratio of 1.0, and it is verified against the PAINT, not the formula - a straight bar screenshotted at device scale 10 and summed by pixel coverage gives 1.65px at boxes 12, 18, 22 and 40. 1.65 was chosen because 1,056 of the 1,818 already rendered there: it is the default mark at 18, so the set keeps the weight it was drawn against and the other 762 come to it. The four files that own a stroked mark declare the token; two of them were hand-computing this number in user units and one had declared nothing at all. Everything below this paragraph is the record of what it was, and it is kept because the mechanism is worth knowing. The blow-ups in section 02 are the one exclusion: they carry no .ic, so they still scale, because a drawing shown at four times its size wants its stroke at four times too.

.ic declared its stroke once, in user units, inside a 24 unit box. User units scale with the box. So the line was not that number anywhere: it was that number multiplied by however large the icon was asked to be, and the set is drawn at six sizes. The same glyph at all six, four of which the product actually strokes:

The constant moved from 1.6 to 2.2 on 2026-08-09 and the fault did not, but the spread did, and this page claimed otherwise for a day. It said the ratio was "exactly what it was, 2.98 to 1, because the fault is the unit and not the value". Re-read on the 106 painted screens it is 1.68 to 1, and the reason is not that the unit was fixed: it is that the set no longer strokes at the two boxes that were the extremes. 40 and 20 carry filled glyphs only now, so the stroked range runs 12 to 22 instead of 12 to 40. An argument whose evidence has moved is not a smaller argument, it is a different one. What the new number does fix is the thing it was chosen for: it puts the line marks at the mass of the filled ones beside them. The figures below are re-read at 2.2, and 12px reads 2.4 because .ic-sm declares its own. Two of the six sizes below are a demonstration of the mechanism and not a placement: nothing in the product strokes at 20 or at 40.

.ic-sm @ 12box 12px, was 2.4u rendering 1.20px, now 1.65px
.ic @ 16box 16px, was 2.2u rendering 1.47px, now 1.65px
.ic @ 18box 18px, was 2.2u rendering 1.65px, now 1.65px, the one that did not move
.ic @ 20box 20px, was 2.2u rendering 1.83px, now 1.65px
.ic @ 22box 22px, was 2.2u rendering 2.02px, now 1.65px
.ic.tr-ic @ 40box 40px, was 2.2u rendering 3.67px, a slab, now 1.65px

Measured 2026-08-09 on the 106 painted screens, every svg that actually paints a stroke, 998 placements of 2,399, in CSS pixels: 1.20px at 12 (266), 1.47 at 16 (17), 1.65 at 18 (528), 2.02 at 22 (178), and the remaining 9 are the market chevron in the paragraph below, at 16 and painting 1.20. Four boxes, not six, and 1.68 to 1 between the lightest and the heaviest. The old reading, kept because it is what the set was before the consolidation: 0.90 at 12, 1.07 at 16, 1.20 at 18, 1.33 at 20, 1.47 at 22, 2.67 at 40, a factor of three. What went with it was the argument's sharp end: 0.90px is under one device pixel at DPR 1 and smears, and 1.20px is not, so the lightest line in the product is no longer sub-pixel. The set still had no optical weight. It had one geometric weight that slid, less far.

AND THE THREE CONSTANTS ARE ONE, since 2026-08-10. They were: .ic at 2.2 user units, .ic-sm at 2.4 - the smallest box declaring the thicker number, which after the scale landed at 1.20px, the thinnest line in the product - and a third this page had never named, .market-chevron writing its own stroke-width:1.8 in market.css at a 16px box, which rendered 1.20px as well: the same painted weight from a different number at a different size, in a file the icon rules do not reach. Two declarations agreeing by accident is not one weight, it is two that have not disagreed yet. There was a fourth that agreed with nothing: .tr-ic on the trust strip's own stand declared no stroke width at all and took the SVG default of 1, rendering 0.92px, under one device pixel at DPR 1. All four read --stroke-mark now, and the value is in screen pixels because vector-effect:non-scaling-stroke takes the viewBox scale out of it.

The safe field, measured against the paint

The smallest distance from painted edge to cell edge, for all 35, in the distribution two paragraphs down. The line numbers all end in .9 because they are a whole-module contour plus the 1.1 of stroke that paints outside it, which is the arithmetic of rule 3 showing up in the data. They ended in .2 at 1.6 and this sentence said 52 and 0.8 until 2026-08-09, one day after the set was consolidated, which is the same lag the audit below opens by naming.

A method note, because the first pass of this got it wrong. A sweep run over the live feed reported thirteen glyphs inside the field. It was reading the stroke off getComputedStyle of the child, and a <use> inside .ic inherits the stroke width, now 2.2, whether or not it paints a stroke, so every filled glyph was credited with half of it in paint it does not have and lost a module of field. An inherited property is not a painted one, and the fix is to ask whether the element actually strokes before spending half of it.

Re-measured 2026-08-09 by INK rather than by geometry, and the rule now holds on every filled glyph. Filled, 20 glyphs: field 2.0 on 17, 3.0 on one, 3.3 on two, and none inside the rule. Line, 6 glyphs: 4.9 on two, 3.9 on two, 2.9 on one and 1.9 on the menu, a tenth under, unchanged and confirmed by ink at 2.2. 18 of the 20 filled glyphs are centred at 0.0 / 0.0, the other two off by 0.2 and 0.3. Brand, 8 marks: not measured against this grid, and two of the three providers paint to the cell edge, which is what a logo does. The old reading, kept because it is what the hand-drawn set actually was: stroked 33 glyphs, field 2.2 on 15, 3.2 on 10, 4.2 on 6, 5.2 on 2; filled 15 glyphs, 2.0 on 13.

Two modules is the target and it is not a preference. An icon sits in a 36px circular button at 22px: 2 modules of headroom is 1.8px of air between the paint and the button's own border, and that is already tight. Below 2 the glyph touches. Above 4 it stops reading as the same size as its neighbours, which is the chevron's problem in section 02.

The centre had drifted on twelve glyphs, and section 06 is where that ends

This paragraph is the hand-drawn set's reading and it is kept as one. All three glyphs it sends away to be corrected are gone from the product, and 19 of the 21 filled glyphs now sit at 0.0 / 0.0: the audit below states it and this is the argument it answers. Measured against the geometric centre, in modules. Some of it is right: a shield at -0.5 and a bell at 0.0 are optically centred, which is rule 4 being obeyed. Some of it is not. sort at -2.0 across is a glyph drawn from x=4 with ragged right ends, so it is not optically centred, it is left-aligned inside a centred box. trend-up at -2.0 down and music at -1.7 / -0.8 are the same thing on the other axes. Those three are drawings to correct; the rest are within half a module and are left alone, because a half module at 16px is a third of a pixel and moving it buys nothing.

ALL 34, AGAINST THE PAINT

Every glyph in the product, on its own grid, with its painted extent and its smallest safe field measured in modules on 2026-08-09. Uses are counted across the 106 painted screens. It was 52 glyphs the day before, and the audit that follows is the one this page has always run, taken again after the set was consolidated.

The centre drift this page opened with is gone, and the consolidation is what removed it. sort at -2.0 across, trend-up at -2.0 down and music at -1.7 / -0.8 were three drawings to correct. They are not drawings any more: 18 of the 20 filled glyphs sit at 0.0 / 0.0, and the two that do not are off by 0.2 and 0.3 of a module. That is what taking a set from a grid buys, and it is worth more than three hand corrections would have been.

AND THE WHOLE SET SHIPPED SOLID FOR A DAY, WHILE THIS PAGE DREW IT CORRECTLY. Solar Bold draws its detail as a KNOCKOUT: the exclamation in the warning triangle, the tick in the shield, the meridians on the globe, the lens of the magnifier are holes cut from one path with fill-rule:evenodd. A stroke outlines every subpath including the holes, and 2.2 units of brass around a 2 unit exclamation closes it completely. Fifteen component rules paint an icon with stroke: at two classes, which beats svg.ic:has(use) at (0,1,2), so the product drew blobs where the stand drew glyphs, because no component rule reaches a specimen. It is stroke:none!important in base.css now, one of five in the file, and it is a floor rather than a patch. The stand could not have found this: it is the one defect a stand is structurally blind to.

THE CLOCK NEVER FILLED THE CELL. A MASK IS INVISIBLE TO getBBox, AND THAT IS THE WHOLE OF BACKLOG 70. This page read i-clock-circle-b at 24 x 24, field 0 and filed a row to swap the drawing for a smaller one. Read again by ink, painting each symbol into a canvas at 20x and finding the opaque pixels, it is 20 x 20, field 2, centre 0.0 / 0.0: the same box as i-sort-b standing beside it in the same filter row. The glyph was delivered as a full-cell rectangle behind a mask, <path d="M0 0h24v24H0z" mask="url(#...)"/>, and getBBox returns the geometry of the path and never the mask. This is the same defect as the stroke that closed a knockout, one layer up: an instrument that reads the drawing instead of the paint. It is redrawn as one evenodd path now, Solar's two published subpaths composed with a fill rule instead of a mask, 0.09 per cent of pixels different and all of them the antialiased edge of the hand. What went with the mask is a document-unique id in the sprite, which is backlog 45's family.

And the glyph that WAS breaking the rule is the one the row did not name. i-magnifer-o painted 21.5 x 21.5 at field 1.23, the only filled glyph inside the two-module rule, while its caption on this page claimed 19.4 and 2.3. It is bigger than the set, not smaller: everything else paints 20. The symbol places Solar's own path at scale(.9294) about the cell centre, which lands it at 20 x 20, field 2.0, centre 0.0 / 0.0. The path data is unmodified; the placement is ours, and NOTICE.md says so.

The line marks keep the arithmetic this page named in rule 3. Their fields all end in .9 because they are a whole-module contour plus the 1.1 of stroke that paints outside it, which is the same fact that made them end in .2 at 1.6. The menu is the one under 2, at 1.9, and it is under by a tenth.

Filled, 20 glyphs, Solar Bold through the sprite

i-bookmark-b303 usespaint 18 x 20, field 2
i-global-b211 usespaint 19.9 x 20, field 2
i-bell-b108 usespaint 17.9 x 20, field 2
i-check-circle-b213 usespaint 20 x 20, field 2
i-shield-b106 usespaint 18 x 20, field 2
i-graph-up-b106 usespaint 20 x 20, field 2
i-widget-b105 usespaint 20 x 20, field 2
i-list-b105 usespaint 17.5 x 11.5, field 3.3
i-transfer-horizontal-b73 usespaint 17.5 x 17.5, field 3.2
i-user-b73 usespaint 16 x 20, field 2
i-clock-circle-b45 usespaint 20 x 20, field 2, centre 0.0 / 0.0read as 24 x 24 field 0 until 2026-08-09, because it was drawn as a full-cell rect behind a mask and getBBox does not see a mask. Redrawn as one evenodd path, same silhouette
i-sort-b44 usespaint 20 x 20, field 2
i-heart-b36 usespaint 20 x 17.4, field 2, centre off 0 / -0.2
i-login-3-b32 usespaint 17 x 18, field 3
i-inbox-b10 usespaint 20 x 20, field 2
i-chat-b10 usespaint 20 x 20, field 2
i-share-b9 usespaint 16.5 x 20, field 2, centre off 0.3 / 0
i-info-circle-b9 usespaint 20 x 20, field 2
i-magnifer-o4 usespaint 20 x 20, field 2, centre 0.0 / 0.0Solar OUTLINE rather than Bold, because a lens with no hole is a disc. It painted 21.5 x 21.5 at field 1.23, the one filled glyph inside the rule, and the symbol now places Solar's own path at scale .9294 about the cell centre
i-danger-triangle-b20 usespaint 20 x 18, field 2

Line, 6 glyphs, hand-drawn at 2.2, and not one of them has an interior

close333 usespaint 14.2 x 14.2, field 4.9
chevron down266 usespaint 14.2 x 8.2, field 4.9
tick108 usespaint 18.2 x 14.2, field 2.9, centre off 0 / -1
arrow right105 usespaint 16.2 x 14.2, field 3.9
plus85 uses, all of them .bal-addpaint 16.2 x 16.2, field 3.9FILLED since 2026-08-13, #i-plus-b

The menu left this grid on 2026-08-14, and the badge above became right by accident. l-menu was the sixth figure here and the fifth line mark, and it went with the control it was drawn for: the header's hamburger was a <button> labelled "Menu (reserved for future scaling)" with no handler and no drawer, display:none below the desk, removed from 105 painted screens, 87 grey ones and 10 kit specimens in one pass. A symbol whose only remaining reader is the page that documents the sprite is a glyph with no placement. The sprite is 34 symbols, 30 filled and 4 line, and the "34 glyphs" badge above had been one short against 35 for as long as it has stood, disagreeing with the two badges beside it. Its field readings are kept in the measurement paragraphs on this page rather than deleted, because those are a record of the set as it stood on their own date, and the menu is the mark the 2 rule was under by a tenth.

Brand, 8 marks, drawn by their owners and not measured against this grid

X sign-in108 usespaint 24 x 21.7, field 0
Google sign-in107 usespaint 23.5 x 24, field 0
Apple sign-in107 usespaint 17.4 x 21.4, field 1.2
X (Twitter)105 usespaint 16.2 x 16.2, field 3.9
Discord105 usespaint 16.2 x 12.2, field 3.9
Telegram105 usespaint 20.2 x 17.2, field 1.9
Instagram105 usespaint 16.2 x 16.2, field 3.9
TikTok105 usespaint 12.7 x 14.7, field 3.9

EIGHT JOBS WERE DRAWN TWICE, AND ALL EIGHT ARE DECIDED

52 glyphs and 45 jobs became 35 glyphs on 2026-08-09, and 34 by the end of the day. Four pairs crossed the two families, three sat inside the stroked one, and the eighth is below. None of them was a variant with a stated purpose; each was a second drawing of the same idea, made on a different day. The table is kept as it was read, and the answer is now in the last column of each row.

Two of the eight were not pairs at all, and a shape census cannot tell. The "second close" is the X brand mark in the footer and the "second chat" is Discord. A census that reads geometry and not meaning will file a logo as a duplicate of a control every time.

And the eighth is the mirror of that, which is why the census missed it entirely. The seven above were found by shapes that RESEMBLE each other. A circle and a triangle do not, so the two warning marks read as two different glyphs doing two different jobs, and they sat under the same sentence on twenty screens for weeks. A shape census can only find a duplicate that looks like one: this one was found by reading what the mark stands next to, "Couldn't load", sixteen times in a circle and four in a triangle.

Job The two drawings Which wins, and why close438 readings between them
M6 6l12 12M18 6L6 18 348 / M5 5l14 14M19 5L5 19 4
Not a pair, and this row stopped a sweep on 2026-08-13. The second is the X brand mark of the footer social row and it stays a brand mark; backlog 144 cut that row, so it has 0 product placements and 4 on this stand, which are now the only copies of it and are written out by hand on purpose. The first is the close, it stays a line, and since 2026-08-13 it is #l-close in the sprite along with the other five movements. The pass that moved them swallowed this one first, because two drawings that look alike read as drift, and the page that had already decided is what caught it
search4 readings
Same circle, handle M16 16l5 5 outward / M20 20l-4-4 inward
Done. Both are i-magnifer-o now, one filled glyph over 6 placements
clock45 readings
r=9 with hands 7v5l3 2, 44 / r=8 with hands 8v4l3 2, 1
Done. Both are i-clock-circle-b, 45 placements. Two circle radii for one job was the clearest case on the page of a set with no grid discipline
bookmark303 readings
stroked, 88 / filled i-bookmark-b, 215
Filled wins, 88 placements converted. It is the one that mattered: both were in use for the SAME meaning, at two different inks, in the same header
bell108 readings
stroked, 35 / filled i-bell-b, 73
Filled wins, 37 placements converted
shield212 readings
stroked with tick, 106 / filled i-shield-b, 106
Filled wins, 110 placements converted. 106 against 106 was not a preference that drifted, it was two decisions taken in two places
chat114 readings
stroked, 105 / filled i-chat-b, 9
Not a pair. The 105 are the Discord mark in the footer, which is a logo. The real chat is filled and always was
warning20 readings
i-danger-circle-b, 16 / i-danger-triangle-b, 4
The triangle wins, 16 placements converted, and the circle leaves the set. Both trees carried the same split on the same files, so this was structure and not paint, and it was fixed grey first. The count said circle and the convention said triangle: a triangle is the error mark a person already knows, and it was already on the loudest two surfaces, the main feed error and the 500

The rules, and what this decides

Rule. One cell, one field, one weight. viewBox="0 0 24 24" on every glyph; paint in 2..22, checked against the paint; the stroke reads a token and lands on a whole module. Anti-rule. An icon is never the only name of an action, and a glyph is never redrawn because the old one looked slightly wrong in one place. That is how a set gets seven jobs and eight drawings.

Rule, 2026-08-09. An object is filled and a movement is a line, and weight is what holds them together. A bell has an interior and a cross does not, so the split is a fact about marks rather than a preference between styles. Solar Bold for the first kind, a hand line at 2.2 for the second.

Rule, 2026-08-09. Every rule that paints an icon names both stroke and color. The set has two kinds of mark and they read different properties, so a rule that names one paints half of what it is pointing at.

Rule, 2026-08-09. A brand mark is not in the system. It keeps its own drawing, takes no system ink, and no generic glyph may stand in for it.

Never take a licence by naming the set. Fifteen Solar glyphs shipped for weeks under a comment that said "Solar Bold icon sprite" and no attribution anywhere. CC BY asks for the author, the licence and whether it was changed, and a comment naming the vendor is none of the three. NOTICE.md.

What goes into the consolidation

  1. 1The stroke becomes a size-aware token, not a constant. Re-read 2026-08-09: three declarations in user units, 2.2 on .ic, 2.4 on .ic-sm and 1.8 in market.css, are what make the line run 1.20 to 2.02 over four boxes. The fix is a stroke per rendered size, so 12, 16, 18 and 22 all paint the same weight on screen, and the file that writes its own goes with it.
  2. 2The safe field is declared at 2 and the line family is redrawn to it. Re-read 2026-08-09 against the consolidated set: one mark of six is inside the field, the menu at 1.9, and the rest run 2.9 to 4.9, so the chevron's old 5.2 is no longer the problem. The filled family holds 2.0 or better on 20 of 21 and the exception is the clock at 0, which is backlog 70 and a swap rather than a redraw.
  3. 3DONE 2026-08-09. The two families are declared, and neither one won. An object is filled and a movement is a line: 20 filled glyphs over 1,517 placements, 6 line marks over 990, and the four crossed jobs are filled. "All of them filled" was asked for and is not available, because six of the marks have no interior.
  4. 4DONE 2026-08-09. The three duplicate pairs are collapsed, two of them into one filled glyph each and the third revealed as a brand mark rather than a duplicate.
  5. 5The provider marks get a written exception and stop being four untokenised hex values with no rule attached.
  6. 6.ic-sm is deleted as a size. It is the smallest box carrying the thickest user-unit stroke, which is the exact inversion of what a small glyph needs, and it exists only because nobody had measured the rendered result. Re-read 2026-08-09 it is not even a size: of 358 placements, 354 are 12px and four are not, all four on the toast, where toast.css rewrites the box to 18 and the stroke to 2.2, and rewrites it again to 22 and 2.4 on the error face. A class that a component re-declares from scratch is a name the markup carries, not a size the system owns.