The same pinned sentences as PR #8942, laid out so a non-technical admin sees name → can → can't in one eye movement — and can compare all five roles in one place.
16 Sept 2026 · branch lane-e/role-card-design · captured against propflow-stage · at 9b5602fe6d
Data note. Every name and balance below comes from propflow-stage, which is anonymized by construction (ADR-0097/0110 — phones in the impossible +1000 NPA, emails @example.test). The identical capture against prod would carry real tenants' names and balances and is not safe to attach anywhere, which is why the generator refuses to run against one.
Typing an address touches the row and the card appears under the select. What changed from #8942 is the SHAPE, not the words: a tinted tile carrying the role's glyph on the app's own --color-role-pm-* tokens, the role's name beside it, then the two lists side by side under Can / Can't eyebrows. The boundary — the part an admin is actually checking — is one eye movement to the right instead of four sentences down.
Hierarchy is size, tracking and ink: 13px name, 11px tracked uppercase eyebrows, 12px lines in --color-text-muted (5.34:1). Nothing above weight 500 — the theme clamps it anyway.
Asserted in the captured DOM — Property manager · Run the day to day: leasing, maintenance, collections, residents and vendors. · Make somebody an organization admin. · Compare with other roles. The role's name, one can-line, one can't-line, and the folded compare affordance — in the state the screenshot shows.
Picked from the select. Four can-lines against two can't-lines is the honest proportion for the role that runs the account, and the two columns keep that proportion visible instead of burying the short list under the long one. The shield glyph sits on the --color-role-orgadmin-* pair.
Asserted in the captured DOM — Organization admin · Invite teammates, change what they can do, and remove them. · Add PropFlow staff to the company.. The ORGANIZATION ADMIN block after a pick — not the default role's.
Two can-lines beside three can't-lines: the right-hand column being the longer one is itself information. “Open maintenance or vendors at all” is the fail-closed reading and it is exact — this role has no key for either entity in the matrix. The key glyph is on the leasing pair.
Asserted in the captured DOM — Leasing agent · Run leasing end to end: prospects, tours and renewals. · Open maintenance or vendors at all.
The one role whose can't-list has no “see a building they have not been given” sentence, because it cannot open the buildings section for ANY building — role-grants.ts says why, and this card adds nothing to it. Wrench on the maintenance pair.
Asserted in the captured DOM — Maintenance · Run work orders from start to finish, and manage vendors. · Open leasing, buildings, or what a resident owes.
There is no --color-role-viewer-* pair in the token set, and the card does not invent one: the eye glyph sits on the neutral hover surface in muted ink, which is also the right signal for the one role that changes nothing.
Asserted in the captured DOM — View only · Change or add anything, anywhere. · Invite anyone.
The fold is closed by default — the question the card answers is about ONE role — and opens to the other four beneath the selected one, each in the identical block shape separated by a hairline, so the five read as a set. The compare button's caret turns, aria-expanded flips, and nothing else on the step moves. A taller viewport here so the whole set is in one frame; on a real screen the dialog scrolls internally.
Asserted in the captured DOM — Property manager (selected) · Organization admin · Leasing agent · Maintenance · View only · Work in every part of PropFlow: properties, leasing, maintenance, collections, residents and vendors. · Look at everything the company runs in PropFlow — leasing, maintenance, collections, residents, vendors, buildings and settings.. Every role's name is on screen at once — none of them is in the (closed) select — the held one marked (selected), plus the first can-line of the first and last compared roles.
At 390px the row grid collapses to one column (.ob-row-grid) and the card's own columns follow suit without a media query: auto-fit over a 200px minimum cannot fit two inside the card's 302px, so Can stacks above Can't. The tile and name stay on one line; the glyphs never shrink beside a wrapped sentence.
Asserted in the captured DOM — Property manager · Run the day to day: leasing, maintenance, collections, residents and vendors. · Make somebody an organization admin.
The role with the most words, at the narrowest width this wizard is used at. Each line wraps under its own glyph, not under the glyph column.
Asserted in the captured DOM — Organization admin · See every building the company has, including ones added later. · See anything belonging to another company.
Five blocks, one column each, hairlines between. A tall viewport so the whole set is in one frame; on a phone this is the dialog's own scroll.
Asserted in the captured DOM — Organization admin · Leasing agent · Maintenance · View only · Invite anyone, or open settings.
The wizard renders a theme switch of its own, so dark is reached the way a customer reaches it — by clicking it. Every colour on the card is a token with a dark-mode value: the role tile pairs, the hairline, the muted ink, the success check. Nothing here is a hex.
Asserted in the captured DOM — Property manager · Run the day to day: leasing, maintenance, collections, residents and vendors. · Compare with other roles
The four role tints have dark-mode values in globals.css; the viewer tile's neutral pair does too. This is the frame that would show a tile going invisible, and it does not.
Asserted in the captured DOM — Organization admin · Leasing agent · Maintenance · View only · Change or add anything, anywhere.
Neither identity this tool signs in as can reach the wizard (the smoke account is platform staff and is redirected; the seeded non-staff identity is already onboarded and is redirected too), so the run was forced down the tool's anonymous path with a deliberately wrong smoke credential: a local dev server serves the step unauthenticated, and these frames are the step exactly as a customer meets it. The run's own guard confirmed the data source was propflow-stage before a browser launched.
What these frames do NOT prove: that the sentences are true. That is role-grants.ts's job, pinned by roles.test.ts against the catalog, and this PR did not touch a word of it.