Person card detail surface — the four-zone identity layout (HEADER / DECIDE / DEFINE / CONTEXT) fetched on demand when a row in PeopleListView is clicked. Mutations flow through detail_ops async helpers; every successful op re-fetches and notifies the parent list to refresh.
Declared but not yet dispatched — a real panel whose bound element types do not route to it at runtime today (often intentionally: an anchored popover, a sub-surface of another panel, or a future surface pending other work). See the panel's YAML for the specific reason. Amber means "still to do", not "broken".
Live
The real panel component, mounted here over fixture data — the same shipped chrome the workspace renders, not a sketch.
contact
AL
Avery Lindqvist
Head of Reconciliation
domainRidango
hourglassReady.
Sketch
Structural preview of the panel chrome. The browser panel renders the real BrowserChrome primitive at miniature scale; the other variants are CSS shape silhouettes. Either way the composition tree below is the authoritative description of what's inside.
Contactportal/src/canvas/people/detail.rspartial
States
emptyNo contact selected — modal hidden
loadingFetching contact details...
populatedFull contact loaded with all four zones rendered
confirm_deleteDelete confirmation dialog open (shared canvas ConfirmDialog)
load_errorCouldn't load contact — try again
Composition
Click any component name to jump to its component-page entry.
EntityDetailShellouterCentered modal shell (portal-side wrapper around ModalShell + a fixed four-zone CSS grid). Provides the focus trap, ESC-to-close, and the header/decide/define/context zone scaffolding.
ContactDetailHeaderchromeHEADER zone — IdentityChip(density=Header) + name/title/pronouns inline-edit + DNC banner + open-organization affordance. The chip's avatar / name / pronouns can each go live without leaving the zone.
IdentityChipidentityAvatar + name + role glyph composite. density=Header sizes for the header zone; the same chip at density=Compact appears in the address-book row that opened this modal.
InlineEditcontrolClick-to-edit name / title / pronouns. Saves through detail_ops::save_field on blur; on success bumps the parent list's row data via on_mutated.
DncBannerstatusVisible only when do_not_contact=true. Renders as a yellow banner above the header so messaging affordances downstream hide automatically.
ContactDetailDecidecontentDECIDE zone — the primary action surface. DNC toggle, status counters (open / blocked / done activities), and a contact-scoped activity timeline.
DncToggleButtoncontrolPrimary destructive-ish action — flips do_not_contact via detail_ops::toggle_dnc. Confirms inline (no second modal); state lives on contact, not on this component.
ActivityTimelinecontentScoped to the contact (TimelineScope::Contact). Lifted from the board package — same component, different scope. The live timeline shows every activity logged across pursuits this contact participates in.
ContactDetailDefinecontentDEFINE zone — the structured-data surface. Endpoints (emails / phones / messaging / socials / addresses), notes, and tags.
EndpointsSectioncontentPer-channel endpoint editors (one section per endpoint kind). Add / edit / remove flows through detail_endpoints::EndpointCallbacks; payload shape is contact-typed JSON, not free-form.
TagEditorcontrolComma-keyed tag chip input. detail_ops::add_tag and remove_tag drive mutations; the tag ring is element-agnostic — any contact-shaped element can wear this surface.
NotesFieldcontrolFree-text notes textarea. Saves through save_field('notes', ...) with debounced auto-save on blur.
ContactDetailContextchromeCONTEXT zone — secondary metadata strip + the destructive Delete action. Demoted to the bottom because it's reference data, not the primary edit surface.
KeyValuecontentStatic label/value rows for organization, discovery source, created_at / updated_at. Read-only from this surface — organization is a separate ops flow.
ConfirmDeleteButtoncontrolDelete affordance — opens the shared canvas ConfirmDialog via use_confirm_context().ask_danger, replacing a hand-rolled inline two-step strip. The delete itself runs through detail_ops::delete_contact and emits on_mutated.
Uses Components
Flat list of every component referenced — verifiable against the composition tree by the future generator audit.