Logo

The square a merchant's mark sits in. It is the only saturated object in a subscription row, and it is the one thing on a screen that is data rather than chrome: it is the person's own Netflix, rendered as Netflix.

Atom21 grey pages111 places5 sizes, 3 contentsno states, not interactive

Anatomy

One zone and one content slot, which is what makes it an atom. Everything below is drawn by design/system/components/logo.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.

Variants and sizes

Two axes. Size is set by the container and never by importance: the same Netflix mark is 52px on a detail hero and 22px in the reveal's chip group because the host is bigger, not because that subscription matters more. Content is what we know about the merchant, and its three values are three different sentences.

Size

Set by the HOST. A logo never carries a size class of its own, and there is no .logo.large: if a square is the wrong size, the host is what changes

Corner Its host
52 .hero .logo --radius, 14px the subscription detail hero. Past 36px the square stops reading as a control and becomes a container, so it takes the container corner
36 .logo --radius-sm, 10px the base, and the list row: the object the whole product is made of. Also the source card, and since 2026-08-14 the landing window's tile. 97 of the 136 places, recounted that day
32 .alert .logo --radius-sm an alert item, where the mark yields a little to the sentence beside it
30 .tile .logo --radius-sm a preset tile on Add a subscription, where the mark is the whole point of the tile
22 .rgroup li .logo --radius-xs, 6px the reveal's chip group, where marks run in a line as evidence rather than as rows. At 22px a control corner reads as a pill, which is the same argument that named --radius-xs for the chip
20 - The grey draws the reveal's group at 20px (wireframes/_wf.css:623) and the colour layer has shipped 22 since stage 07. The inventory's "20 / 22 / 30 / 32 / 36 / 52" counts both files; only five of those six sizes render anywhere today. Listed so the sixth is not re-derived from the grey at stage 12
Content

Three values, and each says something different about what we know. Do not use one to stand in for another: a loading square that never resolves is a lie, and an unmatched square that pulses says we are still trying

Tokens What it says
A mark .logo > img --bg-callout we know the merchant. 14 marks cover the whole canonical dataset; the fill behind them is the callout wash, so a mark with transparency still has a square
Unmatched .logo, no image --bg-callout
--line-container
--text-muted
we looked and could not name it. Node 2.7's unrecognized state is the whole reason that screen exists, and the grey writes "[ ? ]" where a mark would go. The one form with a border
Loading .logo.is-skel --bg-placeholder we do not know yet. It takes the skeleton fill so it reads as part of the loading row, and it does not pulse: only .skel animates. See Skeleton bar

Four of the five sizes are shown live above and the fifth is not, for a reason worth naming. The hosts of the 52, 32 and 30 forms are plain classes, so a bare <span class="hero"> is enough to reach them here. The 22px form is selected as .app .rgroup li .logo, and the li in the middle is an element rather than a class: it can only be reached by building a real list, which would drag a browser list marker onto this page and say nothing true about the component. It is live on Guided Reveal. This is the same finding the chip page records about .appbar .plan, and the same repair closes both: step 6's rename moves the size onto the square rather than onto the path to it.

Solid, not dashed, and this is the one place the colour layer departs from the wireframe convention on purpose. The grey draws every logo square with a dashed border (wireframes/_wf.css:311 for the row, :638 for the hero) because that is what "we have nothing to show" means in a wireframe. DESIGN.md forbids a dashed border outright: "There are no dashed borders, no double borders, and no border that exists to decorate a block that would read fine without one." The container hairline plus the callout fill says the same thing in this language.

One number here disagrees with DESIGN.md, and the code wins. Its prose calls this "a 40px logo tile"; the stylesheet has shipped 36 since stage 07, on 136 places across 21 pages (111 before the landing window put 28 marks on the public page). Step 3 decided the document moves to the code and not the other way round, and the row is on the correction checklist in docs/tokens-audit.md. Nothing in this component is 40.

When to use it

A person recognises their own subscriptions by their marks before they read a single word, and that is the whole job: on Home the fourteen squares are what turn a list of amounts into my list. DESIGN.md sets the rule that makes it work: a real name and a real mark wherever the merchant is known, never a cryptic bank code, never stock art, never an illustration standing in for a company. The founder's decision on 2026-08-10 was full colour real logos, and zero photography anywhere in the product.

The containment rules are binding, and they are what let a brand colour into a calm screen at all. The mark is the only saturated thing in its row: the amount, the name and the date stay ink and muted, and a row never tints its background, its border or its text to match the brand. Petrol never sits inside the square, so the one accent and the brand colour never touch, and no brand colour appears anywhere outside the square. The One Voice Rule survives fourteen logos because of exactly those two sentences.

Where a person meets it: on Home in every group, on a subscription detail as the 52px hero mark, on Add a subscription inside the preset tiles, on Alerts beside each sentence, and on the guided reveal as a line of small marks that is the evidence for the number above it.

The rule, and the anti-rule

Use a logo

A merchant, in a row that is about that merchant. The mark is data: it identifies the thing the row is about, so it belongs to the content and not to the interface.

Use a destination icon instead
Home · Alerts · Save · You

A place inside the product is not a merchant, and it takes the destination icon, .ic-*: a mask painted in currentColor, with no brand colour and no fill behind it. The tell is ownership. A logo belongs to somebody else and is allowed to be saturated; a destination mark belongs to Tendd and therefore inherits the one voice. Putting a merchant mark in the tab bar, or a masked glyph in a subscription row, breaks the rule in both directions at once.

Say we could not name it

An unmatched charge gets the bordered empty square and the plain question mark. It is honest and it is quiet, and the screen beside it says what to do about it in a sentence.

Use a wash block instead, and only if something failed
We could not refresh just now.

An unmatched merchant is not an error, so it never takes clay and never takes an error tone. DESIGN.md: clay is scoped to a genuine failure, and "Don't use clay on an empty state. Nothing went wrong in an empty state." When something really did fail, the object is the wash block, .wash.error, carrying a sentence and a way to retry. The square stays neutral either way.

Limits

U13, context. LIFT. The merchant mark rises by one nudge and grows to 1.06 when the target it stands in is hovered: a row, an alert, a preset tile or a door. It is the identity of the thing you are about to open, which is why the mark answers and the amount beside it never does. The rule is scoped to the pressable form of every host and excludes .is-skel twice over, so a placeholder never lifts. Everything in this product that moves travels exactly one --nudge, which is 2px, and nothing anywhere travels two. Hover and release run at --dur-state (150ms) on --ease-arrive; a press runs at --dur-press (90ms), because it answers a finger that is already down. The full language and the live specimens are on Motion; the table with sources is Usage rules.

States

None, and that is a decision rather than an omission. The square is never the tap target: on every screen the whole subscription row is one link with one accessible name, so a screen reader reads the subscription and not five fragments, and a pointer that hovers the mark is hovering the row. logo.css therefore declares no hover, no focus and no disabled, and the row's own hover is the row's rule. The three forms above are content, not state: they say what we know about the merchant, and none of them is reachable by an interaction.

The technical half

ReadsWhich tokenGrowing from
the square behind a mark--bg-callout--canvas. The same role the unmatched square takes: both are a wash inside a card, and in the dark theme they lift off the surface together
the loading square--bg-placeholder--skeleton
the unmatched border--line-container--hairline. Decorative, not a control edge: nothing about this square has to be found by touch
the "[ ? ]"--text-muted--muted, the single secondary tier. 5.17:1 on the callout fill
the three corners--radius, --radius-sm, --radius-xsprimitive, straight: geometry has nothing to override

Lives in design/system/components/logo.css. The fourteen marks themselves are files in design/visuals/logos/ and are catalogued, with their fidelity debt, on Icons and marks. Stands on 22 grey pages and 22 coloured ones, in 182 grey places and 207 coloured ones, recounted 2026-08-20. It said 136 for both sides; the two corpora carry the same PAGES and not the same places, and the 25 that differ are all on the landing, the one page the colour may differ on by more than styling. Coloured screens carrying it: Home, Subscription Detail, the unrecognized state, Home, loading, Add a Subscription, Guided Reveal.

<span class="logo"><img src="visuals/logos/netflix.svg" alt=""></span> <span class="logo">[ ? ]</span> <span class="logo is-skel"></span> the size comes from the host, never from a class on the square: <div class="hero"><span class="logo">...</span></div> 52px <li class="alert"><span class="logo">...</span></li> 32px