Teammates step — the role card

What the role you just picked actually hands somebody, in words, from the same source of truth the app enforces.

16 Sept 2026 · branch lane-a-teammates-role-card · captured against propflow-stage · at 8431078d30

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.

1 · Nothing yet — a fresh form is not a wall of permissions copy

Every row HAS a role — a blank one starts on Property manager — so “render the card when a role is picked” cannot mean “when row.role is set”. It means once the row has been touched. This is the untouched state: no card, and the footer is where it has always been.

Asserted in the captured DOMAdd your team · Finish. The step renders; the card is absent rather than empty.

Nothing yet — a fresh form is not a wall of permissions copy

2 · Property manager — the default role, once an address is typed

Typing an address is one of the two ways to touch a row, and it is the one that matters most: the default role is now being handed to a real person. Both halves render — what they can do, and the part an admin is actually checking, what they can't. Every line is a quote from a gate that ships today: the fail-closed entity matrix, the invite ladder, and building scope.

Look at the inset and the glyph alignment: the check and cross are flexShrink: 0 against sentences that wrap, and the body ink is --color-text-muted (5.34:1) rather than the --color-text-mid the rest of the step uses, which globals.css measures at 3.98:1 and calls a knowing AA failure at 12px.

Asserted in the captured DOMWhat they can do · Run the day to day: leasing, maintenance, collections, residents and vendors. · Make somebody an organization admin.. The heading, a can-line and a cannot-line of the DEFAULT role, in the state the screenshot shows.

Property manager — the default role, once an address is typed

3 · Leasing agent — a different role, a different card

Picking a role is the other way to touch a row. “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, so every action is denied, not just editing. The same role's list says “change a setting” rather than “open settings”, because it does hold settings: READ — a distinction the copy draws on purpose, and differently again for Maintenance.

Asserted in the captured DOMRun leasing end to end: prospects, tours and renewals. · Open maintenance or vendors at all.. The LEASING AGENT card, after a pick — not the default role's.

Leasing agent — a different role, a different card

4 · The phone width — the card under the select, not beside it

.ob-row-grid collapses the row to one column at ≤640px. The card sits under the select it explains at both widths, which is why it is a sibling of the row grid rather than a fourth cell inside it.

Asserted in the captured DOMWhat they can do · Make somebody an organization admin.

The phone width — the card under the select, not beside it

Captured anonymously, on purpose

Neither identity this tool signs in as can reach the wizard: the smoke account is platform_admin, which the wizard layout redirects to /dashboard, and the seeded non-staff identity is already onboarded, which redirects too. A local dev server serves the step unauthenticated (middleware.ts short-circuits outside production, and the layout runs its redirects only when a session exists), so 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.

PropFlow Docs