# Search Console in the dashboard — mockup notes (spec 0.82, M1–M3)

Open [`index.html`](index.html). Every screen is static HTML in `screens/` built from the real tokens
(`dashboard/app/app.css`, copied into `assets/ui.css`) and the class lists of the real components (`SubNav`,
`StatTile`, `SectionCard`, `EmptyState`, `Badge`, `Dialog`, `LaunchChecklist`, `NeedsYouRail`, Analytics'
`RangePicker`/`TabbedBreakdown`, `SeoInspectorDialog`). PNGs in `shots/`, re-shot by `shoot.mjs` (also fails on
horizontal overflow or page errors; last run: none). URL switches: `?mobile=1 ?dark=1 ?plan=free ?role=member
?menu=1 ?tip=1 ?notes=0`.

Not done: shooting the real app beside the mockups. `tools/dashboard-harness` has never been brought up in this
worktree (it needs cf-platform installs and a seed), so the shell was rebuilt from the components' source instead.
A board-parity pass against the real SEO, Analytics and Overview screens is still owed before L3 starts.

## Performance page: three options

All three share the shell, the tabs-as-title row (**Health · Performance** `New`, using `SubNav`'s `suffix`), the
range control and `…` menu on the right of that row, the freshness line as the intro line, and the same data.

| | Shape | For | Against |
|---|---|---|---|
| **A** | The spec's order, everything full width. Pages to improve is a 7-column table (Luka's research layout). | The densest. Easy to compare numbers down a column. | The fix (the point of the card) gets squeezed into one column and wraps to 2–3 lines. On a phone the table needs a different layout, which means building it twice. |
| **B ★** | The spec's order, full width. Pages to improve is a list: page + kind badge, the fix as a sentence, the numbers on a muted line under it, one **Copy prompt** on the right. | The fix reads first, like Health › Needs attention rows (same row shape). Phone works with no second layout (the button drops under the text). Free is the same card with 3 rows and a footer line. | Taller: 5 rows ≈ 470px against ≈ 310px for A. |
| **C** | Totals as one joined strip (Overview's counter style), chart, then a main column (fixes + table) and a 20rem Indexing column like Overview's rail. | Fixes and indexing both visible on one 1440 screen. | Indexing gets cramped (verdict badges wrap). A rail on a data page competes with Overview's "Needs you" rail as a pattern. The joined strip differs from the Analytics tiles one tab away. Falls back to one column below lg anyway. |

**Recommendation: B.** It keeps the spec's order (the order Luka set), makes each row a sentence a site owner can act
on, uses one shape on desktop and phone, and on Free it shows less without a different layout. A is the fallback if
Luka wants numbers first. The table it uses is the Searches | Pages card, which already does that job lower down the
page. Mobile B: `shots/d2-option-b-390.png`.

## What each screen shows (and why)

- **A, not connected.** `EmptyState` with the Google mark, 3 small "what you get" cards, one yellow **Connect Google
  Search Console** (the page's main action, rule 3). Non-owner: "Ask a workspace owner to connect Google." plus
  **Copy link for an owner**, which copies the spec's `openUrl`. That button is my addition. Drop it if unwanted.
  F7 covers the disabled states (not published, password, certificate pending).
- **B, ownership notice.** Its own dialog, so its main action (Continue to Google) is yellow. The spec's sentence sits in
  a warning-tinted box. While Google opens: busy dots on the button, Cancel disabled (`editor-loading-ux`).
- **C, connecting.** Same header and progress bar as `LaunchChecklist`, same done/todo marks, busy dots on the running
  step. Two variants: we verify with the file (`?variant` default) or the site is already in the user's Search
  Console (`?variant=existing`).
- **D, connected.** Tiles: Clicks · Shown in search · Click rate · Avg. position, foot "↑ 18% vs the 28 days before"
  (Overview's counter wording). Chart: Analytics' two normalised series (clicks green solid, shown dashed gold, so
  colour isn't the only difference), the last 3 days hatched with a label and a tooltip line "Still coming in from
  Google". The `…` menu has who is connected and which site, so the page needs no separate "Connected as" row.
- **E, Free.** Tiles, chart, top 3 fixes, Indexing as a plain list of not-shown pages (no Google status, no Check on
  Google). One line at the foot of Pages to improve, copying the password-protection precedent ("…come with Core.
  **See workspace plan**"). There's no Searches | Pages card at all: no blur, no fake rows.
- **F, states.** No numbers yet · reconnect (owner/member) · moved workspace · address changed (info tone, no button, the
  checklist runs inline) · stale bundle (intro line changes) · two connect failures · three blocked reasons · numbers
  from the www pair.
- **G, disconnect.** Red confirm (`confirm()` danger tone). The checkbox only shows when no other site uses the
  account; it says so.
- **H, inspector.** **On Google** sits right under Search preview, so it shows without scrolling inside the 36rem
  dialog: one line of numbers, then the Google status + Check on Google, then top 5 searches. Checks moves below. Free:
  numbers + one line.
- **I, Overview.** See the spec issue below. I1 shows the checklist step before publish. I2 shows it as a Finish setup
  rail row after publish. I3 shows the Search card in the main column under Last 30 days. I4 shows the reconnect card.

## Things I dropped because the data can't back them

- **"data up to 7 Oct" on the Overview card.** The `search` slice / `gscsum:` has `at`, not `dataThrough`, so the card
  says "updated 6 h ago". If we want the date, add `dataThrough` to `gscsum:` (one field).
- **"42 pages handed to Google"** in the connecting checklist. The binding stores only `sitemap.submittedAt`. The count
  appears in the Indexing card instead, where it comes from `sitemaps.get`.
- **A chart on the Overview Search card.** The slice has no series (0 extra requests is a spec rule).
- **Everything Z-2 deferred:** country/device filters, 16-month range, publish markers on the chart, "Searches with no
  matching page", the Opportunities tab, Test new title, AI visibility. Also VERSIONS S13's blurred previews (the brief
  says no fake data) and S12's Analytics › Sources link (not in spec § 6).
- **"Brief agent" as a second button label.** Every row is **Copy prompt** (the existing `rules.copyPrompt.short`, full
  label in the tooltip). Five identical "Copy prompt for your AI" buttons read as noise.

## Spec issues found while drawing (please fix in 0.82 § 6)

1. **The Search card can't sit "under the checklist".** `LaunchChecklist` only renders before the first publish
   (`showChecklist = sitePhase !== "published"`, `sites.$slug._index.tsx:812`), and connecting needs a published site.
   After publish the main column is Counter strip → Last 30 days → What's happened, and open checklist steps move to the
   Finish setup rail (`deriveRailItems`, `includeChecklistSteps`). Proposed: the step shows pre-publish as waiting ("After
   you publish", not counted, like a skipped step, I1), becomes a rail row after publish (I2), and the card goes under
   Last 30 days (I3).
2. **"Range select".** Analytics uses a segmented control (`RangePicker`). I reused it (7 days · 28 days · 3 months)
   so the two tabs match, with a select on phones. The spec should say segmented.
3. **`not_shown` lives in two places.** It's an opportunity kind (§ 3.7) and also the Indexing card's list (§ 3.6). On
   Core with ≤ 5 rows the same page can show twice. Mocked: Pages to improve carries only `ctr_gap` +
   `striking_distance`, and not-shown pages show only in Indexing. Proposed: the Performance page filters
   `kind≠not_shown`. MCP keeps all three.
4. **Free and the Indexing card.** § 3.8's paid list doesn't include `getSearchIndexing`, so Free gets the sitemap row +
   not-shown list. Verdicts only exist after `inspectUrl` (Core), so Free never sees them. Mocked that way; confirm.
5. **Overview "3 pages to improve"** on Free: is `gscsum.opportunities` the full count or capped at 3? The link lands
   on a page that shows 3, so cap it at 3 for Free.
6. **Who sees the `…` menu.** "Refresh · Open in Search Console ↗ · Disconnect — owners only": I read "owners only" as
   applying to Disconnect. Everyone with access can refresh and open Search Console.

## Open questions for Luka

1. **Option B** (fix list) vs A (table)? And is the kind badge ("Better title", "Almost on page 1") worth keeping, or
   is the sentence enough?
2. **Status words for Google's indexing states.** Mocked "Google knows it, hasn't read it yet" (Discovered, not
   indexed), "Google read it, didn't add it yet" (Crawled, not indexed), "On Google", "Not checked yet". We need the full
   mapping table for `@dotsy/copy`. Raw Google wording in a tooltip, or never?
3. **"Could win about N clicks a month"** shows only when the API sends `potentialClicks`. Keep it on the row, or is it
   too much of a promise for a heuristic (spec § 11 risk)?
4. **Free upgrade line**: one line under Pages to improve (mocked) or at the bottom of the page? It mentions three things
   (fixes, searches/pages, Check on Google). Is that too long?
5. **Checklist step before publish** (I1): show it as waiting, or hide it until publish?
6. **Copy link for an owner** on the non-owner state: keep or drop?
7. **Chart colours** reuse Analytics (green + gold). In dark mode the two overlapping fills go muddy olive. Drop the
   shown-in-search fill and keep only its dashed line?
8. **Tabs row**: "New" suffix on Performance for 30 days (needs a ship date constant). OK?
