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.

Molecule12 grey pages1 content axis, 3 values3 states, both themes

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

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

A hairline, and nothing else

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

No 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.

Never a card, never a badge
A boxed, filled, iconned trust panel: three marks for one quiet claim

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.

Use it for the source of figures

From Chase, read-only. Tendd cannot move your money.

Last checked today, 9:14 AM.

Data and privacy

Anywhere 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.

Use a promise list before the connection
Read-only, through Plaid, and about a minute. Tendd cannot move your money.

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 privacy

The 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.

Restlight
--text-action on the ink and on the shield, --line-divider on the rule above
Restdark
petrol climbs the scale rather than descending it: --text-action resolves to the lightened petrol at 6.8:1 on the dark surface
Hoverlight
the ink holds at --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
Hoverdark
the same move on the other half of each pair: the underline climbs from the dark tint to the lightened petrol, so it steps away from its ground in this theme too
Focus visiblelight
--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 separated
Focus visibledark
the ring is the one state this component demonstrably has in both themes, and it is the one it declares nothing for
Retake, 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

ReadsWhich tokenGrowing 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--tapprimitive, 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>