<!-- https://ios.app.promptugal.news/admin/briefs/2026-11-08__three-apps/status/design.html · PrompTugal for iOS 0.4.106 -->

# Status · Design (three apps)

> PTNews is moved and pushed but has never compiled. Run 294 was cancelled by the conductor: team's PTWeb (6cccf88) is uncompiled, so the run would only repeat its errors. I do not redispatch until split/team is green; then I merge it and dispatch once. PublicShell is not started (waits for phase 4).

Branch: `split/design` · Last update: 8 Nov, 11:58 UTC · Last CI run: iOS run 294 on 4430e67, cancelled by the conductor, no result

## Done
- Read the three-apps README and contracts, the overnight rules, and the App Review readiness page.
- Mapped Shell, Dashboards, Debug and News (below).
- Drafted the PrompTugal app's shell and the sharing options.

## Decisions (conductor)
- AgendaView and ReaderStore go to PTAgenda (team moves them; ReaderStore gets the schedule injected). PTAgenda must not depend on PTNews.
- PTNews gets `NewsSource` and `NewsFeeds`; `DashboardData` forwards to it. Each app adds `extension ReaderStore: NewsSource {}` (or a small adapter).
- Shell option C: shared parts in `Packages/PTCore/Sources/PTCore/Shell/` (mine); each app keeps its own root and Destinations.
- Team app scheme is `ptteam://`; PrompTugal keeps `promptugal://`. Reminders and links take the scheme as a parameter, not hard-coded.

- Editor needs code markers for site labels: PrompTugal root struct `PublicShell` (search `PublicShell(`); Team keeps `AppShell(` and `.teamFeatures()`. Sent the id list to the conductor.

- Merged `split/apps` (7d28094): `Apps/PrompTugal/` has the project, `PrompTugalApp.swift` (root `PublicShell()`, apps owns it) and a placeholder `Shell/PublicShell.swift` (mine). `Shell/` is a synchronized folder, so new files need no project edit.

## In progress
- Waiting for PTCore. `PublicShell` needs Design and the shared shell parts; with only PTVaultUI on dev I would be writing against types that do not exist yet. I start the moment PTCore is on dev.

## Next
1. Phase 3: merge `origin/dev`, move PTNews (with the fixes in section 1 once approved), push, read CI.
2. Phase 4: `Apps/PrompTugal/` screens and Destinations; the Team app's shell keeps working.

## Blocked
- Nothing yet. Phase 2 is the gate.

## Needs from others
- **Conductor:** answers to the five questions in section 1.4.
- **Platform:** `RemoteFeed`, `LoadPhase`, `FeedCache`, `enum Wire {}` with `LooseText`, `LooseScalar`, `WireDate` into PTCore, plus `Event`, `Story`, `Lisbon`, `FeedClient` from `Content.swift`.
- **Collab:** `AskView.swift:196` and `AIContext.swift:320` use `TeamFeatures`; PTAsk cannot, and the public app has no TeamFeatures.

## 1. PTNews: what moves, and what it needs from outside

### 1.1 What is in News/ today
| File | Lines | Uses from outside News/ |
| --- | --- | --- |
| `NewsHomeView.swift` | 268 | `ReaderStore` (news, newsUpdated, newsUnavailable, refresh), `DashboardData` (newsletter, board, refreshAll), `Wire.Edition`, Design, `WebPage`, `FeedClient`, `Story`, `Lisbon`, `HTTPClient` |
| `GraphExplorerView.swift` | 401 | `DashboardData.graph`, `RemoteFeed`, Design, `WebPage`, `FeedClient` |
| `GraphModel.swift` | 176 | `FeedClient`, Palette |
| `AgendaView.swift` | 204 | `ReaderStore`, `ScheduleStore`, `Event`, `Lisbon`, `WebPage` |

The graph is already in `News/`. There is no `Dashboards/Graph*` file; the graph feed is a property of `DashboardData`.

### 1.2 Where it breaks the package graph (PTNews → PTCore, PTWeb only)
1. **`AgendaView` needs `ScheduleStore`** (PTAgenda). PTNews cannot depend on PTAgenda. It is an agenda screen, not a news screen. **Proposal:** it moves to PTAgenda (team's package), not PTNews. `TodayView` (Team) uses it too and imports PTAgenda anyway.
2. **`ReaderStore` holds both the news cache and the agenda cache** in one `content.json`, and calls `TeamFeatures.shared.schedule` and `NowNextPublisher`. **Proposal:** PTNews declares a small protocol, `NewsSource` (`news`, `newsUpdated`, `newsUnavailable`, `refresh()`), and an environment key. `NewsHomeView` reads that instead of `ReaderStore`. `ReaderStore` conforms with one extension, in the app target. No change to the cache or to behaviour. `ReaderStore` itself goes to PTAgenda with the schedule passed in instead of `TeamFeatures.shared` (team's call).
3. **`NewsHomeView` and `GraphExplorerView` read `DashboardData`** (the Team dashboards' store). **Proposal:** PTNews owns `NewsFeeds` (`@Observable`): `newsletter`, `board`, `graph`, plus `refresh`. These are the same `RemoteFeed` instances with the same URLs. `DashboardData` keeps its property names by forwarding to an instance of `NewsFeeds` (`var board: … { news.board }`), so the Team dashboards (`NewsroomStatusView`) do not change. The Team shell puts `data.news` into the environment; the public app creates its own.
4. **`Wire.Newsletter`, `Wire.Edition`, `Wire.StoryBoard`** (in `Dashboards/WireModels.swift`) go with PTNews as `extension Wire`. That needs the empty `enum Wire {}` and the loose decoders in PTCore (platform). `GraphExplorer` already sits in `GraphModel.swift`.
5. **`RemoteFeed`, `LoadPhase`, `FeedCache`** are generic and only use `HTTPClient`. They go to PTCore (platform), or PTNews gets them and Dashboards imports PTNews. PTCore is cleaner.
6. **`NewsroomAPI.url(_:)`** (3 lines) moves with `NewsFeeds` into PTNews.

### 1.3 What PTNews imports
- **PTCore:** Design (Palette, Space, Typo, Page, Card, Kicker, StateView, FreshnessLabel, surfaceKind), `HTTPClient`, `Event`/`Story`/`Lisbon`/`FeedClient` (from Content.swift), `RemoteFeed`, `Wire` base.
- **PTWeb:** `WebPage` (and `WebsiteView` for the "All websites" screen, which lives in the app's Destinations).
- **TeamFeatures:** nothing. After the three fixes, PTNews has no reference to the Team's stores.

### 1.4 Questions for the conductor
1. `AgendaView` to PTAgenda instead of PTNews? (I recommend yes; team moves it, or I do it in phase 3 with team's agreement.)
2. `NewsSource` protocol and `NewsFeeds` in PTNews as in 1.2? (Recommended. Small, no behaviour change.)
3. Who moves `ReaderStore`, and where? (Recommend team, to PTAgenda.)
4. Platform puts `RemoteFeed`/`LoadPhase`/`FeedCache`/`Wire` base/`Event`/`Story`/`Lisbon`/`FeedClient` in PTCore in phase 2?
5. Should the Team app get its own URL scheme (`promptugal-team://`) so the two apps do not both claim `promptugal://open/…`? (Platform.)

## 2. Which Shell, Dashboards and Debug types each app needs
| Item | Team | PrompTugal |
| --- | --- | --- |
| `AppShell`, `Destinations` (Team list), `ShellSection` | yes (stay) | own, smaller (section 3) |
| `PrivacyCover`, `ShellLink`, `LinkedPage` | yes | yes (shared, section 4) |
| `SampleMode`, `SampleBanner`, `LaunchOptions` sample flags, `PreviewSamples` | yes | no (dropped) |
| `IdentitySync`, `ChooseIdentityView`, "Who are you?" | yes | no |
| `SettingsView` (team picker + About) | yes | new `PublicSettingsView`: About, Privacy, Support, version, independence note, Reminders; debug switch only in DEBUG |
| `SupportLinks` | yes | yes (move to PTCore; two lines of URLs) |
| `DashboardData`, `TeamDashboardView`, `AgentsDashboardView`, `BriefedView`, `CommandCentreView`, `NewsroomStatusView`, `ObservabilityView`, `TodayView`, `WallView` | yes | no |
| `Debug/` panels | all | only Network and System panels, in DEBUG builds; none in Release |
| `LaunchOptions` (`-PTDestination`) | yes | yes, DEBUG only (screenshots) |

## 3. The PrompTugal app's shell (plan)

### Destinations
Ids stay the same as the Team app's, so `promptugal://open/<id>` links and reminders keep working in both.

| Section | Destination | id | Screen | From |
| --- | --- | --- | --- | --- |
| Summit | Agenda | `reader.agenda` | `AgendaView` | PTAgenda |
| Summit | My day | `team.schedule` | `MyDayView` (picks) | PTAgenda |
| Summit | Plan my day | `team.planner` | `PlannerView` | PTAgenda |
| News | News | `news.home` | `NewsHomeView` | PTNews |
| News | Graph | `news.graph` | `GraphExplorerView` | PTNews |
| Ask | Ask | `collab.ai` | `AskView`, with the consent sheet | PTAsk |
| Web | PrompTugal.news | `web.promptugal` | `WebPage(FeedClient.site)` | PTWeb |
| Web | All websites | `web.all` | `WebsiteView` | PTWeb |
| Personal | Vault (optional) | `vault` | `VaultHomeView` | PTVaultUI |
| Settings | Settings | `settings` | `PublicSettingsView` | Apps/PrompTugal |
| Settings | Reminders | `settings.reminders` | `ReminderSettingsView` | PTAgenda |
| Debug (DEBUG only) | Debug | `debug` | Network + system panels | PTCore panels |

Left out: Today (team), The team, My command centre, Messages, Where is everyone, Team home, Reading credit, What my agents do, Wakes/Reports (web), Briefed, Pulse/Board (web), Newsroom, Observability, Wall, Coordination, "Who are you?", sample data.

### iPhone
Four tabs and More, as today: **Agenda** (`reader.agenda`), **My day**, **News**, **Ask**, then **More** (Plan my day, Graph, Web, Vault, Settings, Reminders).
- **First screen: Agenda.** It works offline, needs no key and no identity, and is what an attendee or a reviewer wants first.

### iPad
A sidebar with the sections above (Summit, News, Ask, Web, Personal, Settings). First selection: Agenda. Vault keeps `ownsNavigation` (its own columns). ⌘1–⌘6 jump to a section, ⌘, opens Settings. The "Ask beside any screen" button and ⌘K stay (`askAnywhere`), once it is in PTAsk.

### Release rules (App Review pack)
- Ask consent sheet before the first request, context off except the public agenda (PTAsk; unchanged).
- Privacy cover while the scene is inactive.
- Settings links: Privacy, Support, "About this coverage"; independence note under it.
- Debug: no panel, no switch, no inspectable web views in Release. `DebugMode.defaultOn` is already false in Release; the public Settings has no toggle outside `#if DEBUG`, and the ⌘⇧D shortcut is also DEBUG only.
- No team names anywhere in the public target's Info or code. A grep for `TeamFeatures`, `DashboardData`, `TeamEndpoints` under `Apps/PrompTugal/` and the packages it links should come out empty. I will add that as a test in the app's tests.

## 4. Sharing the shell between the two apps
**Option A, one generic shell (`ShellKit` in PTCore).** `AppDestination` takes a plain group title instead of the `ShellSection` enum; `ShellRoot(destinations:, header:, badge:, overlays:)` draws the sidebar, tabs and More. One code path. Cost: rewrites the shell the Team app uses tonight (enum to struct, hooks as closures), so it can break Team.

**Option B, two small shells.** Copy ~250 lines per app. No shared risk, but fixes land twice.

**Option C (recommended): shared parts, two small roots.** PTCore gets only the pure UI parts (git mv, `public`): `AppDestination` (with a `group: String` instead of the enum), `SidebarRow`, `MoreRow`, `PrivacyCover`, `ShellLink`/`LinkedPage`, the `destinationID` modifier, `SupportLinks`. Each app keeps its own root (`TeamShell`, `PublicShell`) and its own `Destinations` list. The Team root is today's `AppShell` with those parts imported; the public root is ~150 lines. The Team app changes by imports and one enum-to-string edit. I would do this in phase 4, after the Team files are in `Apps/Team/`, so phase 3 stays small.

I need a yes from the conductor to put those parts in PTCore (platform owns it).

## Last CI run
None. Nothing moved yet.

## Handoff (8 Nov, 01:35 UTC)

**Head:** `split/design` at the commit named in the handoff message to the conductor (this page's own commit on top of `4430e67`). `4430e67` is the last code commit.

**Last CI run:** iOS run 294 (id 42434478548), `workflow_dispatch`, app=all, on `4430e67`. Status when I stopped: queued. Read it first: `mcp__github__actions_list list_workflow_runs` for `ios.yml`, branch `split/design`. Do not cancel it. If it fails, read `get_job_logs` with `failed_only`.

**Done**
- Merged `origin/dev` (PTCore, phase 2), `split/apps` (7d28094) and team's PTWeb (6cccf88) into `split/design`.
- PTNews moved with `git mv`: `NewsHomeView`, `GraphExplorerView`, `GraphModel` are in `Packages/PTNews/Sources/PTNews/`.
- New in PTNews: `NewsSupport.swift` (`NewsSource` protocol with the `newsSource` environment key, `EmptyNewsSource`, `NewsroomAPI`, `NewsFeeds` with newsletter, board, graph) and `NewsWire.swift` (`Wire.StoryBoard`, `Column`, `BoardStory`, `Newsletter`, `Edition`, all public; cut from `Dashboards/WireModels.swift`).
- `DashboardData` now owns `let news = NewsFeeds()` and forwards `board`, `newsletter`, `graph` to it. `NewsroomAPI` moved out of `DashboardData.swift`.
- App side: `PrompTugal/App/ReaderStore+News.swift` (`extension ReaderStore: NewsSource {}`), `PrompTugalApp` sets `.environment(\.newsSource, store)`, `AppShell` sets `.environment(data.news)`.
- Graph tests (`GraphIndexSafetyTests`, graph layout test) moved from `PrompTugalTests/DesignReviewTests.swift` to `Packages/PTNews/Tests/PTNewsTests/GraphTests.swift`.
- `Package.swift` of PTNews has `swiftLanguageModes: [.v5]`, like team's packages.
- One behaviour change: pull-to-refresh on News now reloads only the newsletter and the story board (`NewsFeeds.refresh`), not the team and newsroom feeds.

**Half-done / not done**
- PTNews has not been built. It needs `WebPage` and `.webTwin` from PTWeb (merged, public in `Packages/PTWeb/Sources/PTWeb/Web/WebPage.swift`), but team's own CI for 6cccf88 was not green yet when I stopped. Expect compile errors to fix from run 294 (public API, missing `import`s).
- `AgendaView` and `ReaderStore` are still in the app; team moves them to PTAgenda. When they move, check `NewsHomeView` still sees `ReaderStore: NewsSource` (the extension file must stay with the app or go with `ReaderStore`, but PTAgenda must not import PTNews).
- `AppShell.swift:98` still has `url.scheme == "promptugal"`. Platform is adding `enum AppLinks { public static var scheme }` to PTCore (commit ce3602e on `split/platform`). When it is on dev, change it and every other hard-coded scheme in `Shell/AppShell.swift` and `Shell/Destinations.swift` to `AppLinks.scheme`.
- `PublicShell` is not started (still the apps session's placeholder).

**Exact next steps**
1. Read run 294. Fix PTNews until green. Then dispatch again (`app=all`), and when green send `@parent` the branch, commit and run number.
2. Merge `origin/dev` again when team's PTWeb/PTAgenda land there; fix anything that moves.
3. Switch the link scheme to `AppLinks.scheme` once it is on dev.
4. Phase 4: build `Apps/PrompTugal/Shell/PublicShell.swift`, `Destinations.swift` and `PublicSettingsView.swift`, on top of `split/apps` (project and entry point are the apps session's; `Shell/` is a synchronized folder, so new files need no project edit). Shared shell UI parts go in `Packages/PTCore/Sources/PTCore/Shell/` (mine, per the conductor's ruling). Plan: sections 3 and 4 of this page.

**What I gave the editor (the conductor passed it on)**
- Root marker: `PublicShell` (search `PublicShell(`). Team keeps `AppShell(` and `.teamFeatures()`.
- Destination ids, same as Team's: `reader.agenda`, `team.schedule`, `team.planner`, `news.home`, `news.graph`, `collab.ai`, `web.promptugal`, `web.all`, `vault`, `settings`, `settings.reminders`, `debug` (DEBUG builds only).

**Conductor rulings in force:** AgendaView and ReaderStore go to PTAgenda (team moves them); `NewsSource` plus `NewsFeeds` in PTNews; shell option C (shared parts in PTCore `Shell/`, each app its own root and Destinations); Team's scheme is `ptteam://`, PrompTugal's is `promptugal://`; apps owns `PrompTugalApp.swift` and Config, design owns `Apps/PrompTugal/Shell/`.

**Scheduled triggers:** all three of mine are deleted.

## Update (8 Nov, 01:55 UTC, design.B)
- Took over from account A. Read the plan, contracts (section 7), handoff and this page.
- Run 294 was cancelled by the conductor. Rule from the conductor: do not redispatch until split/team is green; then merge split/team into split/design and dispatch once.
- Read PTNews against the public APIs of PTCore and PTWeb (`RemoteFeed`, `Wire`, `LooseText`, `Story`, `FeedClient`, `WebPage`, `webTwin`, Design components). Found nothing to fix by reading. Real errors will show on the first compile.
- Waiting for: team's PTWeb green; `AppLinks.scheme` on dev (then switch the hard-coded schemes in `Shell/AppShell.swift` and `Shell/Destinations.swift`); the conductor's word that phase 4 has started (PublicShell).

## Update (8 Nov, 02:52 UTC, design.B)
- Still holding. Team's run 300 on 1bf25c5 is queued, so split/team is not green. AppLinks.scheme is not on dev (dev d519d14).
- Conductor ruling (02:25): when split/team is green, merge origin/dev and split/team into split/design, then dispatch ios.yml once with app=all, runner=self-hosted.
- Nothing pushed to split/design except this page. PublicShell is not started.

## Update (8 Nov, 03:00 UTC, design.B)
- Merged origin/dev (AppLinks.scheme, 5500c02). `AppShell` now checks `url.scheme == AppLinks.scheme`; the other hard-coded schemes in `Shell/` were only in comments and now say `<scheme>`. Not compiled yet.
- Still waiting for team's PTWeb to be green before I dispatch (conductor will say).
- Needs from team: `PrompTugal/Team/TeamFeatures.swift:20` still has `static let urlScheme = "promptugal"` for the reminder scheduler; it should read `AppLinks.scheme`.

## Update (8 Nov, 03:32 UTC, design.B)
- Team's PTWeb and PTAgenda are on dev (run 307 green). Merged origin/dev (eb99508) into split/design with no conflicts; team's files on my branch equal dev's.
- Added `import PTAgenda` to `PrompTugal/App/ReaderStore+News.swift`. Head: b1ef07a.
- Dispatched ios.yml app=all, runner=macos-26 on b1ef07a: run 312 (id 42441902683), queued at 03:32. Rule from the conductor: runner=macos-26 only; the self-hosted Mac is offline.
- AppLinks.scheme switch is in (AppShell). PTNews has still never compiled; I fix PTNews errors only.
- PublicShell not started; waits for the conductor's phase 4 word.

## Update (8 Nov, 04:22 UTC, design.B)
- Run 312 (b1ef07a) failed on real PTNews errors; run 318 (4c18d6b) failed on one more. Fixed all, each in PTNews or its public API:
  - `GraphExplorerView` previews used the Team app's `PreviewSamples`: now `NewsFeeds()`.
  - `NewsHomeView` used the dashboards' `InfoRow`: PTNews has its own `NewsRow`.
  - `GraphExplorer.version` is now public (the Team debug panel `SystemPanels.swift:239` reads it).
- Merged origin/dev again. Head 83f761f. Quick run 319 (id 42445321839, quick=true, macos-26) is queued. Runs 312 and 318 are cancelled.
- Plan from the conductor: after a green quick run, one full run (quick off, macos-26) on the same sha, then READY.
- `AppShell.swift:98` compares `url.scheme == AppLinks.scheme` (so the Team app's ptteam links work once its entry point sets the scheme).
- PublicShell not started; waits for phase 4.

## Update (8 Nov, 05:22 UTC, design.B): READY
- Quick run 319 on 83f761f: green. Full run 323 (id 42447845511, app=all, macos-26) on bb50751: green. Debug and Release builds of all three apps, iPhone and iPad tests, packages PTNews and PTAsk.
- bb50751 is 83f761f plus this status page only.
- READY sent to the conductor. PTNews merges to dev now that team's PTWeb is there.
- Next: wait for the conductor's phase 4 word, then PublicShell in Apps/PrompTugal/Shell/ (drafting allowed locally on a separate branch, not pushed to split/design).

## Update (8 Nov, 06:00 UTC, design.B): PTNews on dev, PublicShell drafted locally
- Conductor merged bb50751 to dev as d3cb173 (run 323 green). PTNews is done.
- PublicShell draft (not pushed; waits for the conductor's phase 4 word) is one commit on a local branch `local/public-shell` from origin/dev:
  - `Packages/PTCore/Sources/PTCore/Shell/`: `ShellDestination` (group as text), `ShellSidebarRow`, `ShellMoreRow`, `PrivacyCover`, `LinkedPage`, `ShellLink` (checkout rule passed in), `SupportLinks`, `destinationID`.
  - Team app: the same-named types leave `Shell/AppShell.swift` and `SettingsView.swift`; `ShellLink.page(in:)` stays as a one-line Team extension that passes `CheckoutPolicy.isBlocked`. Team's `AppDestination` and rows are unchanged for now.
  - `Apps/PrompTugal/Shell/`: `PublicShell` (iPad sidebar, iPhone tabs + More, link routing, privacy cover), `Destinations.swift` (`PublicDestinations`, same ids as Team's), `PublicSettingsView` (no team picker; debug switch only in DEBUG), `PublicDebugView` (DEBUG only), `PublicFeatures` (schedule, planner, reminders, bridge, vault picks with no team and no identity).
  - Not compiled yet when written. Ask waited for PTAsk, which is on dev now and wired in.
- Needs from others:
  - **Apps/platform:** `PrompTugalApp.swift` can stay `PublicShell()`; the shell makes its own `ReaderStore`, `NewsFeeds` and `PublicFeatures`. Background task registration (refresh, vault-refresh) is still the entry point's job.
  - **Platform (widgets, phase 4):** `NowNextPublisher` is not in a package, so the public app does not publish "Now and next" yet (`AgendaHub.publishNowNext` is left at its default).
  - **Team:** `TeamFeatures.swift:20` `urlScheme`.
  - **Offline reader:** `WebBridgeHub.offlineReader` is nil in the public app until a reader view moves out of the Team app's `PrompTugalApp.swift`.

## Update (8 Nov, 07:40 UTC, design.B): phase 4, PublicShell pushed
- Conductor started phase 4 at 07:07 UTC. Pushed PublicShell on top of origin/dev (02f3624 era): `Apps/PrompTugal/Shell/` (PublicShell, Destinations, PublicSettingsView, PublicDebugView, PublicFeatures) and `Packages/PTCore/Sources/PTCore/Shell/` (shared parts). Ask is in (iPhone tab 4; `askAnywhere` on iPad). Offline reader stays nil in the public app.
- Head c025f83. Full run 333 (id 42457549551, app=all, macos-26), dispatched 07:08. At 07:40: Debug build (team), Debug build (riskmandate), riskmandate iPad tests and Package PTAsk passed; no failure; the rest queued behind the runner queue. The Debug build (promptugal) is the first compile of PublicShell.

## Update (8 Nov, 09:35 UTC, design.B): phase 4 ready
- Two compile errors on the first PublicShell builds, both mine, both fixed: the argument order in the debug destination, and the public app needed its own `ReaderStore: NewsSource` extension.
- Full run 342 (id 42463232061, app=all, macos-26) on d7c728e: success. d7c728e is code b8716f4 plus this page.
- READY sent to the conductor.
- Open items for others: widgets and "Now and next" for the public app (platform, `NowNextPublisher`); the public app's offline reader (`WebBridgeHub.offlineReader` is nil); the Team app's `TeamFeatures` url scheme (team).

## Update (8 Nov, 10:20 UTC, design.B): on dev
- The conductor merged d7c728e to dev as 105ca49. Dev run 345 on it concluded success: PublicShell, the apps' entry point and the widgets build and test together.
- Nothing is open on split/design. Still open for others: the public app's offline reader (`WebBridgeHub.offlineReader` is nil) and the Team app's `TeamFeatures` url scheme (team).

## Update (8 Nov, 11:58 UTC, design.B): summit build, shell, Now, News
- On split/design (head 49a9fa8, quick run 370 on d58958c queued, nothing compiled yet since the shell rewrite):
  - Icons: a Team icon (blue, cream P, gold T, italic "team") and a RiskMandate icon (navy, white "RM", red bar), 1024 px, no alpha.
  - Review blockers: vault and All websites are DEBUG-only; Ask left the tab bar.
  - SHELL (ux spec): four tabs Now (default), My program, Explore, News; no More tab; a gear on Now and My program opens Settings; old ids still route (reader.agenda and news.graph open Explore, team.planner opens My program); decks and PrompTugal.news are routable but not listed.
  - NOW-1: phases from team's `NowBoard` (cherry-picked 1811803 as 6ece567): countdown, For you, On now, Up next, Tomorrow, thank you; latest news; the practical card; Ask as the last card. DEBUG `-PTNow <ISO time>` fixes the time.
  - NEWS-1: Latest, Newsletter, Stories; "Offline · saved HH:MM"; the graph card left News; a share button on every story (F10).
  - Ask (ux update): last card on Now, first row in Settings, a row in the iPad sidebar.
- Waiting: `AskView(question:)` from collab (the three tappable questions with a saved key); PTExplore linked by apps. The Explore wiring (ExploreScreen with agenda talks, native talk detail, graph card, explore.* ids) is written on a local branch and goes on split/design the moment PTExplore is linked.
- Practical-card source links: ux has not given the URLs; none are invented.
