Rename the two medcenter landings to their audience names:
medcenter -> medcenterphysio, medcenterpersonal -> medcenterstart.
Alongside the rename:
- add a RevenueCalculator section to both landings;
- rework the copy and figures in src/data/content.ts;
- simplify the lead form: drop the "cabinet_state" and "profile"
selects (along with SelectField and the matching fields in
shared/lead.ts, lead-mapper.ts and amo-check.ts) and make
company and email optional;
- add the legacy/new static prototypes for both landings;
- add pnpm-lock.yaml to medcenterstart (package-lock.json is still
there too).
deploy/apps.conf and deploy/README.md still refer to the old
directory names and need a follow-up.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ports the last single-file page, MedCbezFiz — the medical centre that has no
physiotherapy yet — to the architecture the other three landings now share:
Vite + React 19 + TypeScript + Tailwind v4, Express 5 for the API, zod schema
shared between client and server.
The original is kept in legacy/index.html as the visual reference, with its
instructions alongside it in legacy/README.md. Its 4 MB collapse to 317 KB of
JS plus assets loaded on demand. Fourteen inlined images were extracted; twelve
turned out byte-identical to the medcenter landing's, and the two large device
PNGs (1.5 MB and 750 KB) had identical sources, so the webp conversions from
that landing are reused rather than redone — 664 KB of assets instead of 2.8 MB.
Text was verified rather than eyeballed: the app is server-rendered to static
HTML and its visible text diffed against the legacy file. 280 blocks against
281, and the only difference is the honeypot's screen-reader label, which the
original has no equivalent for.
Two things in the original are dead and were deliberately not ported: 39
.patient-economics / .base-economics-card rules that no element uses, and the
[data-counter] animation handler, which likewise matches nothing on the page.
Both are documented in the README.
Departures from the medcenter landing this was built from, all following the
original: the hero photo is anchored at 65% (72% from 980px), the header is
transparent until 18px of scroll instead of always painted, the revenue band
keeps 32px gutters at every width, and the launch timeline breaks into two
columns at 900px rather than 760px.
Leads post to /api/leads/medical-centers-no-physio, the address the original
page already referenced, into pipeline 10980758. The cabinet_state select has
no counterpart on this form and was dropped from the schema, mapper and check
script. Vite runs on 5175 and the API on 3002 so all four landings can run at
once.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the single-file MedCsFiz page — the medical centre that already runs
physiotherapy and wants the existing room to earn more — to the same
architecture as the fitness and hotel landings: Vite + React 19 + TypeScript +
Tailwind v4 on the client, Express 5 for the API, zod schema shared between the
two.
The original stays in legacy/index.html as the visual reference. Its 4 MB of
inlined CSS, JS and base64 images become 12 asset files (664 KB) plus a bundle
loaded on demand; the two 1.5 MB / 750 KB device PNGs are recompressed to webp.
The page is split into 18 components with all copy moved to src/data/content.ts.
Leads reuse the fitness amoCRM integration: contact lookup by phone in every
Russian spelling, deal in the first stage of pipeline 10980758, account fields
matched automatically with the rest written to a note. Rate limit, honeypot and
a localStorage fallback so a lead survives the CRM being down. Endpoint is
/api/leads/medical-centers-existing-physio; Vite runs on 5173 and the API on
3000.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the single-file ЭкзоОтель page to the same architecture as the fitness
landing: Vite + React 19 + TypeScript + Tailwind v4 on the client, Express 5 for
the /api/leads/hotels endpoint, zod schema shared between the two.
The original page is kept in legacy/index.html as the visual reference. Its 15
inlined base64 images are extracted to files (the 1 MB HTML becomes ~318 KB of
JS plus assets loaded on demand), and its text is reproduced line for line —
verified with an innerText diff. Section heights stay within 0.6% at 375 and
1440 px; the drift comes from Inter actually loading, which the original asked
for but never served.
Three deliberate departures, documented in the README:
* eyebrow and lead in the CTA block were dark teal on navy (3.4:1); they now
match the other dark sections
* hero fact values overflowed their 80px column into the label below 430px
* "2025–2026г.." typo in the market source note
Leads reuse the fitness amoCRM integration: contact lookup by phone in every
spelling, deal in the first stage of pipeline 10980758, account fields matched
automatically with the rest written to a note. Rate limit, honeypot, and a
localStorage fallback so a lead survives the CRM being down. Vite runs on 5174
and the API on 3001 so both landings can run at once.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Port the single-file landing (2.6 MB of inlined CSS, JS and base64 images,
kept as fitnes/legacy/index.html) to Vite + React 19 + TypeScript, with an
Express API that files every form submission into amoCRM pipeline 10980758.
- Extract the 14 embedded images to src/assets/images and public/
- Rebuild the design system as Tailwind v4 @theme tokens; the stock palette and
breakpoints are cleared so only the EXO scale is reachable from utilities
- Split the page into 15 components; all copy moves to src/data
- Lead endpoint: find-or-create the contact (Russian phone spellings compared on
the last 10 digits), create the lead in the pipeline's first stage, map the
fields the account already has and put the rest in a note. If amoCRM is
unreachable the payload is logged and kept in localStorage rather than lost.
- Add a callback modal as a second entry point, tagged separately in the pipeline
- Self-host Inter Variable so the layout's 760/850/900 weights render as real
weights instead of snapping to bold
Fidelity was checked by comparing section offsets and heights against the
original at 375/480/640/900/1120/1440 px; every section and the total page
height matched exactly. Loading Inter deliberately changes text metrics, so the
byte-exact comparison holds against the pre-font build.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>