diff --git a/lyra/web/static/index.html b/lyra/web/static/index.html index 918f5a6..a0adb37 100644 --- a/lyra/web/static/index.html +++ b/lyra/web/static/index.html @@ -41,9 +41,7 @@

Actions

- - @@ -116,6 +114,14 @@ + + + @@ -523,6 +529,8 @@ // iOS pans the visual viewport when the keyboard opens; follow its top // edge so the pinned #chat sits exactly in the visible area. root.setProperty("--app-offset", off + "px"); + // Keyboard open ⇒ hide the bottom tab bar so the input pins to the keyboard. + document.body.classList.toggle("kb", (window.innerHeight - h) > 150); } // Re-measure across the keyboard animation: iOS reports a stale (too-short) // height mid-animation, so sample a few times until it settles. @@ -568,6 +576,7 @@ hamburgerMenu.addEventListener("click", toggleMobileMenu); mobileMenuOverlay.addEventListener("click", closeMobileMenu); + document.getElementById("moreTab").addEventListener("click", toggleMobileMenu); // Sync mobile menu controls with desktop const mobileMode = document.getElementById("mobileMode"); @@ -1011,15 +1020,9 @@ document.getElementById("mobileFullLogBtn").addEventListener("click", () => { closeMobileMenu(); window.location.href = "/logs"; }); - document.getElementById("mobileMindBtn").addEventListener("click", () => { - closeMobileMenu(); window.location.href = "/self"; - }); document.getElementById("mobileJournalBtn").addEventListener("click", () => { closeMobileMenu(); window.location.href = "/journal"; }); - document.getElementById("mobileHandsBtn").addEventListener("click", () => { - closeMobileMenu(); window.location.href = "/hands"; - }); // Connect to the global live log on page load. connectThinkingStream(); diff --git a/lyra/web/static/style.css b/lyra/web/static/style.css index 535a758..9c85713 100644 --- a/lyra/web/static/style.css +++ b/lyra/web/static/style.css @@ -677,6 +677,9 @@ select:hover { /* Wordmark + status dot — shown only in the mobile header (media query below) */ .brand, .brand-dot { display: none; } +/* Bottom tab bar — mobile only (shown in the media query) */ +#tabbar { display: none; } + /* Hamburger Menu */ .hamburger-menu { display: none; @@ -784,21 +787,26 @@ select:hover { @media screen and (max-width: 768px) { body { padding: 0; + background: var(--bg-elev); /* matches the tab bar so any strip below #chat is seamless */ } #chat { position: fixed; - top: 0; - left: 0; - right: 0; + top: 0; left: 0; right: 0; width: 100%; - /* Height follows the *visible* viewport (above the keyboard); offsetTop - shift is applied via JS transform so it tracks iOS's viewport panning. */ - height: var(--app-height, 100dvh); - transform: translateY(var(--app-offset, 0px)); + height: 100dvh; /* the *visible* viewport (excludes the home-indicator zone); + overrides the base 95vh. Body bg matches the bar below it. */ + background: var(--bg-dark); border-radius: 0; border: none; } + /* Only while the keyboard is open do we follow the *visible* viewport: release + the bottom anchor and size from the top by the measured visible height. */ + body.kb #chat { + bottom: auto; + height: var(--app-height, 100dvh); + transform: translateY(var(--app-offset, 0px)); + } /* Show hamburger, hide desktop header controls */ .hamburger-menu { @@ -857,14 +865,51 @@ select:hover { font-size: 0.85rem; } - /* Input area - bigger touch targets */ + /* Input area - bigger touch targets. The tab bar owns the bottom safe-area + inset now (the input is no longer the bottom-most element). */ #input { padding: 12px; - padding-bottom: calc(12px + env(safe-area-inset-bottom)); padding-left: calc(12px + env(safe-area-inset-left)); padding-right: calc(12px + env(safe-area-inset-right)); } + /* Bottom tab bar */ + #tabbar { + display: flex; + flex: none; /* never let it be compressed/clipped by the flex column */ + border-top: 1px solid var(--border); + background: var(--bg-elev); + padding-bottom: 6px; /* 100dvh already excludes the home-indicator zone */ + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); + } + #tabbar .tab { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 3px; + padding: 7px 0 5px; + background: none; + border: none; + border-radius: 0; + color: var(--text-fade); + font-family: var(--font-console); + text-decoration: none; + -webkit-tap-highlight-color: transparent; + } + #tabbar .tab:hover { background: none; } + #tabbar .tab:active { background: var(--accent-soft); } + #tabbar .tab .ti { font-size: 1.3rem; line-height: 1; filter: grayscale(.45); } + #tabbar .tab .tl { font-size: .64rem; letter-spacing: .3px; } + #tabbar .tab.active { color: var(--accent); } + #tabbar .tab.active .ti { filter: none; } + body.kb #tabbar { display: none; } /* keyboard open ⇒ hide so input pins to keyboard */ + + /* The "More" tab is the menu trigger now — retire the hamburger. */ + .hamburger-menu { display: none !important; } + #userInput { font-size: 16px; /* Prevents zoom on iOS */ padding: 12px;