The same button. A new structure underneath.
The base button rule of takenote, an open-source notes app (MIT), before and after conversion. After conversion, the same rule reads the tokens Loom generated for it. Move the slider: the rule converts value by value, and the look stays the same.
%buttons {
border: 2px solid $primary;
border-radius: 0.3rem;
background: $primary;
color: white;
font-weight: 600;
font-size: 1rem;
padding: 0.5rem 0.75rem;
margin: 0 0 0.5rem 0;
line-height: 1;
}
%buttons {
border: 2px solid var(--semantic-action-primary);
border-radius: 0.3rem; /* 0.3rem: no token has this value */
background: var(--semantic-action-primary);
color: var(--palette-gray-10);
font-weight: 600; /* out of scope: not a colour, spacing, radius or shadow */
font-size: 1rem; /* out of scope: not a colour, spacing, radius or shadow */
padding: 0.5rem 0.75rem; /* 0.5rem: space.3 is 8px; px against rem is a decision, not a swap; 0.75rem: no token has this value */
margin: 0 0 0.5rem 0; /* 0.5rem: space.3 is 8px; px against rem is a decision, not a swap */
line-height: 1; /* out of scope: not a colour, spacing, radius or shadow */
}
What each token resolves to, in the generated file
var(--semantic-action-primary)→{proto.primary}→#5183f5needs a human decisionvar(--palette-gray-10)→#ffffffneeds a human decision
Token names, values and statuses are copied from the token file Loom’s conversion generated for takenote (24 October 2026). The after rule is written by Loom’s token codemod from that file, not by hand: exact matches are swapped at high confidence, the $primary variable at medium confidence, and the 0.5rem spacing stays as it is, because the generated token is in px and a unit change is a decision for a person.