Feature docs

Analytics

PRESCRIPTIVE — design-ahead of the app

Sales Analytics answers a manager's four questions: Are we on pace? Which rep needs me? Which lead is about to be lost? What did the AI do vs my people?

It is a coaching instrument, not a bookkeeping report. The page evolves the shipped Analytics tab — a four-tile clickable hero (Sold · Unresponded · Untouched · Total Touchpoints) at the top, the Team Accountability table as the centerpiece, the Unresponded queue for customers waiting on a reply, a Reports menu in the page header carrying the seeded standards plus whatever we authored for that store, and an honest human/AI split running through every number.

Listen to this page
0:00/9:25

Rulings ledger

DateRuling
07-10AI = one combined bucket — automation-flagged sends UNION the DAISI actor; one "AI" label, never blended into human rows or totals.
07-10Black hole is strict + immediate — no open task AND no future appointment; an automation enrollment is NOT follow-up; no grace period.
07-10Targets = New / Used only — Fleet excluded; targets come from dealership Settings; no targets → the empty state, never fake numbers.
07-10Pipeline bars kept — WITH the mandatory coaching empty state (never looks broken).
07-10No leaderboards — threshold callouts only; values get color, never rows, never ranks.
07-10Behaviors grouped before outcomes — the column-group band order is fixed.
07-10Accountability table sits ABOVE the cards (ruling 7).
07-10DAISI row pinned bottom — ruled off from humans, muted identity, honest numbers.
07-10"Last Active" naming — new metric from dealerjourney MAX(datetime) per dealer; presence dot = activity ≤15m, not online status.
07-10Evolution law — build on top of today's Analytics page; no restyling of the shipped gospel modules.
07-29No Follow-Up RETIRED, replaced by Unresponded (inbound with no reply since) — tasks-and-appointments never described what a rep actually owes a waiting customer.
07-29Inbound calls count MISSED only. Answered calls leave no reply row and were roughly half the flagged set at one store as pure artifact.
07-29The AI cut reuses the existing AI Included/Excluded toggle rather than a new control — which makes the excludeAi dashboard parameter a hard prerequisite (design-only today).
07-29Automation and drip sends never count as a reply; a queued scheduled message does not, a fired one does.
07-29Opted-out/STOP repliers and Closed/Bad status are excluded from Unresponded.
07-29Computed from the customer timeline, never from the respondedAt stamp.
07-29The Unresponded tile is always range-bounded.
08-03Reports live in the page header, not inside a data card — navigation never lives in a data card; a card's controls act on that card.
08-03Header order is scope, then AI, then destination — Team/Mine | AI | Reports, with the date range and Filters on the right.
08-03Dealers get no report builder. Definitions are authored in the launch portal and carry a scope of either the whole tenant or specific users; the only dealer-facing knob is the date range.
08-03The four Activity reports are seeded standards in the Reports menu.
07-30Two roles, one table. BDC and Sales are stacked sections inside the single accountability card — same range, filters and sort. Not two cards, not a role filter: the comparison across the floor is the point.
08-04BDC outcome columns are Appts Created and Appts Shown. Appts Created counts the appointments that actor created (attribution: the creator; anchored on the created date). Appts Shown counts appointments scheduled in the range and marked complete, credited to the customer's assigned dealer (anchored on the scheduled date) — so it is shared with the sales band, identical definition, not role-specific. The two are independently attributed and never form a ratio or funnel; marked-complete means Appts Shown undercounts, so no show rate.
07-30Shared columns, role-specific columns. Calls, Texts, Emails, Tasks and Avg Response appear for both roles; Appts Shown is shared by both bands with one definition, while the other outcome differs — Appts Created for BDC, Sold for Sales — each section showing its own set rather than padding both with blanks.
07-30Managers and role-less users are excluded from the accountability table. It measures the people working leads.
07-30A role is a marker on the user, not their job title. Job title is free text and display only; the structured role marker drives the split.
07-30Unresponded — nobody replied, human or AI. A reply from the AI clears it exactly as a human reply does; the metric measures neglect, not staffing model.
07-30A blast is not a reply. Automation and drip sends never clear Unresponded. Neither does a queued scheduled message — only one that actually went out.
07-30Answered calls are out, missed calls are in. An answered inbound call leaves no reply record, so it cannot be judged; a missed one is the clearest possible unanswered signal.
07-30Compliance is not neglect. Opted-out customers and STOP replies never appear in Unresponded. Closed and Bad statuses are excluded too.
07-30Time-bounded, always. Unresponded follows the page's date range. Unbounded it is an eleven-year graveyard: 242,000 customers platform-wide, 99.6% of them with nothing unanswered inside three days.
07-30The AI toggle is the human-diligence view. With AI included, a DAISI answer counts as handled. Flipping to AI excluded surfaces the customers only the AI ever answered — that is the intended way to ask “are my people engaging?”, and it is why no second tile is needed.
07-30One definition, three surfaces. The Unresponded tile, the Contacts view it opens, and the Unresponded filter never diverge.
07-11Hero = four clickable metrics — Sold / Unresponded / Untouched / Total Touchpoints; the Pipeline bar removed (duplicated the Lead Funnel card); pacing shelved pending the targets model.
07-13Header rework — the Analytics title row is dropped; the header is the shared root-header grammar (quick-filter chips + date chip + Filters button); the location dropdown is retired to the Filters panel; panel filter set = Included Users + Locations (ship today) with Lead Source / Traffic Source / Inventory as prescriptive additions.
07-13Filter panel rebuilt to native FilterPageForm grammar (extracted from the Contacts/dashboard filter source): date field + 2-col shortcut grid, Included Users assignment selector w/ user chips, Lead/Traffic Source as chip-trigger fields w/ search overlays, Inventory as multiselect chips; header date chip opens the Filters panel (caret removed).
07-13Filter panel production tightening — panel chrome (Apply Filters header action + gear + Clear All/Apply footer), dual-month custom-range popover, chip-trigger selected state = blue outline + blue-02 fill + trailing pencil edit (reusable law); panel now opens from the date chip and Filters button in the screen mocks.
07-13Atomic audit — multiselect chips = gray-06 fill unselected / blue-02 + x selected (atom-level, cascades); filter section headers = gray-07 band + gray-06 underline w/ container-title style; panel pushes content (split-view), never covers; all-caps buttons RETIRED DS-wide (Title Case); page body = systemWhite token.
07-13Atomic sweep — info glyph fa-regular DS-wide + info seats next to its label (removed .sb-stat far-right margin + section-title flex spacers); mobile page body = systemWhite + canonical .sb-mh-tabs band; mobile Team Accountability now the horizontal-scroll .sb-acct table (card stack + .sb-acct-card atom retired from the screen); dead rules (grpband, .sb-stat .k) and local style forks removed; .val.alert, .fbar/.vals tokens, merged .sb-locgrid/.sb-mschips.
07-14Table styling — column-header row = gray-07, 48px, nowrap+ellipsis (never wraps); Reports controls row also gray-07 so the whole top block is gray-07 above the gray-06 "All" totals; accountability avatars s24→s20, rows 54px; Last Active is relative-only ("1d ago", not "Yesterday").
07-14Accountability avatars removed — rep rows are now index + name/role only (the s20/s24 avatars distorted into ovals and added no value); the Daisi row keeps its name + AI chip, no avatar. Dead .avwrap/.presence/.ai-av CSS retired. Compact/density toggle standardized on fa-grip-lines.
07-14Feature Header Inventory — new comp-header-inventory page logs every feature's desktop + mobile header in one place (shared chrome factored out; FULL vs COMPACT mobile variants; desktop↔mobile parity). Defines the Tasks header (All/Mine · All/Overdue/Due-Today status filter · Compact · Filters · +New Task; no date-range — status is the date cut) and the Calendar header (All/Mine · Unresolved · Compact · Filters · +New Appointment; date navigated via the grid) ahead of building those screens.
07-14Header controls refinement — new control-group divider atom .sb-mseldiv ([assignment] | [status] | [Compact] | [actions]); primary Add keeps its text label on mobile compact rows; Leads Add restored (desktop + mobile); overdue/unresolved status use the warning triangle (fa-triangle-exclamation); Tasks status is a two-state toggle (All ↔ Overdue), "Due Today" removed; inventory-page mobile frames de-contained (squared, no shadow).
07-14Header Controls — States & Behavior — new comp-header-controls-states page: the canonical interaction-states + behavior spec for the .sb-msel header control family (base states · single-select group · two-state toggle · smart-view + count · density toggle · multi-select chips), with LIVE clickable demos. The Feature Header Inventory (composition) now links out to it (behavior) instead of duplicating state notes.
07-14Shared sb-controls.js + data-role convention — header-control interactivity is now provided by one shared script (included like sb-tooltip.js) wired by a data-role convention (single|toggle|two-state; data-group for a single-select set); the states page is script-driven (no bespoke JS), and feature screens opt in by adding the attributes + the include.

Anatomy map

Showroom (source)The live Showroom strip instances these atoms — showroom owns the grammar. ReportsThe header control, the menu, the fixed-report template, and how a report gets made. Team AccountabilityThe centerpiece table — anatomy, thresholds, AI row, data contract. AI splitThe Exclude AI quick-filter chip (form provisional) and the "humans only" scope annotation. UnrespondedThe stat, drilldown, and Contacts queue — not yet redrawn for Unresponded. Pacing + PipelineThe monthly-target progress module and the stacked pipeline distribution bar — atoms awaiting the targets model. Filter rowThe Analytics header variant — Source chip + Exclude AI, collapse priority. Coaching drillThe per-rep page a manager opens from an accountability row. Reports + Activity LogCustomTable grammar, Reports controls, the relocated Activity Log.

The accountability table

One table answering "is my team doing the work, and is it turning into sales" — its anatomy, thresholds, AI row, and contract.

Two roles, one table. The split uses the dealers roundRobinRoles marker — sales_person vs bdc_agent — excluding managers and role-less users. BDC and Sales are stacked sections inside the single accountability card: same date range, same filters, same sort. Not two cards, and not a role filter: the comparison across the floor is the point. Calls, Texts, Emails, Tasks and Avg Response mean the same thing for both roles and appear for both. Appts Shown is likewise shared, with one definition in both bands — appointments scheduled in the range and marked complete, credited to the customer’s assigned dealer. What differs per role is the other outcome column: Appts Created for BDC (attribution: the creator) and Sold for Sales, so each section shows its own set rather than padding both with blanks. A role is a structured marker on the user, not their job title; job title is free text and display only.

Honestly: only 5 of 107 dealerships have anyone marked bdc_agent today, and the field is gated behind auto-assignment — so it reads as never-configured rather than empty. The ruling is to ship the split anyway because the feature is rolling out.

Appointment attribution caveat. There is no creator column: attribution needs the notifications proxy at ~90% coverage, ~30% of “dealer” creates are actually DAISI, 31% of appointments are customer self-scheduled with no rep at all, and 39% sit unresolved via a silent hourly sweep — so do not ship a bare show-rate percentage.

1 · Anatomy — section card · rep cell · aggregate row · default sort
OPEN QUESTION: data-point mix under review — Taylor.
Team Accountability
Rep Tasks Today Overdue Calls Texts Emails Avg Response Appts Shown Sold Last Active
All (team)3610871696415m2414
1Sonya WestClient Advisor
6143298m644m ago
2Jake MartinSalesperson
42921522m5338m ago
3Karla SellersSalesperson
511181212m432m ago
4Devon BrooksBDC
812241156m3212m ago
5Tara McCannBDC
718361114m211h ago
6Marcus LeeFleet Manager
234631h 12m21Yesterday 6:45pm
7Priya NairClient Advisor
3712831m13h ago
8Shane DusangSalesperson
142311Tuesday 2:10pm
Daisi (AI) AI
2201841m1m ago
Totals are humans; AI reported separately.
This is also the zero-config default state whenever no bdc_agent exists on the roster. Section card (FIDELITY-3): gray-07 TITLE BAR ("Team Accountability" 14px semibold + info icon, r5 top) → WHITE body carrying the table → gray-07 FOOTER BAR (r5 bottom) with the humans/AI microtext. This IS the sales column set — behavior columns (Tasks Today → Avg Response) then sales outcomes (Appts Shown, Sold) then Last Active. Showing an appointment is a sales-role outcome whether or not a BDC set it, so a BDC band is purely additive: it appears above when the roster carries a bdc_agent and never changes how sales is measured. No vertical column lines (production tables have ONLY horizontal separators). Data rows = WHITE token bg; "All (team)" row gray-06; header row transparent-on-white. Rep cell: index box + name (semiBoldParagraph gray-00) + role subtitle (mediumIndicator gray-03) — no avatar (Taylor: the small avatars distorted into ovals and added no value; removed). Default sort = Sold descending (circled active glyph). Whole row = one tap target → the rep coaching drilldown. Exact geometry (FIDELITY-2A): 1px gray-06 outer border r5; header h40 (13px bold gray-02); rows FLUSH with 1px gray-06 separators, min content height 48; each rep row leads with a 24×24 INDEX BOX (12px medium gray-02), cell pad-left 8, 8px gaps; metric headers AND values CENTERED 13px bold with trailing 32px sort boxes (hover/active only) + invisible leading boxes; the AI row keeps the geometry with an em-dash index box.
1b · Role bands — BDC + Sales (when a BDC exists)
Team Accountability
BDC3 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts CreatedAppts ShownLast Active
All (BDC)21358104349m4118
1Devon BrooksBDC
812241156m18812m ago
2Tara McCannBDC
718361114m1461h ago
3Renee OkaforBDC Agent
621827818m9426m ago
Sales5 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts ShownSoldLast Active
All (sales)18940803017m3312
1Sonya WestClient Advisor
6143298m1144m ago
2Jake MartinSalesperson
42921522m9338m ago
3Karla SellersSalesperson
511181212m832m ago
4Marcus LeeFleet Manager
234631h 12m311d ago
5Shane DusangSalesperson
14231213d ago
Daisi (AI) AI
2201841m1m ago
Totals are humans; AI reported separately.
Zero config. Everyone carries the sales_person default via roundRobinRoles; the BDC band appears only when the roster says at least one person is marked bdc_agent — most stores today have nobody marked, and render the single table in specimen 1. One grid, two headers: both bands live in ONE section card on identical column tracks, and each band’s own header row carries the role label (role name + rep count in the row-key cell, no chevron — it is a static subgroup label, not a picker) so no extra full-width divider row is needed. Appts Shown is the SAME metric with the SAME definition in both bands — a shared column, not a role-specific one: appointments scheduled inside the range, marked complete, credited to the customer's assigned dealer. What actually differs per role is the OTHER outcome column: Appts Created for BDC (the appointments that actor created, credited to the creator, anchored on the created date) and Sold for Sales. The two BDC columns do not chain. Created is creator-attributed on a created-date anchor; Shown is assignment-attributed on a scheduled-date anchor — so Shown is not a subset of Created and the pair is never a ratio or a funnel. A BDC rep who books an appointment for a customer assigned to a salesperson sees it in that salesperson's Appts Shown, never their own: intended, because Shown measures who owned the customer when they walked in. BDC sits on top and Sales below; each band opens with its own aggregate row and there is no whole-floor total. Each band sorts by its final outcome column descending. Counts, never a percent: because Shown requires marked-complete, the 39% of appointments left unresolved by the silent hourly sweep never count — Appts Shown undercounts, so no show-rate percentage may be derived from it. Membership: a bdc_agent marking beats the sales_person default everyone carries, so dual-role people land in BDC; you appear if you were assigned a lead OR logged any activity in range — a GM who works no leads vanishes naturally, while a rep with assignments and zero activity still shows as the zero row this table exists to catch. Daisi appears once per card after the Sales band, ruled off as always, and is governed by the AI Included/Excluded toggle.
2 · Threshold cells — values get color, never rows
Overdue: red-01 when >0 · em-dash gray-04 at zero. Avg Response: default fg below 15m · orange-01 15–60m · red-01 above 60m (the grounded AFT bands — calibrated on live first-touch distributions). Last Active: relative time boldTiny; turns orange-01 when older than 24h (e.g. "Yesterday 6:45pm"). Values only get color — never whole rows. Zero-data cells render an em-dash, not zero-noise.
3 · Pinned AI row
Bottom-pinned, visually ruled off from humans: gray-07 fill + a 2px gray-06 top rule; name "Daisi (AI)" + an "AI" RoundedText capsule; values in the SAME columns but the identity text is gray-02 — muted identity, honest numbers. The AI row is OUTSIDE the "All (team)" totals; the microtext under the table states it: totals are humans; AI reported separately. AI bucket (ruling 1): automation-flagged sends UNION the DAISI dealer actor — one bucket, one "AI" label.
7 · Data contract — column → backend metric id
// Column → metric id (POST /v2/dashboard/sales + dealerjourney) Tasks Today = TasksTodo Overdue = TasksOverdue Calls = OutboundCalls Texts = OutboundTexts Emails = OutboundEmails Avg Response = AvgResponseTime // MEDIAN — label it honestly wherever surfaced Appts Shown = AppointmentsShown // SHARED by both bands, identical definition: // appointments SCHEDULED inside the range, MARKED COMPLETE, // credited to the customer's ASSIGNED dealer (not the creator). // Date anchor: the appointment's scheduled date. Appts Created = AppointmentsCreated // BDC band only: // appointments THAT ACTOR CREATED — attribution is the CREATOR. // Date anchor: appointments created inside the range. // The two are INDEPENDENTLY ATTRIBUTED over DIFFERENT date anchors — Shown is NOT a subset of // Created. Never present them as a ratio, a funnel, or a show rate. Sold = DealsClosedWon Last Active = NEW metric — MAX(datetime) per dealer from dealerjourney // ROLE MARKER — the band split dealers."roundRobinRoles" text[] NOT NULL DEFAULT ARRAY['sales_person'] // bdc_agent BEATS the sales_person default everyone carries — dual-role people land in BDC. // A role is a marker on the USER, not their job title: the free-text job title under each name is // display only and does NOT drive the split (specimen 1 shows reps whose title reads "BDC" in a // store with no bdc_agent marker — that is the point). // BAND MEMBERSHIP — a rep appears if they were ASSIGNED A LEAD or LOGGED ANY ACTIVITY in the range. // A manager who works no leads drops out naturally; a rep with assignments and zero activity still // shows as the zero row this table exists to catch. There is no clean manager field to exclude on. // APPOINTMENT ATTRIBUTION — no creator column exists. Attribution needs the customernotifications // proxy at ~90% coverage; ~30% of "dealer" creates are actually DAISI; ~31% of appointments are // customer self-scheduled with no rep at all; ~39% sit unresolved via a silent hourly sweep. // Therefore ship COUNTS, never a bare show-rate percentage. And because Appts Shown requires // MARKED COMPLETE, the appointments left unresolved by that sweep never count — Appts Shown // UNDERCOUNTS by construction, so no show-rate percentage may be derived from it. // AI bucket (ruling 1): automation-flagged sends UNION the DAISI dealer actor // — one bucket, one "AI" label; never blended into human rows or the All (team) totals. // Row example { "dealerId": "dlr_8842", "name": "Sonya West", "role": "Client Advisor", "TasksTodo": 6, "TasksOverdue": 0, "OutboundCalls": 14, "OutboundTexts": 32, "OutboundEmails": 9, "AvgResponseTime": 480, // seconds, median "AppointmentsShown": 6, "AppointmentsCreated": 11, "DealsClosedWon": 4, "roundRobinRoles": ["sales_person"], "lastActive": "2026-07-10T13:52:00Z", // MAX(datetime) — drives the Last Active cell "isAi": false }
8 · Rules — engineering checklist
No leaderboards or rank celebration — threshold callouts only.
Behaviors before outcomes — behavior columns run first, then the role's outcomes, then Last Active.
Role bands are the one group-band exception — the BDC band appears only when a bdc_agent exists on the roster; a store without one renders the single sales table.
Both bands use identical column tracks — Appts Shown is shared (same definition, assigned-dealer attributed); only the other outcome differs (BDC: Appts Created, creator-attributed · Sales: Sold). The two BDC outcomes never form a ratio.
Each band carries its own aggregate row and sorts by its own final outcome column.
No whole-floor total row — summing different column sets is meaningless.
The Daisi row stays ONE row for the whole card, after the last band.
Every number drills down (the R0 drilldown grammar — read-only rows).
Medians labeled as medians — AvgResponseTime is a median; say so.
AI labeled, never blended — outside totals, ruled off, "AI" capsule.
Zero-data columns render an em-dash, not zero-noise.
Values get threshold color — never whole rows.
Rep cell = index + name + role — no avatar (Taylor: the small avatars distorted, removed).
The table is a CustomTable instance — extend .sb-table, never fork it.

The AI split

How every number on the page separates human effort from the machine's.

4 · Exclude AI — quick-filter CHIP (FIDELITY-4: the CustomSwitch form is RETIRED; control form PROVISIONAL — Taylor may want something else)
OFF (default) — the AI row is visible, pinned bottom.
Touchpoints
41
humans only
ON — the AI row is hidden AND every stat value carries a small "humans only" scope annotation (shown here on a StatsCard) so scoped numbers are never mistaken for totals. Control form is PROVISIONAL — the chip replaces the retired CustomSwitch; Taylor may rule a different form.

Unresponded

The assembled analytics screens and the element spec page embedded below have not been redrawn for Unresponded yet.

The tile that answers “who is waiting on us right now” — customers who reached out and have not heard back.

Definition. A customer who sent an inbound text, email, or missed call inside the selected date range and has had no qualifying reply since. Clicking the tile opens a Contacts view sorted longest-wait-first. Tooltip copy: “Customers who reached out and haven't heard back. Counts inbound texts, emails and missed calls in this range with no reply since.”

Counts as inbound: sms/send, email/send, call/send-fail (missed). An answered inbound call is excluded — it leaves no reply row, so it would read as neglect purely as an artifact. Counts as a reply: any outbound human or DAISI message. Not a reply: automation and drip sends, and scheduled messages still queued (one that actually fired does count). Excluded: opted-out customers and STOP repliers (you must not reply to them), and customers at Closed or Bad status.

Measured from the timeline, not the respondedAt stamp. respondedAt is written by a single async, forward-only writer that clears a customer's entire historical backlog on one reply, fires on both direction branches for calls, and silently under-writes per tenant — one live dealership stamps it on 0.4% of inbound texts while others hit 78–96%. The timeline is immutable and self-healing.

Range-bounded by construction. Unbounded, this is 242k customers back to 2015; 99.6% have nothing unanswered inside three days. The tile always reads the selected range.

AI split. The tile obeys the existing AI Included / AI Excluded toggle. AI-included counts a DAISI reply as handled; AI-excluded surfaces customers only the AI touched — the human-diligence view.

Open questions. Should AI-Excluded be the default for this tile? AI-included flatters heavy-DAISI stores — a 13× spread between two live tenants. Is “Unresponded” the right word, or “Awaiting Reply”? Should a manually logged call count as a reply? Should archived customers be excluded?

1 · Definition
A black-hole lead = an ACTIVE (non-archived) customer with NO open task AND no future appointment. An active automation enrollment does NOT count as follow-up — ruled: a human never has to look otherwise. Flagged immediately — no grace period. One definition, every surface.
2 · The StatsCard instance — alert semantics
Locked StatsCard grammar: solid info icon always present. Value renders red-01 when >0, em-dash gray-04 at zero (same alert semantics as Untouched). Delta uses invertColors — down = good = green. Third specimen: the "humans only" scope sub-line shown when Exclude AI is on. Tap → the drilldown below.
3 · The queue — read-only drilldown · Contacts smart view
Drilldown — read-only customer list
No Follow-Up
Tamika JeffersonNo Follow-up6 days ago
Created 05/31/17Customer
Robert CookNo Follow-up9 days ago
Created 06/12/26Customer
The R0 drilldown grammar: app bar = back + title only; whole row = one tap target; no per-row actions. Each customer row carries a red "No Follow-up" RoundedText capsule beside its status chip. Drilldown entity = Customer.
Contacts smart view — the queue lives in the views rail
Priya NairNo Follow-up4 days ago
Created 07/02/26Customer
2024 Kia Telluride
Marcus LeeNo Follow-up12 days ago
Created 05/18/26Customer
2021 Honda Civic
The views rail (locked views-nav grammar): "No Follow Up" carries a red count pill. The list = locked customer-card instances wearing the same red capsule — the capsule travels with the customer everywhere the queue surfaces.
4 · Rules + data contract
// Definition as pseudo-logic — ONE definition, every surface isBlackHole(customer) = customer.status != "archived" // active customers only AND openTasks(customer) == 0 // no open task AND futureAppointments(customer) == 0 // no future appointment // NOTE: automation enrollment does NOT count as follow-up (ruled — // a human never has to look otherwise). Flagged immediately, no grace period. // Count metric id (NEW): NoFollowUp // Drilldown entity = Customer { "metric": "NoFollowUp", "value": 6, "drilldown": "customers" }
One definition everywhere — stat, drilldown, and smart view never diverge.
Automation enrollment ≠ follow-up — only an open task or a future appointment clears the flag.
Flagged immediately — no grace period.
Value red-01 when >0 · em-dash gray-04 at zero · invertColors (down = good).
The red capsule travels with the customer — same RoundedText everywhere.
Drilldown rows are READ-ONLY (R0 grammar) — the fix happens on the customer, not in the list.

Reports

The fixed reports a store can open from the page header — the control, its menu, the one view they all render through, and how a report comes into being.

1 · The control — a labeled chip in the pagehead, after a group divider
Closed — the resting state.
Standard reports
Built for Galleria BMW
Open. The chip lives in the header because these reports are destinations, not page content. The .sb-mseldiv before it marks it as a different class of control from the filters to its left — those act on the page you are looking at; this one takes you somewhere else. Navigation never lives inside a data card: a card's controls act on that card, and anything that leaves lives in the page chrome.
2 · The menu — two groups: seeded standards, then what we built for this store
Standard reports
Built for Galleria BMW
Every store gets the standard set at setup. The second group is authored by us server-side for that tenant — the concierge moment: the report with their weird three-table join carries their name. The four Activity reports are seeded standards in this menu. A menu scales cleanly from 1 to 20 entries, where a permanent shelf of chips would starve at two and overflow at twelve.
3 · The fixed-report template — one view every report renders through
Lease Maturity + Equity
CustomerVehicleLease EndPayoffEst. EquityAssigned
Marcus Lee2023 BMW 530i09/14/26$31,480$4,210Karla Sellers
Priya Nair2022 BMW X310/02/26$27,905$2,860Jenna Marsh
Devon Brooks2023 BMW X510/28/26$44,120−$1,940Karla Sellers
Rachel Rowen2022 BMW 330i11/09/26$24,660$5,375Taylor Bertrand
Alex Chen2023 BMW i412/01/26$38,240$1,105Jenna Marsh
5 rows
The date range is the only knob a dealer gets — no column picker, no builder, no save. The report definition (query, columns, default range) lives server-side per tenant, so shipping a new report is a config row rather than an app release. This is deliberately the opposite of the audience builder: flexibility moved from the dealer to us.
4 · States — a store with standards only · the template's empty range
Standard reports
Standards only — no bespoke group header at all.
Lease Maturity + Equity
No rows in this range
0 rows
Empty range — the date chip stays, because changing it is the fix.
A store with no bespoke reports shows one group and no second header — an empty "Built for" heading would advertise an absence. The template's empty state keeps its chrome so the dealer can widen the range without leaving.
5 · How a report gets made
Dealers never build reports. Authoring happens on our side, in the launch portal — the internal admin surface — where a report definition is captured: the query and its joins, the columns, the default date range, and the display name. Every report carries a scope. It can be published to the whole tenant, so everyone at that dealership finds it in their Reports menu, or to specific users, so a report built for one GM or one desk manager appears only for them. Whoever it is scoped to simply finds it in the menu — nothing tells the dealer whether a report is seeded, tenant-wide, or built for them personally. It is just their list. Because the definition lives in config rather than in the app, shipping a new report to one store — or to one person at one store — is a config change, not a release. The mechanism is deliberately not pinned down. Whether authoring is a form, a query builder, or a prompted agent inside the launch portal is an open question. What is settled is the output contract — a definition plus a scope — and that the dealer-side UI never changes to accommodate a new report.

The hero metrics

Four clickable tiles — Sold, Unresponded, Untouched, Total Touchpoints — each tapping to its view.

Live Showroom strip

Straight from a GSM interview at Galleria BMW: the one thing that would make her open Analytics instead of her DMS reports is a live read of the floor — who is here right now, which rep they're with, and how long they've been waiting. So the strip sits just under the hero, above Team Accountability.

It is an instance of the Showroom atoms, not a second showroom — .sb-shwm-ctn, the .sb-svisit rows, the duration legend, the .sb-rts road-to-sale chips, .sb-avgroup reps, and the .sb-dealrow vehicle of interest all come from comp-showroom-screen, which owns the grammar. Time-in-store keeps the showroom banding: under 2h neutral, 2h–4h warning, over 4h red. The five road-to-sale chips (Greet, Test Drive, Appraisal, Manager T.O., Credit App) surface her killer coaching case at a glance — a deal that reached Manager T.O. with Test Drive still unchecked.

The strip is a glance that hands off, never a place to act: the whole row is a click target → the Showroom view and the strip footer carries the canonical View All text button (the SectionActionTextButton), but Analytics never mutates a visit — no check-out, no editing, no toggling road-to-sale here.

Showroom3 Total< 2h2h - 4h> 4h
TB+2
1:20 pm2h 40mSales
GreetTest DriveAppraisalManager T.O.Credit App
2026 BMW X5 xDrive40i#4471902$74,900FinanceWorking
JM+2
3:05 pm0h 55mSales
GreetTest DriveAppraisalManager T.O.Credit App
2025 BMW 330i#4470310$48,200LeaseFresh
DB+2
11:10 am4h 50mSales
GreetTest DriveAppraisalManager T.O.Credit App
2026 BMW iX M60#4472558$112,300CashFinance

Pacing and pipeline

Built atoms held for the dealership targets model: pacing needs monthly New/Used targets to read against. Pipeline shape is carried by the Lead Funnel card.

1 · .sb-pacing — Monthly Target module · TWO rows: New + Used (Fleet EXCLUDED by ruling)
New38/ 45 targetPacing 47 (+2 vs target)
WTD 8 · last wk 6
Used21/ 50 targetPacing 42 (−58 vs target)
WTD 4 · last wk 9
Each row: uppercase boldTiny gray-02 label + sold-so-far big number (semiBoldHeading5 gray-00) + "/ NN target" (gray-03) + the .sb-goalbar (6px track gray-06, r3, fill colored by pace threshold) + a pace line (mediumIndicator, threshold-colored) + a WTD/MTD compare microline (gray-03). Tap a row → the Desk filtered to Closed for that department. Two rows only — New and Used; Fleet is excluded by ruling.
2 · Threshold grammar + states — on-pace / near / behind / loading
New40/ 45 targetPacing 48 (+3 vs target)
WTD 9 · last wk 7
New30/ 45 targetPacing 42 (−3 vs target)
WTD 6 · last wk 8
Used12/ 50 targetPacing 24 (−26 vs target)
WTD 2 · last wk 5
Threshold grammar: pacing projection behind target = red-01 · within 10% of pace = orange-01 · on/ahead = green-01 — the pace line AND the goalbar fill carry the same color, always together. Loading = shimmer placeholders (bar track stays, no fill). Pacing N = month-end projection at the current daily rate; the (±N vs target) delta speaks plainly.
3 · No-targets-set empty state — never fake numbers
No targets set Targets come from dealership Settings
When leadership hasn't entered monthly targets the module NEVER invents them — headline + microcopy + a "Set targets" text-button routing to Settings. No sample bars, no placeholder pacing.
4 · .sb-pipebar — pipeline distribution bar
Fresh 1.9K Working 848 Finance 331 Close 590
Working · 848 ← hover a segment = the chart tooltip with the count.
ONE horizontal stacked bar (10px, r3), segments proportional to deals-by-processingStatus: Fresh orange-01 · Working purple-01 · Finance blue-01 · Close green-01 (the semantic status hues — never an ordered palette). Legend beneath: hue dot + label + count (boldTiny); counts use the abbreviated pill format for big numbers. Tap a segment → the Desk filtered to that status.
5 · Empty / low-adoption state — coaches adoption, never looks broken
Pipeline lives on your Leads board — start moving deals to see it here
MANDATORY: at zero data the bar renders solid gray-06 with centered coaching microcopy + an "Open Leads" text-button. It coaches adoption, never looks broken — the zero-data law: no empty rectangles, no fake distributions.
6 · Data contract
// PACING — requires the NEW targets model (no backend yet — PRESCRIPTIVE): // dealership Settings · per month · per department (New / Used) · entered by leadership. { "targets": { "month": "2026-07", "new": { "target": 45, "sold": 38, "pacing": 47, "wtd": 8, "lastWtd": 6 }, "used": { "target": 50, "sold": 21, "pacing": 42, "wtd": 4, "lastWtd": 9 } // Fleet EXCLUDED by ruling. targets == null → the no-targets empty state (never fake numbers). } } // PIPEBAR — existing deals processingStatus counts (no new backend): { "pipeline": { "Fresh": 1912, "Working": 848, "Finance": 331, "Close": 590 } // all zero → the coaching empty state; segment tap → Desk filtered by that status. }

The coaching drill

Tap a rep row and get everything a coaching conversation needs — one rep, one page.

Jake Martin
JM
Jake Martin
Salesperson · Last active 38m ago
Personal funnel
41331163
Assigned Contacted Appts Set Shown Sold
Activity trend
1260
6/106/196/287/7
Calls Texts Emails
Road to sale
Test drive before deskingcloses 2.1× more
Proposal within 48h of first visitcloses 1.6× more
Recent activity
Devon Brooks2 minutes ago
Created 07/01/26Customer
Send lease quote
Due 3:30 pm
Shane Dusang
Jul 12, 10:00 am · Sales Confirmed
Jordan Avery
Personal funnel: tile-row funnel instance (exact FIDELITY-2A grammar — equal-width tiles, value strip + legend strip, single group / no spacer, semantic sequence ramp Assigned orange-01 → Contacted purple-01 → Appts Set indigo-01 → Shown blue-01 → Sold green-01). Every bar drills down to that rep's records (Assigned → their leads · Sold → their closed deals). Same Jake Martin numbers as comp-accountability-states — consistent-data law.
Road to sale: plain-fact insight rows (MultiUseItemView row instances) — title + right-aligned fact ("closes 2.1× more"). The numbers speak: NO directional words, NO arrows (terminology law). Store-level correlations, not per-rep judgments.
Rules: entry = tapping a rep row in the Team Accountability table (whole row is the target). Every number drills down: scorecards → the R0 read-only drilldown grammar; funnel bars → filtered record lists; recent-activity rows are read-only (no per-row actions). Thresholds follow the DS bands (Overdue red >0 · Avg Response 15m/60m). No leaderboards — one rep, coaching context only. PRESCRIPTIVE — instanced from statscard · charts · drilldown · menus grammars.

The page

The assembled desktop composition and its mobile counterpart — same data, same modules, two idioms.

Team Accountability
BDC3 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts CreatedAppts ShownLast Active
All (BDC)21358104349m4118
1Devon BrooksBDC
812241156m18812m ago
2Tara McCannBDC
718361114m1461h ago
3Renee OkaforBDC Agent
621827818m9426m ago
Sales5 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts ShownSoldLast Active
All (sales)15729653018m3312
1Sonya WestClient Advisor
6143298m1144m ago
2Jake MartinSalesperson
42921522m9338m ago
3Karla SellersSalesperson
511181212m832m ago
4Marcus LeeFleet Manager
234631h 12m311d ago
5Priya NairClient Advisor
3712831m213h ago
Daisi (AI) AI
2201841m1m ago
Totals are humans; AI reported separately.
Appt. Funnel
423324135
Set Confirmed Shown Missed Declined
Lead Funnel
1.9K84833159096
Fresh Working Finance Close Archive
Inbound Comm.
60300
6/307/17/27/37/47/5
Calls Texts Emails
Outbound Comm.
60300
6/307/17/27/37/47/5
Calls Texts Emails
Reports
By User New Leads Assigned Appointments Created Appointments Shown Deals Closed Won Win Rate
All9642241458%
1Sonya West28149444%
2Jake Martin24116350%
3Karla Sellers22105360%
4Devon Brooks2274250%
Team Accountability
BDC3 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts CreatedAppts ShownLast Active
All (BDC)21358104349m4118
1Devon BrooksBDC
812241156m18812m ago
2Tara McCannBDC
718361114m1461h ago
3Renee OkaforBDC Agent
621827818m9426m ago
Sales5 repsTasks TodayOverdueCallsTextsEmailsAvg ResponseAppts ShownSoldLast Active
All (sales)15729653018m3312
1Sonya WestClient Advisor
6143298m1144m ago
2Jake MartinSalesperson
42921522m9338m ago
3Karla SellersSalesperson
511181212m832m ago
4Marcus LeeFleet Manager
234631h 12m311d ago
5Priya NairClient Advisor
3712831m213h ago
Daisi (AI) AI
2201841m1m ago
Totals are humans; AI reported separately.
Appt. Funnel
423324135
Set Confirmed Shown Missed Declined
Lead Funnel
1.9K84833159096
Fresh Working Finance Close Archive
Inbound Comm.
60300
6/307/17/27/37/47/5
Calls Texts Emails
Outbound Comm.
60300
6/307/17/27/37/47/5
Calls Texts Emails
Reports
By User New Leads AssignedAppointments CreatedAppointments Shown Deals Closed Won Win Rate
All9642241458%
1Sonya West28149444%
2Jake Martin24116350%
3Karla Sellers22105360%

Table chrome

How the shared .sb-table reads on the Analytics tables (accountability + Reports).

Accountability thresholds PROPOSED — pending Taylor

Status coloring for the accountability value cells (values only get color, never whole rows). Grounded in the 14-day inbound-response distribution: median 6.1m, p75 21.7m, 61% respond within 15m, 18% take over 60m.

The standard Activity reports

All Activity, Call Activity, Text Activity and Email Activity are four of the seeded standard reports every dealership gets at setup. They sit in the header Reports menu under “Standard reports”, alongside Team Performance. Each opens its activity list through the fixed-report template; Export CSV downloads the rows in the selected range.

What each number means

Every number on this page carries a hover tooltip. This is the dictionary, and it exists because a metric a manager cannot define is a metric he will not trust.

MetricTooltip (what the user reads)What it actually measures
Sold“Vehicles sold in the selected period.”Deals that entered the Closed stage inside the range, credited to the customer's assigned rep. A deal reopened and reclosed counts twice.
Unresponded“Customers who reached out during this period and still haven't heard back — from a person or from the AI. Click to open them in Contacts, longest wait first.”See the Unresponded section.
Untouched“New leads nobody has contacted yet.”Leads created in the range with zero outbound messages since — email, text or call.
Outbound Touches“Every outbound call, text and email your team sent.”The sum of outbound calls, texts and emails in the range. Currently labelled Total Touchpoints, which collides with a report column that also counts notes.
Open Tasks“Tasks still to do.”Open to-do tasks touched inside the range. Currently labelled “Tasks Today”, which is neither today-scoped nor due-date-based.
Overdue“Tasks past their due date.”Open tasks whose due date has passed as of now — always as-of-today, even when looking at a historical range.
Calls“Outbound call attempts, including ones that didn't connect.”Outbound call events plus manually logged phone calls.
Texts / Emails“Outbound texts (emails) sent by this person.”Outbound message events by that rep. The communication chart on the same page counts a different set, including automation — the two numbers are not the same population.
Avg Response“Median time to reply to a customer's text or email. Calls aren't counted.”A median, not an average, over inbound texts and emails, credited to the customer's assigned rep rather than whoever actually replied.
Sold (accountability column)“Deals closed in the selected period.”Same as the hero Sold, per rep. Currently labelled “Sold Today” on the screens even though it follows the range.
Last Active“When this person last used the CRM.”The rep's most recent CRM activity. Goes silently blank for long-idle users because the underlying history is pruned.
Appts Created“Appointments this person booked.”Appointments that actor created — attribution is the creator, anchored on the created date. BDC band only. Not comparable to Appts Shown: different attribution, different anchor.
Appts Shown“Appointments that actually happened for this person's customers.”Appointments scheduled inside the range and marked complete, credited to the customer's assigned dealer rather than whoever booked it. Same definition in both bands. Because it requires marked-complete, the appointments left unresolved by the silent hourly sweep never count — it undercounts, so never derive a show rate from it.
Appointments: Scheduled“Every appointment on the calendar for this period.”All appointments whose date falls in the range, whatever became of them. Currently labelled “Set”, which collides with a report column meaning something narrower.
Appointments: Confirmed / Shown / Missed / Declined“Appointments the customer confirmed / showed up for / missed / cancelled.”The appointment's status. A large share of appointments are never resolved either way, so a bare show-rate percentage would be computed on an unreliable denominator.
Time in store“How long this guest has been here.”Elapsed time since check-in on an open showroom visit.

Names being corrected

Six relabels: Tasks Today → Open Tasks · Sold Today → Sold · Set → Scheduled · Avg Response split into First Response and Reply Time · Total Touchpoints → Outbound Touches · and the Lead Funnel stage names aligned to Desking and Financing.

Engineering scope

What is an instance of existing grammar vs genuinely new — plus the defects to fix while in the code.

Full decision ledger: autopilot/ANALYTICS_PLAN.md (repo). Composed per the Atomic documentation LAW — narrative + rulings ledger + anatomy map + @dsEmbed transclusions (build inlines them with provenance links) + eng scope notes; template of record: docs-leads.html.