/
/planner, /design
/planner/[planId], /design/[designKitId]
/content, /dashboards, /reports, /events/[category], /contacts
/chat/[chatId] — and /rg, /localization, /checklist/[checklistId], /edit, whose main is the same persistent chat
The same pages as E, with the context column open
/planner/[planId], /design/[designKitId], /content, /contacts/[contactId], /dashboards/[dashboardId], /reports/[reportId], /rg, /localization
The same pages as G, with main unmounted
Every part of every screen above, numbered once. A number belongs to a component rather than a position, so 06 is the breadcrumb wherever it appears, and it carries its column’s colour with it.
The logo, in the rail’s header. The only thing on screen that belongs to the product rather than to anything you have open.
Not decided
Collapses the rail, at the right of its header beside the mark. The name is mine — the notes do not have one. It is the only control in the rail that is not a destination.
Collapses or opens aside-left. Nothing else moves
The product’s areas. The rail is how you get between screens, so nothing belonging to one screen goes here.
Goes to that area of the product
Recent conversations across everything, not just the thing you have open.
Opens that conversation in main
Account, theme, the rest. Pinned to the rail’s footer.
Not decided
The way back out, at the left of the header bar. Leaving a chat calls setCurrentChat(null) — a state change, not a route. The work area uses the same component in its own header, which is why it carries this number there too.
Back to the hub — setCurrentChat(null)
ContextAsideButton, at the right of the same bar. It opens and closes aside-right without touching what is in main.
Opens or closes aside-right. Nothing else moves
The composer. It runs two ways. On an entity it is anchored to that entity’s URN, so the chat comes back in its conversation list, and it is retitled because the day’s greeting says the wrong thing on one thing’s board: contextUrn, heading, brief={false}, navigate={false}. In the meeting room it takes none of those — a chat there belongs to no one thing — and the greeting and the brief are the room’s own voice moment.
Starts a chat. On a hub it replaces the hub in main; in the meeting room it goes to /chat
What this kind of entity would do for you. Inert on purpose — nothing in it clicks and no card carries a count, because there is no source for those numbers yet. A step gains a click and a count together.
Nothing. Inert until a step has a count behind it
What is waiting on you here. Empty for anything that is not a plan, because proposals carry a planId. Render it anyway: it is where entity proposals will land.
Not decided — nothing lands here yet outside a plan
Which plan, which design kit. The list pages have no name in the notes yet, so this is what it does rather than what it is called. The one screen where main is not a conversation.
Opens that plan or kit, which lands on its hub
The conversations. selectChatRowsForContexts(chats, [urn]).
Opens that chat in main
The conversation itself, once one is current. Which one is driven by the fc-current-chat cookie rather than the route.
—
The meeting room’s own header: a heading, where every other screen carries a breadcrumb. There is nothing above the meeting room to go back to.
Nothing. It is a title, not a control
What Odin has for you, in five sections — Setup, Critical, Attention, Proposals, Healthy. Attention comes before Proposals because work already running is tended before new work is planned. The five share one accordion, so opening a section closes the rest, and a section with nothing in it leaves the board rather than standing there empty.
A card opens its own detail; the chat is reached from inside that
What the list adds up to, above the list itself: how many, and in what state. It is about the set rather than any one of them, which is why it sits here and not on a hub. A list of names is a poor first thing to meet. Nothing draws it on /planner or /design yet, so this is what it does rather than what it is called.
Not decided
The column’s own header. There are two of these columns, one per occupant of main, and this is the header of whichever is showing.
The toggle is the control; the header itself does nothing
The brief. Part of the hub’s fixed list.
Opens the brief in the work area
The guidelines. Fixed too.
Opens the guidelines in the work area
The contents. Every row is a door into the work area, never a thing that opens where it sits.
Opens that row’s thing in the work area
What the conversation has named. First in the column because it is the part that fills soonest — anything you type at Odin can put something here.
Opens what the row names in the work area
Two controls at the right of the work area’s header. Close unmounts it and returns you to main. Expand is how you get to composition H: it unmounts main instead, and the work area has the width to itself. The names are mine — the notes do not have them.
Close returns to main; expand unmounts it — composition H
One, never two. Opened by a row in the context column, by Odin from inside a chat, or by a chat that begins about it.
—
App layout says what the columns are. This page says what goes in them. The whole of it comes down to asking, of anything you are about to place, which column’s question it answers.
A column that answers two questions has stopped being a column and become a page.
Every row in a context column is a door into the work area. That is the whole contract, and it is what keeps the two columns from doing each other’s job.
The work area can be opened three ways: a row in the context column, Odin opening something from inside a chat, or a chat that starts out about a thing. All three land in the same place, which is why a row that expands where it sits breaks more than it looks like it should — it gives one of the three a second destination.
The layout allows aside-right and work-area side by side. The hubs choose to swap them. That is a product decision, not a layout constraint, and it should not be repeated as though the layout forced it.
Chrome goes in the card snippet. A pane that frames its own body stops matching the ones beside it the moment either changes.
width: 480px on body content is a named anti-pattern, and so is an inline --dialog-max-width. The column owns the width.
The context column is doors. Something that opens in place makes the work area optional, and then two places show the same thing.
It holds one. Two means you have built a layout inside a layout, and the outer one stops being able to help.
If it gets you somewhere else it belongs to the rail. A pane that navigates competes with the thing that already does.
For anything that does not obviously belong anywhere. Ask them in this order and stop at the first one that answers.
The conversation goes in main. The thing goes in the work area, and the way to it goes in the context column.
If yes it is not context — context comes and goes with its occupant. If no it does not belong in the work area, which stays put while main changes.
Doors go in the context column, rooms in the work area. A row that expands in place is neither, and is the commonest way this gets broken.
Then it belongs to aside-left, or to nothing.
These four are consistent with what is built, but nobody has agreed them. They are on the page so they can be argued with, not because they are settled.