# cross-platform-variants.screen Per-platform layout breakdowns for iPad (E2), macOS Catalyst (E3), and web (E4) — adapting the iPhone canonical `chat-home.screen.md` without re-design. Tokens, components, and voice inherit from iPhone; only layout adapts. Companion handoff between phone and web/laptop is covered separately in `cross-device-handoff.flow.md` (G4 / Mode 1–3). ## E2 — iPad (P5) iPad runs the same SwiftUI codebase as iPhone, recomposed for landscape two-column with persistent drawer; portrait collapses back to iPhone behavior. ### Landscape two-column sketch (logical 1366×1024) ``` ┌──────────────────────────────────────────────────────────────────────────────┐ │ status bar (system) │ ├────────────────────────────────────────┬─────────────────────────────────────┤ │ [≡] ai-copilot ▼ [🔍] [⌥] │ Drawer · Calendar [⊟ pin] │ ├────────────────────────────────────────┤─────────────────────────────────────┤ │ [ai-copilot 12·🟢] [triage 47·🟡] [⊞] │ Oct 2026 │ ├────────────────────────────────────────┤ ┌──┬──┬──┬──┬──┬──┬──┐ │ │ ┌────────────────────────────────────┐ │ │M │T │W │T │F │S │S │ │ │ │ Bumped Tryst at 11:02. ↶ │ │ ├──┼──┼──┼──┼──┼──┼──┤ │ │ └────────────────────────────────────┘ │ │ │ │ 1│ 2│ 3│ 4│ 5│ │ │ ┌────────────────────────────────────┐ │ │ 6│ 7│ 8│ 9│10│11│12│ │ │ │ ▢ New about-me for Tryst │ │ │… │ │ │ │ [Edit][Approve][Set aside] │ │ │ │ └────────────────────────────────────┘ │ Berlin Oct 3–7 · 4 directories │ │ │ [Announce] [Edit] [Set aside] │ │ Quinn: pause tryst for an hour │ │ │ Cocotte: Paused til 12:43. │ │ │ │ │ ├────────────────────────────────────────┤ │ │ ╭────────────────────────╮ [🎤][📷] │ │ │ │ Tell Cocotte… │ │ │ │ ╰────────────────────────╯ │ │ └────────────────────────────────────────┴─────────────────────────────────────┘ ↑ chat column (≈58% width) ↑ persistent inspector drawer (≈42%) ``` - Drawer is **persistent** (not full-screen sheet). Tap a drawer-opening affordance in chat → drawer column swaps content, chat stays put. - `[⊟ pin]` toggles pin/unpin; unpinned drawer slides away on outside-tap, pinned holds across navigation. - Drag the column divider to resize (40/60 → 60/40 clamp). ### Portrait fallback Compact-width (iPad portrait, multitasking split-view ⅓, Slide Over): collapses to single-column iPhone behavior. Drawers become full-screen sheets again. Persistent-drawer pin state is remembered and re-applied when returning to landscape. ### Hover affordances (trackpad / Apple Pencil hover) - Approval cards lift 2pt and reveal a hover-only `[•••]` overflow with Approve / Reject / Edit / Snooze. - Receipt bubbles show a hover-only `↶ undo` chevron without requiring swipe. - Fleet-strip pills surface a hover tooltip with last-action time and pending count. - Cursor is the platform `IBeamCursor` in composer, `pointingHandCursor` over cards. ## E3 — macOS Catalyst (deferred design; scaffold-ready) macOS runs Catalyst with a three-column layout when window width ≥ 1280pt. Sidebar (specialists fleet) + chat + drawer/ticker. Keyboard is the primary input. ### Three-column sketch (logical 1440×900) ``` ┌──────────────────────────────────────────────────────────────────────────────┐ │ ● ● ● CocotteAI ⌘K search │ ├────────────────┬────────────────────────────────────┬────────────────────────┤ │ FLEET │ ai-copilot ▼ │ Agent actions · live │ │ ● ai-copilot │ ───────────────────────────────── │ ───────────────────── │ │ ● triage 47 │ Bumped Tryst at 11:02. ↶ │ 11:02 Tryst bump ok │ │ ● bookings 6 │ │ 10:58 OF draft saved │ │ ● content-of 3 │ ▢ New about-me for Tryst │ 10:41 Triage: 2 warm │ │ ● strategist │ "—corporate" removed │ 10:30 Vigil opened │ │ ● producer │ [Edit][Approve][Set aside] │ … │ │ ● publisher │ │ │ │ │ Quinn: pause tryst for an hour │ Filter ▾ [audit ↗] │ │ [⊞ all 12] │ Cocotte: Paused til 12:43. │ │ │ │ │ │ │ │ ───────────────────────────────── │ │ │ │ ╭───────────────────╮ [🎤][📷] │ │ │ │ │ Tell Cocotte… │ │ │ │ │ ╰───────────────────╯ │ │ ├────────────────┴────────────────────────────────────┴────────────────────────┤ │ status: connected · vps-0 · 12 actions today v3.0.0 │ └──────────────────────────────────────────────────────────────────────────────┘ ↑ sidebar 220pt ↑ chat (flex) ↑ ticker 320pt ``` - Window-narrower-than-1280pt collapses ticker first, then sidebar (mirrors iPad landscape, then iPhone). - Native macOS chrome: traffic lights, menu bar, status bar at bottom. - Sidebar is the brief-L fleet list; ticker is a live `agent_actions` tail (brief I). ### Keyboard shortcuts | Shortcut | Action | Notes | |---|---|---| | ⌘↵ | Approve focused approval card | Haptic surrogate: subtle accent flash | | ⌘⇧↵ | Reject focused approval card | | | ⌘E | Edit focused approval card | Opens inline edit; ⌘↵ commits | | ⌘K | Global search (brief U) | Spotlight-style overlay | | ⌘, | Settings (brief S) | Native macOS convention | | ⌘. | Kill-switch confirm (brief K) | Two-step: ⌘. opens confirm sheet, ⌘↵ confirms | | ⌘1 / ⌘2 / ⌘3 | Focus sidebar / chat / ticker | | | ⌘[ / ⌘] | Prev / next specialist in fleet | | | ⌘N | New thread with current specialist | | | ⌘F | Find-in-thread | Inline find, not global | | Space | Quick-look focused receipt or audit row | | ## E4 — web variant (`ai.cocotte.maison`) React 19 + Vite, desktop-first because web is where Quinn does bulk / calendar work. Same component contracts as iOS but rendered in DOM. Companion handoff per `cross-device-handoff.flow.md`. ### Responsive breakpoints - **≥1440px (desktop wide)** — three-column mirroring macOS Catalyst: sidebar (specialists) · chat · drawer/ticker. Desktop chrome: top app-bar with brand mark, search, device chip, kill-switch glyph; bottom status strip with connection + audit-count. - **1024–1439px (desktop standard)** — two-column: chat + drawer. Sidebar collapses to a hamburger overlay. Default landing for most laptops. - **768–1023px (tablet)** — single-column chat; drawers slide in as right-edge sheets (≈420px wide). Sidebar is a sheet from left. - **<768px (mobile web fallback)** — degrades to iPhone-canonical single-column with full-screen sheets. Banner: "CocotteAI is better on iPhone — open in app?" with deeplink. Not a primary supported surface; exists so push-notification deeplinks always resolve. ### Desktop-first chrome ``` ┌──────────────────────────────────────────────────────────────────────────────┐ │ Cocotte ai-copilot ▼ ⌘K search 💻 transquinnftw-MBP ⏻ │ 56px top bar ├────────────────┬────────────────────────────────────┬────────────────────────┤ │ Fleet │ Chat (flex) │ Drawer / ticker │ │ … │ … │ … │ ├────────────────┴────────────────────────────────────┴────────────────────────┤ │ ● connected · vps-0 · last sync 2s · 12 actions today v3.0.0 web │ 28px status └──────────────────────────────────────────────────────────────────────────────┘ ``` - Top-bar `💻 transquinnftw-MBP` is the active-device chip from G4 handoff Mode 2; click → device list dropdown. - `⏻` kill-switch glyph mirrors iOS `[⌥]` overflow's kill entry; two-step confirm modal. - Keyboard shortcuts inherit the E3 table (web uses ⌘ on Mac, Ctrl on Windows/Linux). ## Cross-cutting - **Dynamic Type** — iPad and macOS Catalyst honor iOS Dynamic Type sizes the same as iPhone (XXL truncates fleet counts to dot-only, wraps receipts at 4 lines per `chat-home.screen.md`). Web honors browser root font-size and uses CSS `clamp()` for body/heading scale; user-set 200%+ behaves like iOS XXL. - **Dark / light token inheritance** — all platforms inherit brief F tokens. Dark is default; light follows OS preference (iPadOS / macOS appearance, web `prefers-color-scheme`). Stakes colors hit WCAG AA in both modes on every surface. No platform-specific palette overrides. - **Accessibility (per X if shipped)** — VoiceOver on iPad / macOS reads the same labels as iPhone. macOS adds Full Keyboard Access focus rings on all interactive controls. Web meets WCAG 2.2 AA: visible focus rings (2px accent), `aria-live=polite` for receipt arrivals, `aria-live=assertive` for degradation banners and kill-switch, all approval-card buttons reachable by tab order in card-natural reading order. Reduced-motion across platforms replaces stream-fade with cross-fade and removes hover-lift. ## States - **Orientation change (iPad)** — landscape↔portrait animates the drawer column out (slide-right) or in (slide-left) over 240ms; chat reflows underneath. Persistent-drawer pin state remembered per orientation. - **Hover vs no-hover** — `@media (hover: hover)` gates trackpad hover lifts and `[•••]` overflow reveals. Touch-only iPads (no trackpad/pencil hover) get the iPhone interaction set with no hover decoration. - **Keyboard vs touch** — macOS and web with keyboard focus draw a 2px accent focus ring; touch focus is invisible (matches iOS). Approval cards expose `Tab` order: Edit → Approve → Set aside, mirroring left-to-right button layout. - **Split-view portrait collapse (iPad)** — entering ⅓ or Slide Over collapses to iPhone single-column; pinned drawer becomes a queued sheet that opens on next drawer trigger, not auto-shown. - **Web mobile fallback (<768px)** — single-column, full-screen sheets, banner promoting iOS app, all touch gestures from iPhone canonical preserved (right-swipe approve, left-swipe set aside). - **Window resize across breakpoint (web)** — column count animates in/out over 200ms; pinned drawer survives; ticker collapses to a `[≣ activity]` button on <1440px and re-expands on widen. - **Notification chase landing (web)** — when a push is acted on web (G4 Mode 3), the relevant approval card scrolls into view and pulses the stakes band for 600ms. ## Edge cases - **iPad with Magic Keyboard attached** — E3 keyboard shortcut table becomes available on iPad too (gate behind `UIKeyCommand`). ⌘. kill-switch confirm works; ⌘, opens settings sheet. - **iPad Stage Manager floating windows** — treat each window as its own viewport; persistent-drawer pin is per-window. Avoid global modals; sheets are window-scoped. - **macOS multiple windows** — each window holds its own chat/drawer/ticker state but shares one platform.api session and one fleet. Kill-switch is global (one confirm affects all windows). - **Web in a background tab when degradation banner fires** — title-bar badge updates with stakes glyph; favicon swaps to high-stakes variant; no sound unless user-enabled. - **Web with no WebSocket (corporate proxy)** — falls back to long-poll on platform.api every 8s; status strip shows "● polling" instead of "● connected". - **Cursor-only iPad (trackpad, no touch)** — right-swipe approve gesture is augmented by the hover `[•••]` overflow; both paths land on the same audit row. - **Mobile web user lands on a deeplink to a drawer that requires camera** — graceful: shows the drawer in read-only with a "continue on iPhone" banner; deeplink survives the handoff. - **macOS Catalyst on a Mac without notch / different safe areas** — bottom status bar replaces iOS home indicator; layout never reserves an iPhone-only safe inset on mac. ## Related - [Brief E](./E-cross-platform.brief.md) §E2 / §E3 / §E4 — the parent variant brief this screen instantiates. - [Brief A](./A-chat-surface.brief.md) — chat surface contract inherited by every platform. - [Brief B](./B-drawers.brief.md) — drawer pattern; iPad makes them persistent, others keep full-screen. - [Brief G](./G-web-surfaces.brief.md) — web FE infrastructure (vps-0, React 19, ai.cocotte.maison) that E4 ships on. - [Brief F](./00-system-visual-system.md) — tokens, motion, stakes colors that inherit unchanged across platforms. - [`chat-home.screen.md`](./chat-home.screen.md) — iPhone canonical adapted here. - [`cross-device-handoff.flow.md`](./cross-device-handoff.flow.md) — Mode 1/2/3 handoff between phone and web/laptop (G4).