Skip to content

fix(responsive): make every section usable on phones, tablets and 1024-1279 laptops - #7

Merged
aMonteSl merged 10 commits into
mainfrom
fix/responsive-audit
Sep 7, 2026
Merged

fix(responsive): make every section usable on phones, tablets and 1024-1279 laptops#7
aMonteSl merged 10 commits into
mainfrom
fix/responsive-audit

Conversation

@aMonteSl

@aMonteSl aMonteSl commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Summary

After #6 the site looked wrong on phones, tablets and 1024–1279px laptops. This PR is the result of a full responsive audit (measured on the live site with emulated viewports) plus the fixes, area by area. Desktop at 1280px and wider keeps its look; everything below changes on purpose.

Measured before → after

Viewport Before After
1024×768 Header showed only the brand; featured hero card 192px wide; certification cards 124px; secondary project cards 203px; footer under the fixed sidebar Header has language switcher + menu; no sidebar below 1280px; hero card ≈380px; cards follow their container; footer clear
768×1024 No navigation until 450px of scroll; 3 project cards of 222px Menu in the header at any scroll position; 2 columns
1280×720 Sidebar language switcher off-screen Sidebar panel scrolls
320–360 Featured card links overflowed 77px; availability pill broke its card; drawer clipped its last items; carousel arrows invisible on touch Links wrap; pill fits; drawer scrolls; arrows, swipe and 24–44px controls on touch

Navigation shell — sidebar and content offset move from lg to xl (one set of constants shared by home, footer and scroll cue); header below xl gets the language switcher and a 44px hamburger that opens the drawer from any scroll position (drawer state in MorphNavProvider); SidebarPanel is a real component and the scroll region for aside and drawer; drawer has body-scroll lock, focus management, Tab trap and Escape; FAB and browser-translate hint respect the safe area and no longer collide. The desktop header now uses the same max-w-7xl container as the sections and keeps its eight nav labels on one line (on the live site five of them and the brand wrapped onto two lines at every width from 1280 to 1920).

Hero — two-track grid instead of a 12-column grid with 11 gaps; featured card renders both projects stacked in one grid cell so it takes the taller height and never jumps; links wrap; 44px dots and a pause/resume toggle; Badge used colour names that do not exist in the Tailwind v4 build.

Carousel — arrows visible on coarse pointers and keyboard focus; 7-dot window with 24px hit areas; pointer swipe with axis lock that never opens the lightbox or bubbles to the card; lightbox with 44px controls, safe-area padding and a height that fits landscape phones; all labels in a new carousel i18n namespace.

Projects and /uses — sticky project nav with 44px back and always-available previous/next; detail hero with monotonic heading sizes and a DOI chip that can break; release notes follow the narrative on phones; no nested <main>; secondary grid 1 → 2 → 3 columns; equal card heights; /uses gets a 44px back link, a language switcher and block anchors.

Sections — skills modal with a fixed header and 44px close; distribution tiles readable at 320px; references two columns from md; certifications inner grid driven by a container query; contact pill wraps; footer links one column below 420px with 36px rows and 44px icons.

Journey timeline — vertical layout extracted to VerticalTimeline; map height follows the number of years (512–848px instead of a fixed 800px); detail card becomes a sticky bottom sheet with a close button; 44px hit areas while dots and bars stay thin; horizontal markers centred with translate, achievements staggered into two rows when they would overlap, drill-down padding fixed; glow loop only runs while the horizontal layout is on screen; legend and drill-down labels localized.

Foundation / cleanupxs breakpoint (420px), scroll-padding-top for hash links under the fixed header, viewport-fit=cover so safe-area insets work, pause/play icons, useMediaQuery / useElementWidth hooks; the dead constructionNotice / Modal code (with its latent scroll bug) and its development i18n block are removed.

Verification

  • npm run check (lint, typecheck, translations, journey timeline): green
  • npm run build: 17 static pages exported
  • Every Tailwind class in the changed files compiled against the project's Tailwind setup (927 candidates, 0 no-ops)
  • Headless Edge (Playwright) against the dev server: screenshots of /es/ at 320×568, 360×740, 390×844, 768×1024, 844×390, 1024×768, 1280×720, 1440×900 and 1920×1080, plus /es/projects/code-xr/, /projects/obt/ and /es/uses/ at 360/768/1024/1440; no horizontal overflow, no console errors
  • Desktop header measured at 1280–1920 in both locales: one line, 48px of slack in Spanish and 97px in English
  • Touch interactions at 360×740: drawer opens from the header at scroll 0, scrolls internally, locks the body and returns focus on close; featured-card pause toggle; carousel swipe changes the image without opening the lightbox or navigating; lightbox opens on tap with 44px controls and closes with Escape; skills modal keeps its close button fixed while scrolling; timeline bar tap opens the sticky detail sheet
  • Desktop 1440/1920 compared against the live site: layout unchanged apart from the intended details (staggered achievement markers, re-centred markers, 44px language switcher)

After merging

  • The I18n Translation workflow will open an auto-translation PR because en.json changed. Close it without merging: the Spanish copy in this PR is already curated.
  • AGENTS.md's "UI/UX matches current site exactly" checkbox is intentionally not met below 1280px; above it the layout is preserved.
  • Follow-ups left out on purpose: tailwind.config.ts and the two fluid plugins are not loaded by Tailwind v4 (either wire them with @config or delete them); Header.tsx, Nav.tsx, Chip.tsx, test-fluid.css and the unused helpers in timelineConfig.ts / journey.ts are dead code; the vertical timeline could get a per-year zoom.

🤖 Generated with Claude Code

codex and others added 10 commits September 7, 2026 09:18
The responsive fixes that follow need a few things in place first so each
area can be worked on independently: the i18n keys for the new navigation,
carousel, timeline and language-switcher labels (previously hard-coded in
English), pause/play icons for the featured card, the sidebar offset as a
single set of constants, two small hooks (media query, element width), an
`xs` breakpoint at 420px, `scroll-padding-top` so hash links clear the fixed
header, a `viewport` export with `viewport-fit=cover` so safe-area insets
work on notched phones, and a `className` prop on the footer so the home page
can offset it next to the sidebar.

- en.json/es.json: nav.*, hero.featuredProject.goTo/pauseRotation/resumeRotation,
  language.selection/switchTo/current, journey.back/start/yearDetails/
  closeDetails/legend*, new top-level `carousel`; shorter OBT subtitle so it
  fits the featured card without truncation
- icons: PauseIcon, PlayIcon
- morphNav/layout.ts: SIDEBAR_* constants
- lib/hooks: useMediaQuery, useElementWidth
- globals.css: @theme --breakpoint-xs, scroll-padding-top
- app/layout.tsx: viewport export (replaces the manual theme-color meta)
- Footer: optional className

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`DevelopmentModal`, `useScrollGuard` and the generic `Modal` were only
referenced by each other and by nothing in the app. The modal also carried a
latent mobile bug (no max-height or inner scroll while it locked body scroll
with `overflow: unset`), so removing it is safer than fixing code nobody
renders. The `development` i18n block that only it consumed goes with it, in
both locales, so the translation check stays balanced.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Between 768px and 1279px the header showed only the brand: the desktop nav
was gated at xl while the mobile language switcher disappeared at md, and the
floating menu button only mounted after 450px of scroll. At 1024px the fixed
17rem sidebar also squeezed every section into 664px. The drawer clipped its
own content (no scroll, language switcher cut off on every phone) and the
desktop sidebar overflowed 720px-tall viewports.

- Sidebar and content offset move from lg to xl; the offset lives in one set
  of constants shared by the home content, the footer and the scroll cue
- Header below xl: language switcher + 44px hamburger that opens the drawer
  from any scroll position (drawer state lives in MorphNavProvider)
- SidebarPanel is a real module-level component (was recreated every render)
  and is the scroll region for both the aside and the drawer, with safe-area
  padding; drawer items no longer depend on isMorphed to become visible
- MorphDrawer: body scroll lock that restores the previous value, focus to the
  close button and back to the opener, Tab trap, Escape, auto-close when the
  xl sidebar takes over
- FAB and browser-translate hint respect the safe area and no longer share a
  corner; language switcher buttons are 44px; labels localized
- Footer receives the sidebar offset on the home pages so it no longer sits
  under the aside

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The hero used a 12-column grid with 48px gaps, so 11 gutters ate 528px and the
card column measured 192px at 1024px. The featured card had a hard 252px
height with fixed slots; the Code-XR link row overflowed by 77px at 320px
(a shrink-0 group that could not wrap) and the OBT subtitle was always
truncated by line-clamp-2.

- Two-track grid (5fr/7fr) with a single gap; 100svh instead of 100vh
- Featured card: both projects render stacked in one grid cell so the card
  takes the taller one's height and never jumps; links wrap; subtitle gets
  3-4 lines; 44px dot buttons and a pause/resume toggle (touch and keyboard
  users could not pause before); labels localized
- ProfileBio aside floor lowered so the main column stays wider
- Badge used colour names that do not exist in the Tailwind v4 build (the
  legacy config is not loaded), so it rendered without background; now uses
  the CSS variables like the rest of the site

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Arrows were revealed on hover only, which Tailwind v4 wraps in
@media (hover: hover), so phones and tablets never saw them; the dots were
8px targets; there was no swipe; and the lightbox kept auto-rotating and
overflowed landscape phones.

- Arrows visible on coarse pointers and on keyboard focus, larger on touch
- Dots have 24px hit areas and a 7-dot sliding window (Code-XR has 14 images)
- Pointer swipe with axis lock; a swipe never opens the lightbox or bubbles
  a click to the parent card; manual interaction holds autoplay
- Lightbox: 44px controls, safe-area padding, height that fits landscape
  phones, swipe-down to close on touch, Tab trap
- All labels through the new `carousel` i18n namespace

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ablets

- Sticky project nav: 44px back button, previous/next always available (they
  were hidden below md), safe-area top padding
- Detail hero: monotonic heading sizes, 4:3 preview on phones, DOI chip that
  can break, 44px links on touch (compact only for fine pointers at lg+)
- Detail layout: no nested <main>; on phones the release notes follow the
  narrative instead of trailing the sidebar column
- Release cards and footer: 40-44px controls
- Landing cards: secondary grid goes 1 -> 2 -> 3 columns (was 1 -> 3 at
  768px with 203-222px cards), equal card heights, clamped summaries on
  phones, 40px link buttons
- /uses: dvh height, 44px back link with a language switcher, block anchors
  so cards align, 3 columns from lg

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… at small widths

- Skills modal: header and 44px close button stay fixed while the body
  scrolls (the close button used to scroll away); distribution tiles no
  longer overflow at 320-419px; category card header wraps
- References: two columns from md instead of lg (tablet portrait was one
  720px-wide column)
- Certifications: the inner card grid follows the panel width with a
  container query instead of the viewport (124px cards at 1024px before);
  min-heights only from md so phones lose the empty bands; tags can break
- Contact: the availability pill wraps instead of overflowing its card in
  Spanish at 320-360px
- Footer: one column of links below 420px, 36px link rows, 44px social icons

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The vertical layout forced an 800px map, hid its detail card in a 156-240px
column with truncated titles, used 8-14px touch targets, showed the "today"
label on hover only and had year buttons that did nothing on mobile. The
horizontal layout centred markers 2-4px off, let achievement dots overlap,
and drew the "Start" label over January entries.

- VerticalTimeline extracted; map height follows the number of years
  (512-848px), lanes keep a right gutter, lane dots label each stream
- Detail card becomes an in-flow sheet that sticks to the bottom while an
  entry is selected, full width, with a close button; the section uses
  overflow-clip so sticky works
- 44px hit areas via pseudo-elements while dots and bars stay thin; hover
  handlers ignore touch pointers
- Horizontal: markers centred with translate, achievements staggered into
  two rows when they would overlap, drill-down padding fixed, coarse-pointer
  hit areas
- Glow animation only runs while the horizontal layout is on screen (it was
  re-rendering the section at 60fps on phones that never show it)
- Legend and drill-down labels localized

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The header row used the 1200px `.container` while the eight nav labels, the
brand and the language switcher need about 1240px, so on every desktop width
(1280 through 1920, live site included) five nav labels and the brand wrapped
onto two lines inside the 64px bar.

The row now uses the same max-w-7xl container as the sections, so it lines up
with the content and gains 16px; nav labels no longer wrap and use slightly
tighter padding; the brand keeps the short "Adrián Montes" form (the full
name is the hero h1). Measured slack at 1280-1920: 48px in Spanish, 97px in
English.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
At 320px the featured card has ~30 characters per line, so the OBT subtitle
still hit the four-line clamp. Five lines below the xs breakpoint (420px),
four up to sm, three from sm as before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@aMonteSl
aMonteSl merged commit 0dd6633 into main Sep 7, 2026
1 check passed
@aMonteSl
aMonteSl deleted the fix/responsive-audit branch September 7, 2026 08:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants