---
id: "3.8"
title: "States, Fetch"
dept: design
status: draft
owner: Param
branded: true
direction: dog
last_verified: 2026-10-26
sources:
  - "brand-directions/dog/kit-skin.js"
  - "brand-directions/dog/system.md"
  - "brand-directions/docs2/data/dirs.json"
  - "brand-directions/_shared/ia.md:79-145"
  - "brand-directions/_shared/product-model.md:99-113, 129-142"
  - "brand-directions/_kit/screens.js:198-541"
  - "brand-directions/_kit/render.js:52-54"
  - "brand-directions/_kit/kit.css:312, 480-503"
  - "brand-directions/book/content/d2.js:11-160"
  - "brand-directions/_shared/surface-map.md:454-457"
  - "brew origin/main b91e364: public/app.js:1657, public/sw.js:1-8, public/feed-system.css:157-160"
  - "memory: brew-loader, brew-quiet-ui"
---

# States, Fetch

## Answer

Every Brew screen is in one of six states, empty, waiting, partial, error, full or done, and each state looks the same everywhere, with Fetch in its slot and its own words around one plain way forward.

## Today

Checked 26 October 2026.

| Fact | Source |
|---|---|
| 25 empty state classes in markup and 18 more only in CSS | [src: brand-directions/_shared/surface-map.md:456] |
| 10 errors are shown in the empty style, such as "The products didn't load. Reload the page." | [src: brand-directions/_shared/surface-map.md:457] |
| 12 loader kinds: spinners, 23 skeleton uses, 6 full screen holds, 18 button text swaps, a game | [src: brand-directions/_shared/surface-map.md:454] |
| Since 21 October every wait uses one loader, the b mark that fills and steams, inside the button that started it | [src: memory brew-loader] |
| The loader holds still under reduced motion | [src: brew origin/main public/feed-system.css:157] |
| The feed ends with "You're done for today" and Find more | [src: brew origin/main public/app.js:1657] |
| Offline, the app shell shows a plain page instead of a browser error | [src: brew origin/main public/sw.js:1-8] |
| Quiet pages hide a section until it has something; no zero tiles | [src: memory brew-quiet-ui] |
| In the kit, a slot under 120 px draws Fetch's small mark, dog/char-mark.svg, instead of the full pose | [src: brand-directions/_kit/render.js:52-54] |
| Fetch's state words live in its kit-skin.js | [src: brand-directions/dog/kit-skin.js:42-84] |

## Tomorrow

Each state, as Fetch wears it. All v1 unless tagged.

| State | Screen | What you see | Fetch | Words | One way forward | Tag |
|---|---|---|---|---|---|---|
| Empty | w2 Work, empty | the empty state | empty slot, 96 px: dog/char-mark.svg, the small mark | "Nothing in the works yet. Pick one and I will follow." | See this week's picks | Changes |
| Empty, filtered | t4 See everything with no match | the empty state | empty slot, 96 px: dog/char-mark.svg, the small mark | not written yet | Show all areas | New |
| Empty on purpose | Need your yes with nothing waiting | the section hides | none | none | none | Changes |
| Waiting, short | any button that saves | spinner inside the button, label kept | none | none | it finishes | Changes |
| Waiting, long | m2 Making | the thing dimmed, the wait card | wait slot, 64 px: dog/char-mark.svg, the small mark | "Making it now. You can go, I will stay." | leave; it lands in Work | Changes |
| Partial, reading | f4 Reading your store | seven sources tick, findings arrive with sources, question 1 of 3 | wait slot, 140 px: dog/svg/pose-02.svg, sniff, 1.4 s loop | "Sniffing round your store. About 3 to 4 minutes." | answer a question or watch | Changes |
| Partial, connections | s5 Connections | one chip per row: Connected, Needs you, Expiring, Stale, Read only | none | chip words only | open the row that needs you | Changes |
| Error, the read | f5 Read did not finish | the error state, page size | error slot, 96 px: dog/char-mark.svg, the small mark | "I lost the scent and the read stopped. Start again." | Start again | Changes |
| Error, a make | m5 Something broke in Make it | the error panel, says which version is safe | error slot, 56 px: dog/char-mark.svg, the small mark | "Dropped that one. Your other versions are safe. Try again." | Try again | Changes |
| Refusal | f3 This store is for its own team | the error state with your email shown | error slot, 96 px: dog/char-mark.svg, the small mark | "This store is for its own team. Try a demo store." | See demo stores, or Switch email | Changes |
| Not found | x1 Error page | the error state, page size | error slot, 96 px: dog/char-mark.svg, the small mark | "Nothing buried here. This page is not found." | Go to Today | Changes |
| Offline | x2 Offline | the error state | wait slot, 96 px: dog/char-mark.svg, the small mark | "No connection. I will wait by the door." | Try again | Changes |
| Cap reached | f6 Reads are full this week | the empty state, never a countdown | empty slot, 96 px: dog/char-mark.svg, the small mark | "Reads are full this week. Ask us for a design partner read." | Ask for a design partner read | Changes |
| Full | t1 Today on Monday | Need your yes, rings, five picks | corner, 44 px: dog/char-mark.svg | "Monday. Five picks, dropped at your feet." | the bottom bar on a pick | Changes |
| Done, a heart | t6 A heart | a toast with Undo | celebrate, 40 px in the toast: dog/char-mark.svg, the small mark | "Good pick. Fetching more like it." | Undo | Changes |
| Done, handed off to you | h2 Handed off | the celebration | celebrate slot, 120 px: dog/svg/pose-09.svg | "Copied, and the place to post is open." | Open the brief | Changes |
| Done, handed off to a team | h2 Handed off | the celebration with the brief number | celebrate slot, 120 px: dog/svg/pose-09.svg | "Brief copied. Paste it to them, nothing was sent." For our team: "Our team has your brief now." | Open the brief | Changes |
| Done, the week | t5 Caught up | the sign off until Monday | caught slot, 120 px: dog/svg/pose-07.svg | "That is the week. Every pick seen." then "I am keeping the ball now. See you Monday." | none until Monday | New |
| Error inside a sheet | a connect or hand off that did not go | one line above the sheet buttons | none | one plain sentence | Try again inside the sheet | Changes |
| Field warning | f1 Paste your store | warn border and a hint | none | That looks like a name. Paste the website address instead. | fix the address, nothing lost | Changes |

[src: brand-directions/_kit/screens.js:198-541] [src: brand-directions/_shared/ia.md:83-129] [src: brand-directions/dog/kit-skin.js:42-84] [src: brand-directions/dog/kit-skin.js:19-31]

Fetch's own name for a broken moment is "Lost the scent" and for the week done is "Nap time". These live in marketing and section headers, never as the error sentence itself. [src: brand-directions/docs2/data/dirs.json]

### Rules

1. An error never uses the empty style. Empty means nothing is wrong.
2. Every state names one way forward, except done for the week, which says when the next thing arrives.
3. Errors say what happened and what is safe, with no codes and no blame. Errors make Fetch sheepish, ears down. It is never sad, hurt, scared or begging.
4. Money, privacy, apologies and anything a person must sign are written by people; Fetch stays out of those.
5. Say the real time once: about 3 to 4 minutes for the read. Never a countdown.
6. No skeletons. Short waits are the spinner in the button; long waits are Fetch's wait slot and one line.
7. Under reduced motion Fetch holds still in every state.

[src: brand-directions/_shared/product-model.md:99-113] [src: brand-directions/dog/system.md:91-111]

### Sound with each state

Sound is off on a first visit and stays off until the person turns it on in Settings. When on, one tap plays one cue: heart after a heart, ready when the read finishes or a make is ready, handoff after Hand it off, error when something broke on our side, caught when the week is done. Screens that change by themselves stay silent. Files: dog/snd/logo.mp3, dog/snd/cue-heart.mp3, dog/snd/cue-ready.mp3, dog/snd/cue-handoff.mp3, dog/snd/cue-error.mp3, dog/snd/cue-caught.mp3. [src: brand-directions/dog/kit-skin.js:86-89] [src: memory brew-sounds]

### Later states

| State | Version | Tag |
|---|---|---|
| Scheduled, and a post that failed to go out, with Try again | v2 | New |
| Live, with where it went | v2 | New |
| How it went with no data yet: says when the first numbers arrive | v3 | New |
| A rule paused by its limit, in Need your yes | v4 | New |

## How we do it

1. List the states the screen can be in from the table. Draw each one in the kit with its key, such as m5:broke.
2. Use the kit part for the state: k-empty, k-error, k-wait, k-celebrate or a busy button.
3. Take Fetch's words from brand-directions/dog/kit-skin.js; if a state has no key, write one there first, 12 words at most.
4. Check the slot size: under 120 px Fetch draws as the small mark.
5. Force each state on real brands and on the sample store, at 390 and 1280 wide, light and dark.

## Numbers

| Number | Definition | Today | Tomorrow | Where measured | Status |
|---|---|---|---|---|---|
| Empty state styles | distinct empty classes | 25, plus 18 in CSS only | 1 | CSS scan | Measured |
| Errors in the empty style | error messages drawn with an empty class | 10 | 0 | code scan | Measured |
| Loader kinds | distinct ways to show a wait | 12 | 2 | code scan | Measured |
| Screens with every state drawn | of 45 kit screens | not measured | 45 | kit state list | Proposed |
| Weeks caught up | share of brand weeks that reach the caught up state | not measured | | product event | Proposed |

## Open

1. Empty and error slots are 96 px, under the 120 px switch, so Fetch's empty and error poses never show in those slots. Raise those slots to 120 px or accept the small mark? Proposal: accept the small mark in the product and keep the full poses for marketing.
2. The kit has no words for See everything filtered to nothing. Proposal: "Nothing in this area this week." with Show all areas.
3. Should the first heart celebration use Fetch's full celebrate pose rather than 40 px in the toast? Proposal: yes, once, at 120 px, then the toast for every later heart.
