Mobile Styles Fix Implementation Plan
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: Fix five mobile layout bugs: the ~48px gap between toolbar and nav drawer, content pushed rightward, iOS viewport height, missing body scroll lock, and unresponsive about-page grid.
Architecture: Five targeted surgical edits across four files plus one new CSS file. No refactoring. Each fix is independent and can be verified in isolation.
Tech Stack: Astro 5, vanilla CSS, TypeScript (browser), Vitest for unit tests (CSS changes are visual-only — no new unit tests needed; run existing tests to confirm nothing broken).
Task 1: Fix position conflict in ProjectTree.css
Root cause: #site-nav { position: relative } in ProjectTree.css loads after BaseLayout.css in Astro’s bundle. With Astro 5’s :where() scoping, they have equal specificity — so the later position: relative overrides the mobile position: fixed. Result: drawer is in normal flow, shifted 48px too far down, and still occupies flex space.
Files:
- Modify:
app/src/components/ProjectTree/ProjectTree.css:1-8
Step 1: Make the change
In ProjectTree.css, wrap position: relative in a desktop-only media query so it never fires on mobile:
/* ---- Layout ---- */#site-nav { font-family: system-ui, -apple-system, sans-serif;}
@media (min-width: 640px) { #site-nav { position: relative; }}Step 2: Run existing tests to confirm nothing broken
just app::testExpected: all tests pass (CSS changes don’t affect unit tests).
Step 3: Commit
git add app/src/components/ProjectTree/ProjectTree.cssgit commit -m "fix: scope position:relative to desktop to fix mobile drawer gap"Task 2: Fix height: 100vh for iOS Safari
Root cause: On iOS Safari, 100vh equals the full viewport including the browser chrome (address bar). This makes #layout taller than the visible area, causing overflow and incorrect drawer heights.
Fix: Use 100svh (small viewport height — the stable visible area). Add 100vh before it as a fallback for browsers that don’t support svh units yet.
Files:
- Modify:
app/src/layouts/BaseLayout/BaseLayout.css:10
Step 1: Make the change
In BaseLayout.css, update the #layout rule:
#layout { display: flex; height: 100vh; /* fallback */ height: 100svh; /* iOS Safari: stable viewport height */ width: 100vw;}Step 2: Confirm tests pass
just app::testExpected: all tests pass.
Step 3: Commit
git add app/src/layouts/BaseLayout/BaseLayout.cssgit commit -m "fix: use 100svh for stable mobile viewport height"Task 3: Add body scroll lock when a drawer is open
Root cause: When a drawer slides in, content behind it can still be scrolled. The BaseLayout.ts drawer logic adds/removes .open but never locks the body.
Files:
- Modify:
app/src/layouts/BaseLayout/BaseLayout.ts:10-14
Step 1: Update closeAll and the open handlers in BaseLayout.ts
Locate the closeAll function and the two addEventListener click handlers. Update them so that opening a drawer sets document.body.style.overflow = 'hidden' and closeAll restores it to '':
function closeAll() { siteNav.classList.remove("open"); chatPanel.classList.remove("open"); backdrop.classList.remove("visible"); document.body.style.overflow = "";}
menuBtn.addEventListener("click", () => { const willOpen = !siteNav.classList.contains("open"); closeAll(); if (willOpen) { siteNav.classList.add("open"); backdrop.classList.add("visible"); document.body.style.overflow = "hidden"; }});
chatBtn.addEventListener("click", () => { const willOpen = !chatPanel.classList.contains("open"); closeAll(); if (willOpen) { chatPanel.classList.add("open"); backdrop.classList.add("visible"); document.body.style.overflow = "hidden"; }});Step 2: Confirm tests pass
just app::testExpected: all tests pass.
Step 3: Commit
git add app/src/layouts/BaseLayout/BaseLayout.tsgit commit -m "fix: lock body scroll when mobile drawer is open"Task 4: Fix about-page photo grid on mobile
Root cause: about.astro has grid-template-columns: repeat(4, 1fr) as an inline style. On small screens (< 640px), this squishes four photos into very narrow columns.
Fix: Add a <style> block in about.astro that targets the grid div and overrides to 2 columns on mobile.
Files:
- Modify:
app/src/pages/about.astro
Step 1: Add a named class to the grid div and a <style> block
In about.astro, replace the grid div’s inline style with a class, and add a scoped <style> block at the bottom of the file:
<div class="about-photos"> <Image src={meMemoji} alt="A Memoji of Thalida" style="width:100%;height:auto;border-radius:1rem;" /> <Image src={meHeadshot} alt="A headshot of Thalida" style="width:100%;height:auto;border-radius:1rem;" /> <Image src={meAvatar} alt="A cartoon avatar of Thalida" style="width:100%;height:auto;border-radius:1rem;" /> <Image src={meRainbow} alt="A rainbow themed image of Thalida" style="width:100%;height:auto;border-radius:1rem;" /></div>And add at the bottom of about.astro:
<style> .about-photos { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; margin-bottom: 1.5rem; }
@media (max-width: 639px) { .about-photos { grid-template-columns: repeat(2, 1fr); } }</style>Step 2: Confirm tests pass
just app::testExpected: all tests pass.
Step 3: Commit
git add app/src/pages/about.astrogit commit -m "fix: responsive 2-column photo grid on mobile about page"Task 5: Add basic styles for Chat panel
Root cause: Chat.astro has no associated CSS file. The chat panel slides in on mobile but its internal content (heading, inputs, messages) has no styling — inherits browser defaults only.
Files:
- Create:
app/src/components/Chat/Chat.css - Modify:
app/src/components/Chat/Chat.astro(add<style>import)
Step 1: Create Chat.css
#chat-panel { font-family: system-ui, -apple-system, sans-serif; display: flex; flex-direction: column; gap: 0.5em;}
#chat-header { display: flex; align-items: center; justify-content: space-between; margin: 0 0 0.25em;}
#chat-header h2 { margin: 0; font-size: 1.1em; letter-spacing: 0.02em;}
#chat-admin-link { font-size: 0.8em; color: #999; text-decoration: none;}
#chat-admin-link:hover { color: #333;}
#chat-owner-status,#chat-user-count { font-size: 0.8em; color: #666;}
#chat-room { display: flex; flex-direction: column; gap: 0.5em; flex: 1;}
#chat-messages { flex: 1; font-size: 0.85em;}
#chat-username-bar { display: flex; flex-direction: column; gap: 0.25em; font-size: 0.8em; color: #666;}
#chat-username-bar label { font-size: inherit;}
#chat-username { width: 100%; padding: 0.3em 0.5em; border: 1px solid #e0e0e0; border-radius: 6px; font-size: inherit; font-family: inherit;}
#chat-rename-btn { padding: 0.3em 0.6em; border: 1px solid #e0e0e0; border-radius: 6px; background: #fff; font-size: inherit; cursor: pointer;}
#chat-input { width: 100%; padding: 0.4em 0.6em; border: 1px solid #e0e0e0; border-radius: 6px; font-size: 0.85em; font-family: inherit; box-sizing: border-box;}
#chat-send { width: 100%; padding: 0.4em; margin-top: 0.25em; border: none; border-radius: 6px; background: #4338ca; color: #fff; font-size: 0.85em; cursor: pointer; font-family: inherit;}
#chat-send:hover { background: #3730a3;}Step 2: Import Chat.css in Chat.astro
Add at the bottom of Chat.astro:
<style> @import "./Chat.css";</style>Step 3: Confirm tests pass
just app::testExpected: all tests pass.
Step 4: Commit
git add app/src/components/Chat/Chat.css app/src/components/Chat/Chat.astrogit commit -m "feat: add basic styles for chat panel"Final Verification
After all tasks are complete:
just app::testExpected: all tests pass. Then do a manual visual check on mobile (browser devtools responsive mode at 375px width):
- Nav drawer slides in flush against toolbar bottom edge (no gap)
- Content viewer fills full width (not shifted right)
- Backdrop prevents body scroll when drawer open
- About page shows 2-column photo grid
- Chat panel has readable styled content