Trust block
The three lines under a screen of figures that say where the figures came from, what we can and cannot do with the account, and when we last looked. Plus one link to the full answer. GC6 in the IA, and one of only three places in this product where petrol is allowed at rest.
Anatomy
One to three text slots and one link slot, plus a mark drawn by the component itself. Everything below is drawn by design/system/components/trust-block.css through the same entry point a product screen loads, so this page cannot drift from the screens.
From Chase, 11 subscriptions, and 3 you added yourself.
Read-only. Tendd cannot move your money.
Last checked today, 9:14 AM.
Data and privacy.trustthe molecule: a hairline above, 24px of left padding to make room for the mark, and the muted tier throughout. No fill and no card, because a boxed trust claim reads as an advert for itself.trust::beforethe shield. A CSS mask over a solid petrol fill, on a pseudo-element, so a screen carries nothing but the class and the mark never enters the accessible treepone line per promise: the source, the read-only claim, the freshness. Separate paragraphs and not one sentence, because they are separate promises and a reader checks them one at a time. A screen that cannot keep one of them drops the paragraph> athe way to the full answer. A direct child, which is what earns it the 44px target floor: an anchor inside apwould be running text and exemptborder-topthe only line it draws.--line-divider, decorative, no contrast threshold owed: nothing here has to be found by touch
It hosts no atom, and that is worth stating on a molecule page. Everything inside it is a bare p or a bare a: the three lines are not muted lines and the link is not a quiet line's link, because both are sized and coloured by this block rather than by themselves. It is a molecule by the first half of the definition, four content slots in one unit.
Variants and sizes
No CSS axis, and one content axis that needs no class. Every page draws the same block: the same rule, the same padding, the same shield, the same 12px muted tier. What changes is how many promises there are, and the product gets that by writing fewer paragraphs. Counted rather than assumed, across both folders: three lines on 3 pages, two lines on 8, one line on 1. A component that compresses by holding less content is not a component with a size modifier, and giving it one would be a class that says what the markup already says.
| Content One line per promise the screen can actually keep. The source, the read-only claim and the freshness are three promises; a screen that has no source yet drops the source rather than inventing one. Never drop the read-only line: it is the one every form of this block carries |
Measured | Where it stands |
|---|---|---|
| Three lines | 3 × p + a | Home and two of its states. The source line counts the list above it, so it earns a line of its own |
From Chase, 11 subscriptions, and 3 you added yourself. Read-only. Tendd cannot move your money. Last checked today, 9:14 AM. Data and privacy | ||
| Two lines | 2 × p + a | 8 pages: every subscription detail state, and the alerts error in the grey. One account rather than a list, so the source folds into the read-only sentence |
From Chase, read-only. Tendd cannot move your money. Last checked today, 9:14 AM. Data and privacy | ||
| One line | 1 × p + a | 1 page, sign-in, still grey. There is no bank yet, so there is no source and no freshness, and the one promise left is about what we hold at all |
Tendd holds an email and a currency, and nothing else. What we read | ||
What the IA says about this, and what the markup answers. docs/inventory.md records that GC6's compressed form has four names: five node files call it "short", globals.md calls it "one line", node 1.1 calls it "long-form". The markup settles it: there is no short variant, there is a block that carries between one and three promises, and the two nodes that name a short form on a page, 1.3 and 6.15, have no .trust on the page at all. Four names for a thing the CSS never needed is a documentation defect and it is logged as one, not fixed with a modifier.
There is no size axis either. The block is 12px throughout, one step under the body, on every screen and at every width. That is deliberate and it is the reason the component survives being read: it is a footing, and a footing that grows with the screen stops being one.
When to use it
The trust block goes at the bottom of any screen showing money that came out of a bank. It is the fourth design principle drawn rather than claimed: say what happens with the data, every time, and show the source of every figure. research/docs/benchmark.md names trust and first-time clarity as the one dimension that decides this product, and wireframes/docs/screens.md names this block as one of the three elements on the etalon screen that carry it.
It answers three questions in the order a sceptical person asks them. Where did this come from ("From Chase, 11 subscriptions, and 3 you added yourself"). What can you do with my account ("Read-only. Tendd cannot move your money"). How old is this ("Last checked today, 9:14 AM"). Then it offers the whole answer, because a claim with no way to check it is a slogan. On a screen that cannot keep one of the three, that line is dropped rather than softened. The read-only wording is locked in voice/docs/microcopy.md as dictionary entry D7 and the firm verb is deliberate: cannot, not "can never" and not "will not".
Petrol at rest, twice, and this is the third of the accent's four permitted jobs. D-Concept spends the accent on the primary action, the current selection, and the trust line. The shield marks the block rather than one line, because all three lines are the claim; the link takes the same petrol because it is the claim's own proof. Everywhere else in this product a resting link is ink and the underline carries the affordance.
The rule, and the anti-rule
From Chase, 11 subscriptions, and 3 you added yourself.
Read-only. Tendd cannot move your money.
Last checked today, 9:14 AM.
Data and privacyNo fill, no border, no card, no shadow. It is the footing of a screen and not a panel on it, and it earns its separation with one divider, which is what the Flat Paper Rule in DESIGN.md asks for. The only saturated thing in it is a 15px shield.
A trust claim inside a bordered, filled box reads as a badge the product awarded itself. The louder the frame, the less the sentence is believed, which is the opposite of what this block is for. If a screen genuinely needs a raised surface for something, that is the card, .card, and a trust claim is not what goes in it.
From Chase, read-only. Tendd cannot move your money.
Last checked today, 9:14 AM.
Data and privacyAnywhere the screen shows a number that came from a bank. The block says where, what we may do, and how fresh, in that order, and it holds as many of the three as the screen can honestly keep.
Before a bank is connected there is no source and no freshness, so two of the three lines have nothing to say. The component for a claim about what will happen is the promise list, .promises, which is a list of undertakings rather than a report on data. Confusing the two is how the connect screen ended up with a trust block asserting a last-checked time for an account that did not exist yet.
Limits
U8, composition and context. One trust block per screen, and only where a figure on that screen came from the bank. It is the read-only declaration, not decoration: four screens carry it and none carries two.
U17, composition. This block takes order: 4 at the desktop point, and the declaration is the shell's rather than this file's: ordering siblings is the parent's job, and this file refused it first and said so in its header. Since 2026-08-19 the whole set is guarded on :has(> .groups), so a screen that carries a trust block without a groups column set is left in its authored order. Full table with sources and how to check: Usage rules.
States
Three, and they belong to the link. The block is not a target: it is not an anchor, not a button and not pressed on any of the 12 grey pages or the 12 coloured ones, and the shield is a pseudo-element that cannot be reached at all. The link has rest, hover and focus visible. No disabled: a trust claim is never unavailable.
Rest, live
From Chase, 11 subscriptions, and 3 you added yourself.
Read-only. Tendd cannot move your money.
Last checked today, 9:14 AM.
Data and privacyThe shield renders here, and it was checked rather than assumed. The four tab bar masks do not render on a stand page, and their own page says so and shows the shapes another way: their machinery is selected as .app .tabbar a .ic and needs a whole ancestor chain no stand scene has. This one is selected as .app .trust::before, the scene above carries .app, and that is the whole difference. Measured on this page: content: "", a 15 by 15 box at left: 0; top: 16px, background-color: rgb(28, 106, 118), and a mask image that decodes. Nothing is faked and nothing is drawn inline.
The link, 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-action on the ink and on the shield, --line-divider on the rule above--text-action resolves to the lightened petrol at 6.8:1 on the dark surface--text-action and the underline goes from --line-action-soft to --text-action. It was identical to rest until 2026-08-12, and the arithmetic that made it so is below--color-focus, drawn once for the whole system by base.css at specificity 0. It read --line-selected until 2026-08-12, when two roles claiming one job were separatedRetake, same recipe as the etalon, because there is no node Playwright in this repo:
serve the repo, then for theme in (none, data-theme="dark" on <html>):
goto /design/kit/trust-block.html
move the pointer away -> screenshot #live-rest -> screens/trust-block-rest-<theme>.png
hover #shot-link -> screenshot #live-rest -> screens/trust-block-hover-<theme>.png
Tab to #shot-link, assert :focus-visible
-> screenshot #live-rest -> screens/trust-block-focus-<theme>.png
The hover pair now differs from the rest pair in exactly one value, the underline. Until
2026-08-12 it was byte identical, and that absence is what the snapshot was for.
The hover did nothing at all, on the product's most read link, and nothing in either file said so. On 2026-08-12 it came back. Measured before and after, on this page and on the product. Before: at rest rgb(28, 106, 118) with an underline in rgb(231, 237, 238), and under the pointer rgb(28, 106, 118) with an underline in rgb(231, 237, 238). Not one value moved. After: the ink holds at rgb(28, 106, 118), which is right because petrol at rest is already the answer and a link that changed colour here would be spending the accent twice, and the underline goes to rgb(28, 106, 118). A 1.18:1 whisper becomes the full petrol at 6.2:1, both figures tokens.css's own.
The arithmetic, because it is what makes this a repair and not a redesign. kit.css declared this link four times: an unscoped rest rule shared by ten link families, an unscoped hover, and two adjacent .app .trust a rules further down that set the size and the colour again. The first rule's font-size and both of its colours were overridden by the fourth, so two of its three declarations never rendered at all; the second tied with the fourth at 0-2-1 and lost on source order. Nobody wrote that behaviour. It is what four rules for one link produce when two of them happen to weigh the same, and it survived unseen because the ink was already petrol, so the tie only shows in a hairline.
Four rules became two, and order no longer decides anything. Rest is one rule at 0-2-1 and hover is one rule at 0-3-1, so the hover wins on specificity and nothing written later in any file can quietly take it away. The rest rule is scoped now, which is the same repair one level down: an unscoped .trust a would paint a link in the reviewer's chrome. Every value is one kit.css already wrote, and the hover is the one it declared and could not deliver. The product screens took the repair in the same breath: they load ../system/index.css now, and kit.css is deleted.
The technical half
| Reads | Which token | Growing from |
|---|---|---|
| the three lines | --text-muted | --muted. The single secondary tier, and there is no third |
| the shield, and the link at rest | --text-action | --petrol. An INK role on the shield, because the architecture counts an icon glyph as ink and not as a fill |
| the link's underline | --line-action-soft | --petrol-tint. Declared for this, see below |
| the rule above the block | --line-divider | --hairline-soft, decorative, no threshold owed |
| the target floor | --tap | primitive, straight: a size has nothing to override |
The hole was reported rather than invented, and is now filled. The link's resting underline is the petrol tint, and the system had no line role on that value. It had --bg-selected, which is a fill, and the architecture forbids one role on two surfaces even at an identical value. So this component read a fill for a line, with a comment saying so, exactly as the text input read --text-failure before --line-failure existed, and the parent then declared --line-action-soft at the same value. Nothing moved when the loan was repaid. Declared against the rule that one usage is not yet a role, and the exception is named rather than quietly taken: that rule guards against palette inflation, while the surface axis forbids outright what the alternative was.
It was measured before the hole was claimed, because a reported hole that turns out to be fine costs more than no report at all. The tint underline is 1.18:1 on the light surface and its dark pair is 1.20:1 on the dark one: consistent, deliberate, and a whisper in both themes, which is the right answer here because the ink is petrol and carries the affordance by itself. So this is a naming defect and not a contrast one. The value is correct; the role it is read through is not.
The shield is a mask and not an inline SVG, and it sits on a pseudo-element. That means a screen carries nothing but the class, and it means the mark is not in the accessible tree: the three sentences already say what the shield says, and a screen reader reading it twice would be worse than one never reading it. It cannot take currentColor the way the destination icons do, because the block's own colour is --text-muted and the shield has to be petrol. The encoded SVG's own stroke='%23000' is dead weight either way: a mask reads alpha and never hue. The prefixed -webkit-mask is declared before the unprefixed one, because Safari still answers only to the prefixed property and the unprefixed one has to be able to win where both are understood.
One rule is deliberately not in this file. .app > .screen > .trust { order: 4 }, from the 900px container block, is one of four sibling order declarations that only mean anything together and it names the shell's grid rather than this block. It belongs to the App shell organism, and it is named here and in the component's header comment so it cannot be lost between two files.
This component's class does not change, and that is why its link could be settled early. The renaming map leaves .trust alone, so nothing below waits on markup: the rest and hover rules above are their final form. The wash block's link had the same defect and the same fix, and there the selectors had to carry both the old name and the new one for a round, because .notice and .attention were both on the map. Step 6 landed that markup and the old half is gone.
Lives in design/system/components/trust-block.css. Stands on 13 grey pages and 13 coloured ones across 5 screens, which is the whole of the grey. The count moved 12 to 14 on 2026-08-20, when the two rungs of the count ladder each took a trust line saying that no bank is connected - the honest form of the read-only promise on a list nobody read from anywhere. Coloured screens carrying it: Home, Home, could not refresh, Home, save focus, Subscription Detail and its four states, Alerts when the list will not load, Sign in, and since 2026-08-19 History and Trends, which is the only one that stands it beside its figure rather than at the foot of the screen. Recounted by design/kit/screens/counts.cjs.
<section class="trust" aria-label="Where these figures come from">
<p>From Chase, 11 subscriptions, and 3 you added yourself.</p>
<p>Read-only. Tendd cannot move your money.</p>
<p>Last checked today, 9:14 AM.</p>
<a href="data-privacy.html">Data and privacy</a>
</section>