Muted line
The second reading tier of the product, and the largest consolidation in the system: nine class names became one atom at three sizes with one ruled variant and, since 2026-08-16, a declared size axis of two. It is the sentence under a number, the consequence of an action, the footnote at the bottom of a screen, and it is the only quiet grey this product has.
Anatomy
One zone and one text slot, which is what makes it an atom. Everything below is drawn by design/system/components/muted-line.css through the same entry point a product screen loads, so this page cannot drift from the screens: there is no second copy of the CSS here to drift from. The rename landed on 2026-08-12. Nine class names became .muted in the CSS and in the markup of all 28 coloured screens in the same step, because a rename that lands in two halves is a screen that renders unstyled with nothing erroring.
a month, for what you have signed up for
Nothing is missing and nothing failed. Your list, your total and your alerts are all working as usual.
US banks connect through Plaid. More regions soon. What we read
colorreads--text-mutedon every one of the nine names it replaced. It is the whole of what they had in common, and the reason one atom could replace themfont-sizea declared axis of two:--type-bodyas the base and--type-metaon.fineand on the ruled variant. Set by the JOB the line is doing, never by importance, and never by a host reaching inmarginnone. A gap is a relationship between two things and only the container knows it. The hosts position this atom, and the three that had been living off the atom's margin now say so.ruledthe one variant that draws anything: a hairline above it, a step of padding under it, and the quieter size.finethe supplementary size, 12px, added 2026-08-16. The line that answers a question a person has AFTER the block has made its point. It draws nothing and changes no ink.muted pthe block form. The sentence lives in its own paragraph so the link beside it is a sibling and not running text, and it takes the 52ch reading measure> p ~ aa standalone link, the sibling that follows the paragraph, takes the 44px floor from--tapas a BOX. It is the shape a box is right for: its own line, nothing after it.ruled > athe same floor as PADDING, since 2026-08-17. Every one of its six placements is a link inside a sentence, and aninline-flexbox there hands 44px to the line and tears the paragraph open. Vertical padding on an inline element grows the hit area and never enters the line box
Behaviour at width
Every form carries the reading measure, --container-text, and the plain one only got it at stage 10. The ruled form and the block form's paragraph were already 52ch, so nothing moved when the four measures in the system folded into one token. The plain form had no measure at all, and the width sweep priced that: on History and Trends the line under the chart ran 1300px at a 1600 window, 150 characters to a line, and it did the same on all four states of that screen. Settings ran 620px, Home empty 536px. Nothing had asked for those widths; they are what a block element does when nobody stops it.
The measure is declared twice, and the second one is not a duplicate. A muted line that stands as a direct child of the screen ties at 0-2-0 with the shell's blanket max-width: none past the desktop point and loses on source order, so .app .screen > .muted is written at 0-3-0 beside it. This is the sixth element in the product to need that binding, which is why the blanket itself is now a question in docs/backlog.md rather than a fact everyone works around. At 360 nothing moves: 52ch is about 459px and no box on a phone is that wide. See Width.
Variants and sizes
Two axes and no third, and each one carries the rule for choosing on it. The matrix below is the consolidation itself: every old class name appears in the row of the size it now renders at, so the question "what was .pitch" has an answer on this page rather than in four files. There is deliberately no emphasis axis: a muted line that wants to be louder is a different component.
| Size Set by the CONTAINER, never by importance. The same sentence is |
Old names it carries | Where it stands |
|---|---|---|
14px --type-body |
.context .tone .removal .pitch .p .bycat .consequence .freshness p.notice |
The base, and after the fold it is nine of the ten old names. The line under a figure, the line under an action, and the consequence of the thing a person just did |
| a month, for what you have signed up for | ||
12px --type-meta |
.legal, as .ruled.p inside a preset tile |
The two places a container asks for the quieter step: the footnote at the foot of a screen, and the second line of a preset tile. Both have a token to hold the step, which is what let them keep it |
| The full privacy policy is at tendd.com/privacy. | ||
| The step that had no token | .consequence .freshness p.notice |
The one thing the fold could not carry, and it is recorded rather than hidden. These three rendered a step below the rest, and the markup they now wear has nothing on it to say so: .consequence is a bare <p class="muted"> exactly like the caption under a total. So they take the base and GROW. Measured out of kit.css: .consequence 12.5px and .freshness 12px, both to 14px, on 11 coloured places and 2 grey ones; p.notice declared no size at all and inherited the browser's 16px, so on Upgrade it goes the other way, 16px down to 14px. What is owed is a declared size modifier plus the class in the markup, which is docs/backlog.md line 56 word for word. None is invented here: a modifier no element wears is a rule that documents a decision nobody took |
| 12.5px in a row | .app .row .p, deleted 2026-08-12 |
The backlog line closed, and the count is why. Re-counted before it was cut, on both corpora and both instruments: querySelectorAll('.row .p') returned 0 on all 28 coloured screens of the day and 0 on all 55 grey pages, with .row standing 57 and 63 times and .p 13 and 17. The two families never meet. Nothing moved: a rule with no markup paints nothing. It was carried at step 5 because deleting a rule is a named decision and that round made none; the decision now exists, and a rule left standing outlives everyone who understood why. A subscription row's second line is .when, which the row's own file owns |
| Rule Ruled only where the line is a footnote to the whole screen and has to be told apart from the content above it. A rule between a number and its own caption would cut them apart |
Tokens | Where it stands |
|---|---|---|
| Plain | --text-muted | Eight of the nine names. The default, and the one a new line should reach for |
| Pays for itself with the first subscription you cancel. | ||
Ruled .ruled |
--line-divider 52ch |
7 grey pages, and it was .legal. The hairline is a divider and carries no contrast threshold: nothing here has to be found by touch. The rule is the modifier's and the measure is the base's: only this variant draws a line, but 52ch is the atom's reading measure and the two members that carried one carried the same number |
| The full privacy policy is at tendd.com/privacy. | ||
Fine .fine |
--type-meta | Added 2026-08-16, on the founder's word about the pricing band's last line: "сделать дополнительним". A supplementary line under a block that has already made its point is not the same object as the sentence that carries the point, and this atom had one size for both. It is a declared modifier and not a host rule, which is the whole reason it is here: a host writing a font-size onto a hosted atom is the defect this system names in three places, and the answer everywhere else has been to declare the axis and wear it in the markup, as the amount did a day earlier for the plan price. The ink does not change - a third tier of grey does not exist in this product and this does not invent one |
| No cap on subscriptions and no cap on banks in Free. Cancelling is free, always. | ||
| Toned | - | Forbidden with a reason rather than missing. An amber line about a price change and a clay line about a failure are the wash block, which has a fill, a corner and its own tone axis. A muted line that changes colour stops being the second tier and starts competing with the first |
The margins have gone, and that was the consolidation's whole finding. Nine names differed in almost nothing but the gap above or below them, and a gap is a relationship between two things, which is knowledge only the container has. The atom now carries none. Six hosts position it instead: the screen column, the summary under a total, the guided-reveal step, the detail shell, the preset tile and the share card. Three of the six had been living off the atom's margin without saying so, and they say so now. The pixels are the proof: 34 of the 38 muted lines on the coloured screens keep the exact gap they had, against 22 if the base had simply taken the commonest margin instead. The four that moved are in docs/tokens-audit.md, each with the file that owes it a rule.
2026-08-18: the line owes a distance below itself when something follows
The founder, on the coloured Upgrade screen: “нам би еще отступы покрутить би”, with a picture of a sentence sitting flush on the top edge of the plan row. This atom declares a top margin at screen level and no bottom, which is exactly right for the job it usually has - a footnote hanging under the block it explains, with nothing after it. It is wrong for the other job the same markup does: a line of context standing BEFORE the thing it introduces. The last block on a screen and the block before the offer are the same element in this system.
Counted rather than guessed, over all 54 coloured app screens. Sixteen of these lines stand as a direct child of a screen: twelve are the last block on their screen and four are followed by something, and all four measured 0px at 390 and at 1440 - “Saved as you go” sitting on “See your subscriptions” on Add a subscription, the same shape on History and trends, a muted line on a quiet line on the current plan, and the founder's own on Upgrade. :not(:last-child) is what leaves the twelve footnotes untouched.
And the same instrument found three more one level down. Inside a card: “Disconnecting stops Tendd from reading new charges” and “Removing this source deletes the 3 subscriptions you typed” on Your sources, and the reconnect sentence on its reconnect state - each with the button that carries it out sitting on the last line of the sentence. Same root, different host, so a different step: 24 at screen level and 16 inside a card, which is the card's own padding and its internal rhythm. The card's own evidence agrees: of the five action rows inside a card, the two that do NOT follow a muted line already stand at 24 (after a pair list, which pays for itself) and 16 (after a list in a prose card).
It cannot double in the flex column, and that was checked rather than hoped. Past the desktop point the screen is a flex column, so two adjacent margins add instead of collapsing - the trap that has a row of its own in docs/backlog.md. Measured before the change, all seven next siblings compute margin-top: 0px, so there is no second margin for this one to add to at either width. Verified after: all seven pairs read exactly 24 or exactly 16 at 390 and at 1440, and the box fingerprint over all 57 coloured pages moves exactly six pages, which is the six the sweep named.
When to use it
A muted line is the second thing a person reads, and it is always attached to a first thing. Under the monthly total it says what the number is ("a month, for what you have signed up for"). Under an action it says what will happen ("Saved as you go: 3 added so far"). At the foot of a screen it says where the figures came from. It never stands alone: a muted line with nothing above it is a sentence that has been switched off for no reason.
DESIGN.md names the tier it belongs to. The Two Tiers Rule: ink and muted, and a third lighter grey is not available, because it is the first thing to reach for when a layout feels busy and it is how a calm interface quietly becomes an unreadable one. The grey wireframes ran four tiers and six atoms wanted the fourth; it measured about 2.85:1 on the 11 to 12px text it was spent on, under AA. All six collapsed onto this one, which is why --text-muted is the largest role in the system at 59 usages and still holds 5.8:1 in the light theme and 6.4:1 in the dark. The hierarchy the fourth tier was carrying came back as weight and as case, which is where it belonged.
Its copy comes from voice/docs/microcopy.md and it is where this product does most of its reassuring: "Nothing is missing and nothing failed", "This one came from Chase, so removing it hides the row rather than deleting it", "US banks connect through Plaid. More regions soon". Calm, specific, and never an apology. It is also the only quiet text allowed to carry a link, which is what makes "Your sources" and "Remove from your list" reachable without a button shouting on a screen whose job is to look rather than to act.
The rule, and the anti-rule
$192.90
a month, for what you have signed up for
This is the job the component exists for: a figure never appears without saying what it is. The number is 46px and the line under it is 14px, eight of the grid below it, so the pair reads as one object with a caption rather than as two claims. Five coloured screens play it exactly this way, and that eight is the tightest gap in the whole family: it is why .summary takes the atom's positioning back rather than letting the caption drift out to a full step.
Your monthly total went from $172.90 in May to $192.90 in July, up about $20 across three months.
When the sentence IS the finding rather than a caption on one, it belongs to the readout: 15px, full ink, a 46ch measure. On History and Trends the readout is the answer and the muted line under it ("Streaming is up $6 since March") is the footnote. Setting the finding in muted grey tells a person the thing they came for matters less than the chart beside it.
US banks connect through Plaid. More regions soon. What we read
Small print with a way to read more, ruled off from the screen above it and held to 52 characters. The link is ink with a hairline underline, not petrol: petrol at rest is spent on the primary action, the current selection and the trust line, and small print is none of the three.
Can't find it? Add it by hand and fill the details yourself.
The line that offers a person the way OUT of a screen is the quiet line, and it renders at full ink for exactly that reason. "Do this later", "Use a different email", "Add it by hand": a person who is stuck is the person least able to read a footnote, so the exit is never in the second tier. The two components sit one line apart on several screens and the difference in ink is the whole signal.
Limits
U16, context. [hidden] is a fact about an element, and this component is one of exactly two in the system that out-declared it: .muted is display: block at 0-2-0 against the browser's own 0-1-0, so authoring hidden on a muted line did nothing at all, silently. History and trends found it: the summary under its category bars is written once per range and two of the three are hidden in the markup. The fix is not in this file. The display: block here is correct for a line that IS in the page; the one rule that settles it lives at the end of index.css, where source order lets it win without !important. Full table with sources and how to check: Usage rules.
States
The line itself has none: it is text, it is not a target, and a hover written for it would document something the product cannot do. Its link does. Four of the nine names host an anchor, and the census found that job wearing thirteen different rules across the grey stylesheet, differing in font size and in whether anybody had remembered the 44px target. It is one rule now, and it is a real state surface.
Rest, live
US banks connect through Plaid. More regions soon. What we read
This one came from Chase, so removing it hides the row rather than deleting it. If the charge appears again, Tendd will show it again.
Remove from your listThe two anchors are the two cases, and the difference between them is structural rather than a class. The first ends the footnote's own sentence and belongs to the ruled variant, which has a token in the markup. The second is the sibling that follows the block's paragraph, which is standalone, and takes the 44px floor: it is the destructive action on five detail screens, and before the floor existed it measured 15px tall.
The floor is a BOX for one of them and PADDING for the other, since 2026-08-17, and the reason is that a 44px box inside a paragraph tears the paragraph open. The sentence above this one, "the first ends the footnote's own sentence", was read off four of the ruled variant's six placements. On the other two the link stands INSIDE the sentence with text after it: path-choice reads "By starting you agree to our Terms and Privacy Policy. Tendd asks for read-only access and never for permission to move money", and data-privacy reads "The full privacy policy is at tendd.com/privacy." An inline-flex box hands its height to the line it stands in, so one line box of five was 44px tall in the middle of an 18px paragraph and the footnote read as two paragraphs with a hole between them. Measured at 1440: the paragraph was 79px where three lines of 18 and one of 44 is exactly 79, against the 53 it reads now. At 360 it was 97 against 71. Reported by the founder on a screenshot, which is where a stretched line box is visible and where a computed height is not.
And being last in a sentence is still being in one, so the other four are the same case: "US banks connect through Plaid. More regions soon. What we read" is an inline link in a paragraph, and it was paying the same 26px at the foot of the block where nobody looked. All six are one rule now: padding-block on an inline element, which grows the hit area, paints nothing and does not enter the line box calculation at all. The link is still 44px to a finger and the paragraph is back to its own leading. The value is derived and the derivation is a measurement: an inline box does not fill its line, its content box is the font's ascent plus descent, 15px for Inter at --type-meta against a line of 18. The first attempt subtracted the LINE and produced 41px links. The term is 44 - 15, halved, which is 14.5 a side.
The standalone link keeps the box, and not one of its 15 placements moved. .trust > a and .muted > p ~ a are direct children on their own line with nothing after them, which is the shape a box is right for. Verified over all 57 coloured pages at 360 and 1440: 6 pages differ and they are the 6 that host the ruled footnote's link, 30 boxes at 360 and 18 at 1440, every one of them the paragraph losing the 26px, the link's new position, or an ancestor absorbing it. 49 pages are identical to the pixel.
The structure had to be said more precisely than > a at the rename, and it is the one place the fold changed what a selector means. kit.css named .removal > a and .legal > a and left .consequence a out, and that arithmetic worked only because the three had different class names. They do not any more. Left as > a, the rule would have handed a 44px inline box to the two running-text links on History and Trends and on the Pro lock, which is the exact defect the floor is written to avoid. Measured after the change: five removal links at 44px, the footnote link at 44px, and the two running-text links still 17px, the height of their line.
The three, in both themes
The states are described, not photographed. Founder's decision, 2026-08-11: the snapshot strip went from every page in this kit, 120 images across 18 pages. They were framed as measurements rather than illustrations, and that framing was honest, but the bill came due all session: a value moves, and every picture of it is quietly stale until somebody re-shoots it. A stale picture is worse than no picture, because it looks checked. What is left is what a picture never carried anyway: the state, and the token it reads. The resting component is live and interactive above, so hover it, tab to it, and read the value off the real thing rather than off a photograph of it.
--text-muted on the line, --text-body on the link, --line-container under it--text-action, on the ink and on the underline together--text-action again, and in the dark theme it is the LIGHTER petrol: contrast runs against the opposite ground, so the accent climbs the scale rather than descending it--color-focus, from base.css at specificity 0. 6.2:1 as a line. It read --line-selected until 2026-08-12, when two roles claiming one job were separated:where() at specificity 0 precisely so a text link never has to repeat itRetake, and this is the whole recipe, because there is no node Playwright in this
repo and a command that does not run is worse than no command:
serve the repo, then for theme in (none, data-theme="dark" on <html>):
goto /design/kit/muted-line.html
move the pointer away -> screenshot #live-rest -> screens/muted-line-rest-<theme>.png
hover #shot-inline -> screenshot #live-rest -> screens/muted-line-hover-<theme>.png
focus #shot-standalone by Tab, assert :focus-visible
-> screenshot #live-rest -> screens/muted-line-focus-<theme>.png
Reached the way a person reaches them: a real pointer and a real Tab. NO FILE COMES OUT OF THIS TODAY, and the recipe is kept for the day one is
wanted rather than as a promise. The strip was removed by the founder on 2026-08-11 and the
states above are described instead, so there is nothing here for step 9 to diff. The earlier
wording said step 9 checks these files for a byte shift; it was written before the decision
and outlived it, which is the same freeze it was warning about, in prose.
The technical half
| Reads | Which token | Growing from |
|---|---|---|
| the line itself, all nine names | --text-muted | --muted, and --muted-dark in the dark theme |
| the base size | --type-body | primitive. 14px, and after the fold it is nine of the ten old names |
.fine, the ruled variant, and the preset tile's line | --type-meta | primitive. 12px. The modifier is the declared axis; the preset tile's host rule predates it and is a row in docs/backlog.md |
| the gap above or below | not declared here | the host's. Six containers position this atom and the atom carries no margin of its own |
| the inline link at rest | --text-body | --slate |
| the link under the pointer | --text-action | --petrol |
| the underline at rest | --line-container | --hairline. A line role on a text decoration, deliberately: a full strength rule under every link in a calm paragraph reads as emphasis |
the rule above .muted.ruled | --line-divider | --hairline-soft. Decorative, so it owes no threshold |
| the standalone link's floor | --tap | primitive, straight: a size has nothing to override. A BOX, min-height on an inline-flex |
| the footnote link's floor | --tap, minus 15px, halved | the same primitive reaching the same 44px as PADDING, because this link stands inside a sentence. The 15 is measured and not chosen: an inline box does not fill its line, its content box is Inter's ascent plus descent at --type-meta. Subtracting the LINE instead gave 41px links |
| the focus ring | not declared here | base.css draws one ring for the system at specificity 0 |
Lives in design/system/components/muted-line.css. Stands on 36 of the 57 grey pages, a figure the counter cannot recompute because the grey draws it under nine older names, and on 37 of the 57 coloured ones in 87 places, which it can. A sample of the coloured screens carrying it: Home, Guided Reveal, Subscription Detail, Add a Subscription, Upgrade, History and Trends, Settings.
<p class="muted">a month, for what you have signed up for</p>
<p class="muted">Nothing is missing and nothing failed.</p>
<p class="muted ruled">US banks connect through Plaid. More regions soon. <a href="...">What we read</a></p>
<div class="muted">
<p>This one came from Chase, so removing it hides the row rather than deleting it.</p>
<a href="...">Remove from your list</a>
</div>