fix(landing,docs): comprehensive mobile responsive pass#41
Merged
johnnichev merged 1 commit intomainfrom Apr 6, 2026
Merged
Conversation
Fixes the catastrophic mobile layout issues reported on Galaxy S23. The
landing page was effectively unusable below ~1024px due to a combination
of bugs that all surfaced together: nav not collapsing, hero buttons
squeezed, code blocks forcing horizontal page overflow, comparison tables
spilling off the right edge, builder iframe rendering at desktop width,
eval/trace preview iframes scrolling sideways, and footer cluttered. Plus
the docs site had a broken nav icon that triggered a half-rendered state.
Root causes addressed:
1. **html, body { overflow-x: hidden }** instead of body alone — iOS
Safari and some Android browsers ignore the rule unless both have it.
Plus defensive `max-width: 100%` on img/video/iframe/table/pre.
2. **Hamburger menu** — bumped collapse breakpoint from 900px to 1024px
so Chrome's "Desktop Site" mode (~980px viewport) also collapses.
Replaced inline nav-links with a slide-down drawer triggered by an
accessible hamburger button (aria-expanded, Esc to close, focus return,
resize listener that auto-closes when going back to desktop).
3. **Hero buttons stack vertically** at <=640px. Previous flex:1 layout
crushed the pip-install button to "l sele" because three CTAs couldn't
share 360px. New layout: full-width buttons stacked vertically.
4. **Code blocks** — added `min-width: 0` to .code-frame and to all
grid-2/3/4 children. The classic flex/grid sizing trap: default
min-width: auto resolves to max-content, so long code lines forced
parents wider than the viewport. Setting min-width: 0 lets containers
shrink and the inner overflow-x: auto handles scrolling within the
code box. Smaller font/padding at <=640px.
5. **Comparison tables** — wrapped in .cmp-scroll containers with
overflow-x: auto + edge-gradient mask images so users can see there's
more content. min-width: 640px on the table forces readable column
widths. Added "scroll → for full comparison" hint at <=768px.
6. **Builder iframe** — desktop-only widget. Added .builder-mobile-fallback
card that replaces the iframe at <=768px with a "The visual builder
needs more room. Open in new tab →" CTA. Uses data-builder-iframe
attribute selector to hide the iframe specifically.
7. **Eval/trace preview iframes** — made the inner HTML files responsive
with @media (max-width: 560px): reduced padding, simplified grids
(3-col → 2-col), wrapped tables in .table-wrap with their own
horizontal scroll. Iframe height drops from 380px to 320px on mobile.
8. **Footer** — stacks vertically at <=640px with centered alignment,
smaller meta text, more breathing room.
9. **Touch-device hover guard** — single @media (hover: none) override
block at the bottom of the CSS that resets only transform/box-shadow
side of hover (not color) on touch devices. Eliminates "sticky hover"
after tap. Cleaner than wrapping 40+ individual hover rules.
Docs fixes:
10. **Removed `extra.version.provider: mike`** from mkdocs.yml — this
was fetching versions.json (which doesn't exist), causing 404s and
breaking the docs nav state.
11. **Added `extra.homepage`** pointing to QUICKSTART. The actual root
cause of the broken docs nav icon: clicking it navigated to / which
is the landing page (overwritten by the workflow), and Material's
instant-navigation could not render the landing page HTML inside the
docs shell. Now the icon goes to a real Material docs page.
12. **Replaced `docs/index.md`** JS-redirect hack with a proper Material
grid-cards welcome page. The redirect approach broke under
navigation.instant. The welcome page is what local `mkdocs serve`
shows now (production still overwrites it with the landing page).
Test plan after merge:
- Open https://selectools.dev on Galaxy S23 in normal Chrome mode
- Open in Chrome "Desktop Site" mode (this was the hidden gotcha)
- Verify hamburger menu opens/closes, Esc dismisses, anchor links work
- Verify all hero buttons are full-width and tappable
- Verify pip-install button is no longer squeezed
- Verify no horizontal page scroll on any section
- Verify code blocks scroll inside their own boxes, not the page
- Verify comparison tables scroll horizontally with edge gradient hint
- Verify builder section shows the "open in new tab" CTA, not iframe
- Verify eval/trace previews fit within iframe without page overflow
- Verify footer stacks cleanly
- Verify docs site logo click goes to QUICKSTART, not broken state
NOT in this commit (gitignored):
- .private/ URL sweep (44 replacements across 14 launch/blog files)
- .private/launch-prep/gsc-migration-checklist.md (new)
johnnichev
added a commit
that referenced
this pull request
Apr 6, 2026
Addresses the 10 issues from Galaxy S23 testing after PR #41. Critical: header still showed full nav on mobile because Chrome's "Desktop Site" mode reports a viewport of ~1280px (not ~980px as initially assumed), which exceeded the 1024px breakpoint added in PR #41. The fix is to detect touch input via `@media (pointer: coarse)`, which the Desktop Site toggle cannot override. This is the only reliable signal for "this is a touch device, no matter what the viewport pretends to be." Issues fixed: 1. **Header nav still showing on mobile** — Added @media (pointer: coarse) block that forces hamburger + drawer regardless of reported viewport. Also removes nav-hide-on-scroll on touch (issue #10): the auto-hide stays as a desktop progressive enhancement only. 2. **Hero pill grid felt templated** — Replaced 8 generic pills with a cleaner "Works with · OpenAI Anthropic Gemini Ollama" provider strip. Each provider gets a small cyan dot prefix. Removed the redundant feature pills (Multi-Agent Graphs, 50 Evaluators, etc.) since they already appear in the dedicated features section below. 3. **Supervisor agent chips broke into 3+1 layout** — Switched .sim-agents to a 2-column CSS grid with `:last-child:nth-child(odd)` selector that spans the orphaned last item across both columns. Handles 2/3/4 agent counts gracefully. 4. **"What is Selectools?" copy too dense** — Restructured into 3 short paragraphs with a visually distinct middle line listing capabilities separated by middle-dots. Removed the redundant "Unlike LangChain..." framing (the comparison tables already make this case). Closing paragraph keeps the brand voice. 5. **Code block scroll indicator** — Added a right-edge gradient mask to .code-body matching the comparison table pattern. Signals "more content this way" for horizontally-scrollable code. Mask drops on hover/focus so users see the full content when engaging. Also reduced code font slightly on mobile (12px → 11.5px) for better fit. 6. **Feature cards too tall on mobile** — Compact card layout under @media (max-width: 768px), (pointer: coarse): 28px → 20px padding, 40 → 32px icon, 32 → 14px grid gap. Cards now feel like a tight group instead of 1/3-screen blocks with awkward gaps. 7. **"Live · no server required" chip orphaned** — Moved inline with the "Visual Agent Builder" section label so it reads as a header annotation rather than a floating chip between the description and the card. 8. **Comparison table cells wrapping to 3 lines** — Bumped .cmp-table min-width from 640px to 800px so each column has ~115px (enough for "macOS desktop app" and "No (desktop only)" to fit on 1-2 lines). Added `white-space: nowrap` to .yes/.no/.mid verdict cells so 2-3 char answers never wrap awkwardly. 9. **No gap before first builder card in "Three paths"** — Added explicit margin-bottom: 64px on the section description and padding-top: 8px on the cards container. 10. **Header should always be visible** — Removed the hide-on-scroll-down behavior on touch devices (kept on desktop where it's a thoughtful progressive enhancement). On mobile the nav now stays fixed at the top throughout scrolling, which doubles as a wayfinding aid. Approach informed by /adapt and /clarify skill guidelines. The @media (pointer: coarse) pattern is the key insight from /adapt: viewport-based responsive design is fundamentally fragile because users can override it (Desktop Site mode, Reader Mode, browser zoom). Touch input is a hardware property that cannot be spoofed.
16 tasks
johnnichev
added a commit
that referenced
this pull request
Apr 6, 2026
#42) Addresses the 10 issues from Galaxy S23 testing after PR #41. Critical: header still showed full nav on mobile because Chrome's "Desktop Site" mode reports a viewport of ~1280px (not ~980px as initially assumed), which exceeded the 1024px breakpoint added in PR #41. The fix is to detect touch input via `@media (pointer: coarse)`, which the Desktop Site toggle cannot override. This is the only reliable signal for "this is a touch device, no matter what the viewport pretends to be." Issues fixed: 1. **Header nav still showing on mobile** — Added @media (pointer: coarse) block that forces hamburger + drawer regardless of reported viewport. Also removes nav-hide-on-scroll on touch (issue #10): the auto-hide stays as a desktop progressive enhancement only. 2. **Hero pill grid felt templated** — Replaced 8 generic pills with a cleaner "Works with · OpenAI Anthropic Gemini Ollama" provider strip. Each provider gets a small cyan dot prefix. Removed the redundant feature pills (Multi-Agent Graphs, 50 Evaluators, etc.) since they already appear in the dedicated features section below. 3. **Supervisor agent chips broke into 3+1 layout** — Switched .sim-agents to a 2-column CSS grid with `:last-child:nth-child(odd)` selector that spans the orphaned last item across both columns. Handles 2/3/4 agent counts gracefully. 4. **"What is Selectools?" copy too dense** — Restructured into 3 short paragraphs with a visually distinct middle line listing capabilities separated by middle-dots. Removed the redundant "Unlike LangChain..." framing (the comparison tables already make this case). Closing paragraph keeps the brand voice. 5. **Code block scroll indicator** — Added a right-edge gradient mask to .code-body matching the comparison table pattern. Signals "more content this way" for horizontally-scrollable code. Mask drops on hover/focus so users see the full content when engaging. Also reduced code font slightly on mobile (12px → 11.5px) for better fit. 6. **Feature cards too tall on mobile** — Compact card layout under @media (max-width: 768px), (pointer: coarse): 28px → 20px padding, 40 → 32px icon, 32 → 14px grid gap. Cards now feel like a tight group instead of 1/3-screen blocks with awkward gaps. 7. **"Live · no server required" chip orphaned** — Moved inline with the "Visual Agent Builder" section label so it reads as a header annotation rather than a floating chip between the description and the card. 8. **Comparison table cells wrapping to 3 lines** — Bumped .cmp-table min-width from 640px to 800px so each column has ~115px (enough for "macOS desktop app" and "No (desktop only)" to fit on 1-2 lines). Added `white-space: nowrap` to .yes/.no/.mid verdict cells so 2-3 char answers never wrap awkwardly. 9. **No gap before first builder card in "Three paths"** — Added explicit margin-bottom: 64px on the section description and padding-top: 8px on the cards container. 10. **Header should always be visible** — Removed the hide-on-scroll-down behavior on touch devices (kept on desktop where it's a thoughtful progressive enhancement). On mobile the nav now stays fixed at the top throughout scrolling, which doubles as a wayfinding aid. Approach informed by /adapt and /clarify skill guidelines. The @media (pointer: coarse) pattern is the key insight from /adapt: viewport-based responsive design is fundamentally fragile because users can override it (Desktop Site mode, Reader Mode, browser zoom). Touch input is a hardware property that cannot be spoofed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the catastrophic mobile layout reported on Galaxy S23. The landing page was effectively unusable below ~1024px due to a combination of bugs that all surfaced together. Plus the docs site had a broken nav icon that triggered a half-rendered state when clicked.
Issues addressed (from the bug report):
extra.homepage→ QUICKSTART, removed brokenmikeprovidermin-width: 0on grid children + .code-framehtml, body { overflow-x: hidden }(was body alone)Root cause (the hidden gotcha)
The Galaxy S23 was almost certainly in Chrome's "Desktop Site" mode, which reports a viewport of ~980px — just over the existing 900px breakpoint. This defeated
.hide-mobileand kept all layouts in their desktop forms but rendered on a phone screen, producing the squeezed/overflowing/cut-off symptoms.The fix is structural, not just CSS patches:
Detailed changes
landing/index.html(+395 / -16)Page-level overflow fix
html, body { overflow-x: hidden; max-width: 100% }(previously onlybody)max-width: 100%onimg, video, iframe, table, preHamburger menu
.nav-burgerbutton +.nav-drawerslide-down panelaria-expanded/aria-hidden/aria-controlsfor accessibilityHero buttons
.hero-actions { flex-direction: column }at <=640pxflex: 1with!importantso each button gets full widthCode blocks
.code-frame { min-width: 0; max-width: 100% }.grid-2/3/4 > * { min-width: 0 }(the actual flex/grid sizing trap fix).code-body { -webkit-overflow-scrolling: touch }for iOS momentumComparison tables
.cmp-scrollwrapper withmask-imageedge gradient.cmp-table { min-width: 640px }forces readable column widths.cmp-hint("scroll → for full comparison") shown at <=768pxBuilder section
.builder-mobile-fallbackcard with cyan CTA button.builder-frame[data-builder-iframe] { display: none }at <=768pxEval/trace iframes
Footer
.footer-attributionwrapper with smaller.footer-metatextTouch-device hover guard (the touch-stickiness follow-up from earlier)
@media (hover: none)block at the bottom of the CSStransformandbox-shadowside of hover (not color) on touchlanding/eval-report-preview.html(+22 / -1)html, body { overflow-x: hidden; max-width: 100% }@media (max-width: 560px)block: smaller padding, simplified 2-col stat grid, smaller table padding.table-wrapwith horizontal scroll inside the iframelanding/trace-preview.html(+15 / -1)html, body { overflow-x: hidden }fix.table-wrapwithmin-width: 380pxtable inside@media (max-width: 560px)block: smaller padding, font, table paddingmkdocs.yml(+5 / -2)extra.version.provider: mike— was fetchingversions.json(which doesn't exist), causing 404s and breaking the docs nav stateextra.homepage: https://selectools.dev/QUICKSTART/— the actual root cause of the broken docs nav icon. Clicking the logo navigated to/, which is the landing page (overwritten by the deploy workflow). Material's instant-navigation could not render the landing page HTML inside the docs shell, causing the half-rendered broken state. Now the icon goes to QUICKSTART, which is a real Material docs page.docs/index.md(+99 / -3)window.location.replace("QUICKSTART/")) with a proper Material grid-cards welcome page<div class="grid cards">sections: "Get started in 5 minutes" (4 cards) and "Explore the modules" (6 cards)md-buttonstylingnavigation.instant. The welcome page is what localmkdocs serveshows now. Production still overwrites it with the landing page, but theextra.homepageconfig above ensures that's never reached from the docs nav.Local-only follow-ups (in
.private/, gitignored, not in this PR)Done as part of the same work session but not committed because
.private/is gitignored:.private/— samejohnnichev.github.io/selectools→selectools.devsweep we did for public files in PR feat: animation/delight pass + selectools.dev custom domain #40, now extended to launch posts and blog drafts.private/launch-prep/gsc-migration-checklist.md— new file with the full Google Search Console migration playbook (add new property, TXT verification, sitemap submission, change-of-address wizard, monitoring schedule, what NOT to do)Test plan
Pre-merge — verify the build is clean (already done locally):
mkdocs buildproduces 0 errors / 0 warningsnode --check(passes)Post-merge — verify on production at https://selectools.dev
Required device combos:
For each combo, walk through:
For the docs site:
versions.jsonin DevTools Network tabWhat's NOT in this PR
@mediaqueries on the inner files achieve the same UX with less risk)/to/QUICKSTART/for docs (would require an Actions workflow change; theextra.homepageconfig solves the same problem more cleanly)If anything still looks off after merge, the easiest fix-loop is to add to this same branch and re-merge — I can iterate quickly on any specific symptoms you find.