diff --git a/.omo/evidence/v12-full-e2e.txt b/.omo/evidence/v12-full-e2e.txt
new file mode 100644
index 0000000..3e82b9c
--- /dev/null
+++ b/.omo/evidence/v12-full-e2e.txt
@@ -0,0 +1,101 @@
+[WebServer] $ node ./scripts/generate-docs-content.mjs
+[WebServer] Docs content already current with 20 HTML-compiled docs
+[WebServer] $ NODE_OPTIONS=--no-deprecation next build
+[WebServer] ▲ Next.js 16.2.9 (Turbopack)
+[WebServer]
+[WebServer] Creating an optimized production build ...
+[WebServer] ✓ Compiled successfully in 870ms
+[WebServer] Running TypeScript ...
+[WebServer] Finished TypeScript in 1715ms ...
+[WebServer] Collecting page data using 13 workers ...
+[WebServer] Generating static pages using 13 workers (0/11) ...
+[WebServer] Generating static pages using 13 workers (2/11)
+[WebServer] Generating static pages using 13 workers (5/11)
+[WebServer] Generating static pages using 13 workers (8/11)
+[WebServer] ✓ Generating static pages using 13 workers (11/11) in 650ms
+[WebServer] Finalizing page optimization ...
+[WebServer]
+[WebServer] Route (app)
+[WebServer] ┌ ○ /
+[WebServer] ├ ○ /_not-found
+[WebServer] ├ ƒ /api/github-stars
+[WebServer] ├ ○ /apple-icon.png
+[WebServer] ├ ○ /docs
+[WebServer] ├ ○ /icon.svg
+[WebServer] ├ ○ /manifest.webmanifest
+[WebServer] ├ ○ /opengraph-image
+[WebServer] ├ ○ /robots.txt
+[WebServer] ├ ○ /sitemap.xml
+[WebServer] └ ○ /twitter-image
+[WebServer]
+[WebServer]
+[WebServer] ○ (Static) prerendered as static content
+[WebServer] ƒ (Dynamic) server-rendered on demand
+[WebServer]
+[WebServer] $ NODE_OPTIONS=--no-deprecation next start
+[WebServer] ▲ Next.js 16.2.9
+[WebServer] - Local: http://localhost:50813
+[WebServer] - Network: http://192.168.0.3:50813
+[WebServer] ✓ Ready in 56ms
+
+Running 57 tests using 1 worker
+
+ ✓ 1 [chromium] › e2e/docs.spec.ts:15:3 › docs page — structure › responds 200 (17ms)
+ ✓ 2 [chromium] › e2e/docs.spec.ts:20:3 › docs page — structure › has exactly one h1 (107ms)
+ ✓ 3 [chromium] › e2e/docs.spec.ts:25:3 › docs page — structure › renders every section as a visible element carrying its id + title (150ms)
+ ✓ 4 [chromium] › e2e/docs.spec.ts:35:3 › docs page — structure › nav lists every section title as links or buttons (160ms)
+ ✓ 5 [chromium] › e2e/docs.spec.ts:46:3 › docs page — structure › documents lazycodex-ai as the npm install alias (118ms)
+ ✓ 6 [chromium] › e2e/docs.spec.ts:63:3 › docs page — structure › documents skills and built-in workflow usage (165ms)
+ ✓ 7 [chromium] › e2e/docs.spec.ts:80:3 › docs page — structure › orders Skills immediately after Commands and before Concepts (0ms)
+ ✓ 8 [chromium] › e2e/docs.spec.ts:91:3 › docs page — navigation › clicking the $ulw-loop nav entry jumps to that section (156ms)
+ ✓ 9 [chromium] › e2e/docs.spec.ts:106:3 › docs page — no-JS SSR › server-renders every section heading without JavaScript (149ms)
+ ✓ 10 [chromium] › e2e/github-stars.spec.ts:21:3 › github stars API › responds with a numeric live star count (167ms)
+ ✓ 11 [chromium] › e2e/github-stars.spec.ts:37:3 › github stars live source parsing › uses GH_TOKEN when GITHUB_TOKEN is absent (2ms)
+ ✓ 12 [chromium] › e2e/github-stars.spec.ts:63:3 › github stars live source parsing › falls back to Shields when GitHub rejects the request (0ms)
+ ✓ 13 [chromium] › e2e/github-stars.spec.ts:87:3 › github stars live source parsing › parses Shields comma and compact star payloads (0ms)
+ ✓ 14 [chromium] › e2e/github-stars.spec.ts:93:3 › github stars live source parsing › caches the non-zero fallback instead of serving a zero-star shell (0ms)
+ ✓ 15 [chromium] › e2e/github-stars.spec.ts:103:3 › github stars live source parsing › rejects zero-star upstream payloads as stale or broken source data (0ms)
+ ✓ 16 [chromium] › e2e/home.spec.ts:17:3 › home page — content › renders the wordmark, hero copy, and footer (102ms)
+ ✓ 17 [chromium] › e2e/home.spec.ts:37:3 › home page — content › does not show launch gating copy (93ms)
+ ✓ 18 [chromium] › e2e/home.spec.ts:44:3 › home page — content › has a single h1 and no broken landmarks (94ms)
+ ✓ 19 [chromium] › e2e/home.spec.ts:52:3 › home page — content › skip-link is hidden until focused (112ms)
+ ✓ 20 [chromium] › e2e/landing-sections.spec.ts:20:3 › team mode section › renders the grounded team mode copy (120ms)
+ ✓ 21 [chromium] › e2e/landing-sections.spec.ts:41:3 › ulw-research section › renders the grounded ulw-research copy (117ms)
+ ✓ 22 [chromium] › e2e/landing-sections.spec.ts:56:3 › information architecture › keeps the planned section order (553ms)
+ ✓ 23 [chromium] › e2e/landing.spec.ts:15:3 › landing page — hero › has exactly one h1 reading the wordmark (94ms)
+ ✓ 24 [chromium] › e2e/landing.spec.ts:23:3 › landing page — hero › shows the eyebrow and both hero lines (102ms)
+ ✓ 25 [chromium] › e2e/landing.spec.ts:41:3 › landing page — install + commands › shows the install command and a copy button (100ms)
+ ✓ 26 [chromium] › e2e/landing.spec.ts:51:3 › landing page — install + commands › renders every command with its name and syntax (99ms)
+ ✓ 27 [chromium] › e2e/landing.spec.ts:59:3 › landing page — install + commands › feature workflow guidance keeps the three command pillars first (100ms)
+ ✓ 28 [chromium] › e2e/landing.spec.ts:70:3 › landing page — install + commands › places skill coverage before the concept section (104ms)
+ ✓ 29 [chromium] › e2e/landing.spec.ts:87:3 › landing page — links + footer › github stars pill links to the stargazers url with a count (96ms)
+ ✓ 30 [chromium] › e2e/landing.spec.ts:96:3 › landing page — links + footer › updates the github stars pill from the live API (93ms)
+ ✓ 31 [chromium] › e2e/landing.spec.ts:104:3 › landing page — links + footer › has a Docs link pointing at /docs (97ms)
+ ✓ 32 [chromium] › e2e/landing.spec.ts:111:3 › landing page — links + footer › links to OmO and shows lazycodex.ai (96ms)
+ ✓ 33 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at mobile-small (360×640) (803ms)
+ ✓ 34 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at mobile-iphone-se (375×667) (818ms)
+ ✓ 35 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at mobile-iphone-14 (390×844) (784ms)
+ ✓ 36 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at mobile-large-android (412×915) (791ms)
+ ✓ 37 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at tablet-ipad-portrait (768×1024) (824ms)
+ ✓ 38 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at tablet-ipad-landscape (1024×768) (783ms)
+ ✓ 39 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at tablet-ipad-pro-portrait (1024×1366) (793ms)
+ ✓ 40 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at desktop-laptop (1280×800) (795ms)
+ ✓ 41 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at desktop-fullhd (1440×900) (797ms)
+ ✓ 42 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at desktop-wide (1536×864) (829ms)
+ ✓ 43 [chromium] › e2e/responsive.spec.ts:37:3 › @responsive renders correctly at desktop-ultrawide (1920×1080) (830ms)
+ ✓ 44 [chromium] › e2e/responsive.spec.ts:81:1 › @responsive iPhone-13 device profile (Playwright preset) (766ms)
+ ✓ 45 [chromium] › e2e/responsive.spec.ts:98:1 › @responsive iPad-Pro device profile (Playwright preset) (769ms)
+ ✓ 46 [chromium] › e2e/seo.spec.ts:25:3 › site SEO + metadata › has a unique
, description, canonical, lang, viewport (109ms)
+ ✓ 47 [chromium] › e2e/seo.spec.ts:52:3 › site SEO + metadata › has OpenGraph and Twitter card tags (102ms)
+ ✓ 48 [chromium] › e2e/seo.spec.ts:77:3 › site SEO + metadata › has JSON-LD SoftwareApplication structured data (94ms)
+ ✓ 49 [chromium] › e2e/seo.spec.ts:87:3 › site SEO + metadata › /robots.txt and /sitemap.xml are reachable (7ms)
+ ✓ 50 [chromium] › e2e/seo.spec.ts:101:3 › site SEO + metadata › /docs route is reachable (7ms)
+ ✓ 51 [chromium] › e2e/seo.spec.ts:106:3 › site SEO + metadata › /manifest.webmanifest is reachable and valid (3ms)
+ ✓ 52 [chromium] › e2e/seo.spec.ts:114:3 › site SEO + metadata › opengraph image and twitter image render as PNGs (6ms)
+ ✓ 53 [chromium] › e2e/seo.spec.ts:135:3 › site SEO + metadata › serves the unified LazyCodex favicon assets (98ms)
+ ✓ 54 [chromium] › e2e/ulw-demo.spec.ts:35:3 › ulw demo — chat replay @happy › one ask, then the run appends beneath it (6.1s)
+ ✓ 55 [chromium] › e2e/ulw-demo.spec.ts:78:3 › ulw demo — chat replay @happy › walks the whole run to the checkpoint, then loops (46.9s)
+ ✓ 56 [chromium] › e2e/ulw-demo.spec.ts:99:3 › ulw demo — reduced motion + mobile @edge › reduced motion shows the completed run statically (3.1s)
+ ✓ 57 [chromium] › e2e/ulw-demo.spec.ts:117:3 › ulw demo — reduced motion + mobile @edge › no horizontal overflow at 390x844 and the sidebar collapses (2.0s)
+
+ 57 passed (1.3m)
diff --git a/.omo/evidence/v12-lighthouse.txt b/.omo/evidence/v12-lighthouse.txt
new file mode 100644
index 0000000..c7ef0c1
--- /dev/null
+++ b/.omo/evidence/v12-lighthouse.txt
@@ -0,0 +1,60 @@
+[WebServer] $ node ./scripts/generate-docs-content.mjs
+[WebServer] Docs content already current with 20 HTML-compiled docs
+[WebServer] $ NODE_OPTIONS=--no-deprecation next build
+[WebServer] ▲ Next.js 16.2.9 (Turbopack)
+[WebServer]
+[WebServer] Creating an optimized production build ...
+[WebServer] ✓ Compiled successfully in 929ms
+[WebServer] Running TypeScript ...
+[WebServer] Finished TypeScript in 1830ms ...
+[WebServer] Collecting page data using 13 workers ...
+[WebServer] Generating static pages using 13 workers (0/11) ...
+[WebServer] Generating static pages using 13 workers (2/11)
+[WebServer] Generating static pages using 13 workers (5/11)
+[WebServer] Generating static pages using 13 workers (8/11)
+[WebServer] ✓ Generating static pages using 13 workers (11/11) in 627ms
+[WebServer] Finalizing page optimization ...
+[WebServer]
+[WebServer] Route (app)
+[WebServer] ┌ ○ /
+[WebServer] ├ ○ /_not-found
+[WebServer] ├ ƒ /api/github-stars
+[WebServer] ├ ○ /apple-icon.png
+[WebServer] ├ ○ /docs
+[WebServer] ├ ○ /icon.svg
+[WebServer] ├ ○ /manifest.webmanifest
+[WebServer] ├ ○ /opengraph-image
+[WebServer] ├ ○ /robots.txt
+[WebServer] ├ ○ /sitemap.xml
+[WebServer] └ ○ /twitter-image
+[WebServer]
+[WebServer]
+[WebServer] ○ (Static) prerendered as static content
+[WebServer] ƒ (Dynamic) server-rendered on demand
+[WebServer]
+[WebServer] $ NODE_OPTIONS=--no-deprecation next start
+[WebServer] ▲ Next.js 16.2.9
+[WebServer] - Local: http://localhost:51369
+[WebServer] - Network: http://192.168.0.3:51369
+[WebServer] ✓ Ready in 65ms
+
+Running 2 tests using 1 worker
+
+[Lighthouse mobile] url=http://127.0.0.1:51369 perf=100 a11y=100 bp=100 seo=100
+[Lighthouse mobile] Failing audits:
+ - unused-javascript: score=0.5 (Reduce unused JavaScript)
+ - bf-cache: score=0 (Page prevented back/forward cache restoration)
+ - legacy-javascript-insight: score=0.5 (Legacy JavaScript)
+ - network-dependency-tree-insight: score=0 (Network dependency tree)
+ - render-blocking-insight: score=0.5 (Render-blocking requests)
+ ✓ 1 [chromium] › e2e/lighthouse.spec.ts:220:3 › @lighthouse — Lighthouse 100/100/100/100 (Playwright Chrome + CDP) › mobile preset hits 100 in every category (16.5s)
+[Lighthouse desktop] url=http://127.0.0.1:51369 perf=100 a11y=100 bp=100 seo=100
+[Lighthouse desktop] Failing audits:
+ - unused-javascript: score=0.5 (Reduce unused JavaScript)
+ - bf-cache: score=0 (Page prevented back/forward cache restoration)
+ - legacy-javascript-insight: score=0.5 (Legacy JavaScript)
+ - network-dependency-tree-insight: score=0 (Network dependency tree)
+ - render-blocking-insight: score=0.5 (Render-blocking requests)
+ ✓ 2 [chromium] › e2e/lighthouse.spec.ts:226:3 › @lighthouse — Lighthouse 100/100/100/100 (Playwright Chrome + CDP) › desktop preset hits 100 in every category (16.0s)
+
+ 2 passed (39.0s)
diff --git a/.omo/evidence/v12-mobile-green.txt b/.omo/evidence/v12-mobile-green.txt
new file mode 100644
index 0000000..64ade40
--- /dev/null
+++ b/.omo/evidence/v12-mobile-green.txt
@@ -0,0 +1,48 @@
+[WebServer] $ node ./scripts/generate-docs-content.mjs
+[WebServer] Docs content already current with 20 HTML-compiled docs
+[WebServer] $ NODE_OPTIONS=--no-deprecation next build
+[WebServer] ▲ Next.js 16.2.9 (Turbopack)
+[WebServer]
+[WebServer] Creating an optimized production build ...
+[WebServer] ✓ Compiled successfully in 1017ms
+[WebServer] Running TypeScript ...
+[WebServer] Finished TypeScript in 2.5s ...
+[WebServer] Collecting page data using 13 workers ...
+[WebServer] Generating static pages using 13 workers (0/11) ...
+[WebServer] Generating static pages using 13 workers (2/11)
+[WebServer] Generating static pages using 13 workers (5/11)
+[WebServer] Generating static pages using 13 workers (8/11)
+[WebServer] ✓ Generating static pages using 13 workers (11/11) in 800ms
+[WebServer] Finalizing page optimization ...
+[WebServer]
+[WebServer] Route (app)
+[WebServer] ┌ ○ /
+[WebServer] ├ ○ /_not-found
+[WebServer] ├ ƒ /api/github-stars
+[WebServer] ├ ○ /apple-icon.png
+[WebServer] ├ ○ /docs
+[WebServer] ├ ○ /icon.svg
+[WebServer] ├ ○ /manifest.webmanifest
+[WebServer] ├ ○ /opengraph-image
+[WebServer] ├ ○ /robots.txt
+[WebServer] ├ ○ /sitemap.xml
+[WebServer] └ ○ /twitter-image
+[WebServer]
+[WebServer]
+[WebServer] ○ (Static) prerendered as static content
+[WebServer] ƒ (Dynamic) server-rendered on demand
+[WebServer]
+[WebServer] $ NODE_OPTIONS=--no-deprecation next start
+[WebServer] ▲ Next.js 16.2.9
+[WebServer] - Local: http://localhost:50094
+[WebServer] - Network: http://192.168.0.3:50094
+[WebServer] ✓ Ready in 70ms
+
+Running 4 tests using 1 worker
+
+ ✓ 1 [chromium] › e2e/ulw-demo.spec.ts:35:3 › ulw demo — chat replay @happy › one ask, then the run appends beneath it (6.2s)
+ ✓ 2 [chromium] › e2e/ulw-demo.spec.ts:78:3 › ulw demo — chat replay @happy › walks the whole run to the checkpoint, then loops (47.3s)
+ ✓ 3 [chromium] › e2e/ulw-demo.spec.ts:99:3 › ulw demo — reduced motion + mobile @edge › reduced motion shows the completed run statically (3.1s)
+ ✓ 4 [chromium] › e2e/ulw-demo.spec.ts:117:3 › ulw demo — reduced motion + mobile @edge › no horizontal overflow at 390x844 and the sidebar collapses (2.0s)
+
+ 4 passed (1.1m)
diff --git a/.omo/evidence/v12-mobile-red.txt b/.omo/evidence/v12-mobile-red.txt
new file mode 100644
index 0000000..c4bf237
--- /dev/null
+++ b/.omo/evidence/v12-mobile-red.txt
@@ -0,0 +1,74 @@
+[WebServer] $ node ./scripts/generate-docs-content.mjs
+[WebServer] Docs content already current with 20 HTML-compiled docs
+[WebServer] $ NODE_OPTIONS=--no-deprecation next build
+[WebServer] ▲ Next.js 16.2.9 (Turbopack)
+[WebServer]
+[WebServer] Creating an optimized production build ...
+[WebServer] ✓ Compiled successfully in 967ms
+[WebServer] Running TypeScript ...
+[WebServer] Finished TypeScript in 1448ms ...
+[WebServer] Collecting page data using 13 workers ...
+[WebServer] Generating static pages using 13 workers (0/11) ...
+[WebServer] Generating static pages using 13 workers (2/11)
+[WebServer] Generating static pages using 13 workers (5/11)
+[WebServer] Generating static pages using 13 workers (8/11)
+[WebServer] ✓ Generating static pages using 13 workers (11/11) in 603ms
+[WebServer] Finalizing page optimization ...
+[WebServer]
+[WebServer] Route (app)
+[WebServer] ┌ ○ /
+[WebServer] ├ ○ /_not-found
+[WebServer] ├ ƒ /api/github-stars
+[WebServer] ├ ○ /apple-icon.png
+[WebServer] ├ ○ /docs
+[WebServer] ├ ○ /icon.svg
+[WebServer] ├ ○ /manifest.webmanifest
+[WebServer] ├ ○ /opengraph-image
+[WebServer] ├ ○ /robots.txt
+[WebServer] ├ ○ /sitemap.xml
+[WebServer] └ ○ /twitter-image
+[WebServer]
+[WebServer]
+[WebServer] ○ (Static) prerendered as static content
+[WebServer] ƒ (Dynamic) server-rendered on demand
+[WebServer]
+[WebServer] $ NODE_OPTIONS=--no-deprecation next start
+[WebServer] ▲ Next.js 16.2.9
+[WebServer] - Local: http://localhost:64926
+[WebServer] - Network: http://192.168.0.3:64926
+[WebServer] ✓ Ready in 69ms
+
+Running 1 test using 1 worker
+
+ ✘ 1 [chromium] › e2e/ulw-demo.spec.ts:117:3 › ulw demo — reduced motion + mobile @edge › no horizontal overflow at 390x844 and the sidebar collapses (5.3s)
+
+
+ 1) [chromium] › e2e/ulw-demo.spec.ts:117:3 › ulw demo — reduced motion + mobile @edge › no horizontal overflow at 390x844 and the sidebar collapses
+
+ Error: expect(locator).toBeHidden() failed
+
+ Locator: locator('#ulw-demo').locator('.ulw-side')
+ Expected: hidden
+ Received: visible
+ Timeout: 5000ms
+
+ Call log:
+ - Expect "toBeHidden" with timeout 5000ms
+ - waiting for locator('#ulw-demo').locator('.ulw-side')
+ 14 × locator resolved to
+ - unexpected value "visible"
+
+
+ 124 | // the transcript owns the fixed window box.
+ 125 | await expect(page.getByRole("navigation", { name: "Sessions" })).toBeHidden()
+ > 126 | await expect(demo.locator(".ulw-side")).toBeHidden()
+ | ^
+ 127 |
+ 128 | // The replay must be SEEN, not merely attached: the opening ask is
+ 129 | // visible and the transcript pane occupies most of the 560px window.
+ at /Users/yeongyu/local-workspaces/lazycodex-wt/code-yeongyu/light-greeny-redesign-interactive-demo/packages/web/e2e/ulw-demo.spec.ts:126:45
+
+ Error Context: test-results/ulw-demo-ulw-demo-—-reduce-e033a-4-and-the-sidebar-collapses-chromium/error-context.md
+
+ 1 failed
+ [chromium] › e2e/ulw-demo.spec.ts:117:3 › ulw demo — reduced motion + mobile @edge › no horizontal overflow at 390x844 and the sidebar collapses
diff --git a/.omo/evidence/v12-mobile/after-demo-m375.png b/.omo/evidence/v12-mobile/after-demo-m375.png
new file mode 100644
index 0000000..237c410
Binary files /dev/null and b/.omo/evidence/v12-mobile/after-demo-m375.png differ
diff --git a/.omo/evidence/v12-mobile/after-demo-m390.png b/.omo/evidence/v12-mobile/after-demo-m390.png
new file mode 100644
index 0000000..1ae53a0
Binary files /dev/null and b/.omo/evidence/v12-mobile/after-demo-m390.png differ
diff --git a/.omo/evidence/v12-mobile/after-demo-t768.png b/.omo/evidence/v12-mobile/after-demo-t768.png
new file mode 100644
index 0000000..1f06197
Binary files /dev/null and b/.omo/evidence/v12-mobile/after-demo-t768.png differ
diff --git a/.omo/evidence/v12-mobile/demo-m375.png b/.omo/evidence/v12-mobile/demo-m375.png
new file mode 100644
index 0000000..83e074a
Binary files /dev/null and b/.omo/evidence/v12-mobile/demo-m375.png differ
diff --git a/.omo/evidence/v12-mobile/demo-t768.png b/.omo/evidence/v12-mobile/demo-t768.png
new file mode 100644
index 0000000..c2d9087
Binary files /dev/null and b/.omo/evidence/v12-mobile/demo-t768.png differ
diff --git a/.omo/evidence/v12-mobile/docs-m375-full.png b/.omo/evidence/v12-mobile/docs-m375-full.png
new file mode 100644
index 0000000..7d5701d
Binary files /dev/null and b/.omo/evidence/v12-mobile/docs-m375-full.png differ
diff --git a/.omo/evidence/v12-mobile/docs-t768-full.png b/.omo/evidence/v12-mobile/docs-t768-full.png
new file mode 100644
index 0000000..50ffd1c
Binary files /dev/null and b/.omo/evidence/v12-mobile/docs-t768-full.png differ
diff --git a/.omo/evidence/v12-mobile/landing-m375-full.png b/.omo/evidence/v12-mobile/landing-m375-full.png
new file mode 100644
index 0000000..0c3fb62
Binary files /dev/null and b/.omo/evidence/v12-mobile/landing-m375-full.png differ
diff --git a/.omo/evidence/v12-mobile/landing-t768-full.png b/.omo/evidence/v12-mobile/landing-t768-full.png
new file mode 100644
index 0000000..4dd00c8
Binary files /dev/null and b/.omo/evidence/v12-mobile/landing-t768-full.png differ
diff --git a/.omo/evidence/v12-mobile/s0-header.png b/.omo/evidence/v12-mobile/s0-header.png
new file mode 100644
index 0000000..fdbc007
Binary files /dev/null and b/.omo/evidence/v12-mobile/s0-header.png differ
diff --git a/.omo/evidence/v12-mobile/s1.png b/.omo/evidence/v12-mobile/s1.png
new file mode 100644
index 0000000..51fe092
Binary files /dev/null and b/.omo/evidence/v12-mobile/s1.png differ
diff --git a/.omo/evidence/v12-mobile/s10.png b/.omo/evidence/v12-mobile/s10.png
new file mode 100644
index 0000000..77a6e60
Binary files /dev/null and b/.omo/evidence/v12-mobile/s10.png differ
diff --git a/.omo/evidence/v12-mobile/s2.png b/.omo/evidence/v12-mobile/s2.png
new file mode 100644
index 0000000..c37fd8e
Binary files /dev/null and b/.omo/evidence/v12-mobile/s2.png differ
diff --git a/.omo/evidence/v12-mobile/s3.png b/.omo/evidence/v12-mobile/s3.png
new file mode 100644
index 0000000..14f004e
Binary files /dev/null and b/.omo/evidence/v12-mobile/s3.png differ
diff --git a/.omo/evidence/v12-mobile/s4.png b/.omo/evidence/v12-mobile/s4.png
new file mode 100644
index 0000000..e840479
Binary files /dev/null and b/.omo/evidence/v12-mobile/s4.png differ
diff --git a/.omo/evidence/v12-mobile/s5.png b/.omo/evidence/v12-mobile/s5.png
new file mode 100644
index 0000000..ad1d6ce
Binary files /dev/null and b/.omo/evidence/v12-mobile/s5.png differ
diff --git a/.omo/evidence/v12-mobile/s6.png b/.omo/evidence/v12-mobile/s6.png
new file mode 100644
index 0000000..2fe6654
Binary files /dev/null and b/.omo/evidence/v12-mobile/s6.png differ
diff --git a/.omo/evidence/v12-mobile/s7.png b/.omo/evidence/v12-mobile/s7.png
new file mode 100644
index 0000000..dcd2148
Binary files /dev/null and b/.omo/evidence/v12-mobile/s7.png differ
diff --git a/.omo/evidence/v12-mobile/s8.png b/.omo/evidence/v12-mobile/s8.png
new file mode 100644
index 0000000..9899c78
Binary files /dev/null and b/.omo/evidence/v12-mobile/s8.png differ
diff --git a/.omo/evidence/v12-mobile/s9.png b/.omo/evidence/v12-mobile/s9.png
new file mode 100644
index 0000000..1d3f9f3
Binary files /dev/null and b/.omo/evidence/v12-mobile/s9.png differ
diff --git a/.omo/evidence/v12-mobile/s99-footer.png b/.omo/evidence/v12-mobile/s99-footer.png
new file mode 100644
index 0000000..f5cfae9
Binary files /dev/null and b/.omo/evidence/v12-mobile/s99-footer.png differ
diff --git a/packages/web/DESIGN.md b/packages/web/DESIGN.md
index 48a151f..5793cdf 100644
--- a/packages/web/DESIGN.md
+++ b/packages/web/DESIGN.md
@@ -256,7 +256,8 @@ All spacing resolves to a 4px rhythm. Existing Tailwind values map to the same r
so content is readable with JS disabled.
- **Layout stability**: `.ulw-window` is a FIXED 680px box (560px at ≤ 768px); the appending
transcript scrolls internally so the outer box never changes (e2e asserts ≤ 1px drift while
- entries append); panes stack single-column at ≤ 768px.
+ entries append). At ≤ 768px the session sidebar AND the right rail hide (a stacked rail would
+ starve the transcript row to 0px inside the fixed box) — the transcript owns the window.
- **Integrity**: live DOM only — no raster screenshot, `
`, or `background-image` may stand in
for window content.
- **Roster glyph colors**: the subagent glyph squares use the per-theme `--lane-*` identity hues
diff --git a/packages/web/app/styles/ulw-demo-panel.css b/packages/web/app/styles/ulw-demo-panel.css
index 078074f..43a0acb 100644
--- a/packages/web/app/styles/ulw-demo-panel.css
+++ b/packages/web/app/styles/ulw-demo-panel.css
@@ -129,9 +129,12 @@
}
@media (max-width: 768px) {
+ /* The window keeps its fixed height on phones, so the rail cannot fit
+ beneath the transcript inside the box: as a second implicit grid row
+ it starves the transcript row to 0px. The rail hides and the replay
+ owns the window (the remaining auto row stretches to fill). */
.ulw-side {
- border-left: none;
- border-top: 1px solid var(--codex-window-border);
+ display: none;
}
}
diff --git a/packages/web/e2e/ulw-demo.spec.ts b/packages/web/e2e/ulw-demo.spec.ts
index b178791..4a8b31b 100644
--- a/packages/web/e2e/ulw-demo.spec.ts
+++ b/packages/web/e2e/ulw-demo.spec.ts
@@ -120,8 +120,16 @@ test.describe("ulw demo — reduced motion + mobile @edge", () => {
const demo = page.locator("#ulw-demo")
await demo.locator(".ulw-window").scrollIntoViewIfNeeded()
- // The session sidebar is hidden at mobile widths, like the real app.
+ // The session sidebar AND the right rail are hidden at mobile widths;
+ // the transcript owns the fixed window box.
await expect(page.getByRole("navigation", { name: "Sessions" })).toBeHidden()
+ await expect(demo.locator(".ulw-side")).toBeHidden()
+
+ // The replay must be SEEN, not merely attached: the opening ask is
+ // visible and the transcript pane occupies most of the 560px window.
+ await expect(demo.locator(".ulw-app-user")).toBeVisible()
+ const transcriptBox = await demo.locator(".ulw-app-transcript").boundingBox()
+ expect(transcriptBox?.height ?? 0).toBeGreaterThan(250)
// The replay keeps appending; dynamic entries must not overflow.
const entries = demo.locator(".ulw-entry")