From 9b4f93bb163c8f129cc644de46d772c31affeb6c Mon Sep 17 00:00:00 2001 From: Yuriy Panov Date: Sat, 29 Aug 2026 11:32:28 +0600 Subject: [PATCH] Redesign the phone layer of the landing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three layout bugs and a mobile experience that had no wayfinding. The `#proposal` section was clipped, not merely cramped: the submit button carried `whitespace-nowrap` from the shared button base, giving it a min-content width of 358px, which sized the section's implicit `auto` grid track to 406px inside a 343px container. `overflow-hidden` then sliced the copy and every form field off the right edge of a 375px screen. Fixed at the root — `whitespace-nowrap` moves out of `base` and into `headerSize`, where buttons are sized by their label — plus an explicit `grid-cols-[minmax(0,1fr)]` on the section. The market stat cards put their source line in absolute position against a guessed min-height, so the longest label ran underneath it. It is in the flow now, pinned by `mt-auto`. Below 980px the header nav is not rendered, which left seventeen screens of scroll with no way to navigate them. The header gives that width back to the page — logo and call button only — and takes over: scroll progress, a live section indicator that opens a section sheet, and one short CTA, hidden over the hero and over the form. Card rows now say what they are. Rows of unordered peers keep scrolling sideways and gain a measured segment indicator (), replacing the two prose "swipe sideways" hints. The launch timeline goes the other way: sideways scrolling hid week 3-5 from someone reading week 1-2, so below 900px it becomes four disclosures on a spine — which also recovers the scroll length the taller hero spent. Below 560px the type scale steps down half a level and the display tracking opens back up, and the hero photo zooms past `cover` onto the wave wall, since fitting by height left only ceiling tiles above the copy. Also: the route card inside the market section split into two 165px columns at 760px, so that split now waits for 980px. Desktop above 980px is unchanged. Co-Authored-By: Claude Opus 5 --- medcenterpersonal/src/App.tsx | 3 + medcenterpersonal/src/components/Button.tsx | 14 +- .../src/components/EquipmentSection.tsx | 19 +-- medcenterpersonal/src/components/Hero.tsx | 47 +++-- medcenterpersonal/src/components/Icons.tsx | 20 ++- .../src/components/LaunchSection.tsx | 120 ++++++++++--- medcenterpersonal/src/components/Layout.tsx | 16 -- medcenterpersonal/src/components/LeadForm.tsx | 2 +- .../src/components/MarketSection.tsx | 38 +++-- .../src/components/ProgramsSection.tsx | 12 +- .../src/components/ProjectSection.tsx | 14 +- medcenterpersonal/src/components/Rail.tsx | 128 ++++++++++++++ .../src/components/RequestSection.tsx | 11 +- .../src/components/ScenariosSection.tsx | 4 +- .../src/components/SiteFooter.tsx | 3 +- .../src/components/SiteHeader.tsx | 17 +- medcenterpersonal/src/components/ThumbBar.tsx | 160 ++++++++++++++++++ .../src/components/WhyExoSection.tsx | 11 +- medcenterpersonal/src/data/content.ts | 19 +++ medcenterpersonal/src/hooks/useMediaQuery.ts | 22 +++ .../src/hooks/useReadingPosition.ts | 54 ++++++ medcenterpersonal/src/index.css | 104 ++++++++++++ 22 files changed, 724 insertions(+), 114 deletions(-) create mode 100644 medcenterpersonal/src/components/Rail.tsx create mode 100644 medcenterpersonal/src/components/ThumbBar.tsx create mode 100644 medcenterpersonal/src/hooks/useMediaQuery.ts create mode 100644 medcenterpersonal/src/hooks/useReadingPosition.ts diff --git a/medcenterpersonal/src/App.tsx b/medcenterpersonal/src/App.tsx index 81fac7b..267937f 100644 --- a/medcenterpersonal/src/App.tsx +++ b/medcenterpersonal/src/App.tsx @@ -9,6 +9,7 @@ import { ResidencySection } from './components/ResidencySection' import { ScenariosSection } from './components/ScenariosSection' import { SiteFooter } from './components/SiteFooter' import { SiteHeader } from './components/SiteHeader' +import { ThumbBar } from './components/ThumbBar' import { WhyExoSection } from './components/WhyExoSection' export default function App() { @@ -30,6 +31,8 @@ export default function App() { + + ) } diff --git a/medcenterpersonal/src/components/Button.tsx b/medcenterpersonal/src/components/Button.tsx index 509d9d0..e669da1 100644 --- a/medcenterpersonal/src/components/Button.tsx +++ b/medcenterpersonal/src/components/Button.tsx @@ -4,10 +4,20 @@ import { cx } from '../lib/cx' export type ButtonVariant = 'primary' | 'secondary' | 'call' const base = - 'inline-flex cursor-pointer items-center justify-center gap-[10px] rounded-full border border-transparent font-[790] leading-none whitespace-nowrap ' + + 'inline-flex cursor-pointer items-center justify-center gap-[10px] rounded-full border border-transparent font-[790] leading-none ' + 'transition-[transform,box-shadow,background-color,border-color] duration-200 hover:-translate-y-[2px] active:translate-y-0 ' + '[&>svg]:size-[18px] [&>svg]:shrink-0' +/** + * `whitespace-nowrap` belongs on buttons sized by their label, not on every + * button. A full-width button whose label cannot wrap reports a min-content + * width of its whole label — 358px for «Получить предварительный аудит» — and + * that width propagates out through any `auto` grid track around it. That is + * what pushed the whole `#proposal` section 47px off a 375px screen and let + * `overflow-hidden` slice the copy and the form fields off the right edge. + */ +export const nowrap = 'whitespace-nowrap' + /** * Sizing gets its own slot rather than living in `base`. Tailwind resolves * conflicting utilities by their order in the stylesheet, not by the order they @@ -18,7 +28,7 @@ const base = const defaultSize = 'min-h-[52px] px-[22px]' /** `.btn--header` — smaller, and tighter still on the narrowest phones. */ -export const headerSize = 'min-h-[44px] px-[17px] text-[13px] phone:px-[14px] phone:text-[12px]' +export const headerSize = 'min-h-[44px] px-[17px] text-[13px] whitespace-nowrap phone:px-[14px] phone:text-[12px]' const variants: Record = { primary: diff --git a/medcenterpersonal/src/components/EquipmentSection.tsx b/medcenterpersonal/src/components/EquipmentSection.tsx index a91bc13..42f6dc6 100644 --- a/medcenterpersonal/src/components/EquipmentSection.tsx +++ b/medcenterpersonal/src/components/EquipmentSection.tsx @@ -2,7 +2,8 @@ import { devices, equipmentNote } from '../data/content' import { useReveal } from '../hooks/useReveal' import { cx } from '../lib/cx' import { CheckIcon } from './Icons' -import { Container, ScrollHint, Section, SectionHead } from './Layout' +import { Container, Section, SectionHead } from './Layout' +import { Rail } from './Rail' /** * Product shots differ in framing, so the last stylesheet pass in the original @@ -37,10 +38,12 @@ export function EquipmentSection() { lead="Конфигурация подбирается под профиль центра, поток пациентов и задачи врачей. Используем технологическое ядро ЭКЗО без универсального набора и лишнего дублирования." /> -
{devices.map((device) => (
))} -
- - - На мобильном — листайте карточки в сторону - +