# `#mobile-app-features` scroll-sync layout

**Last Updated:** 2026-03-26

## Purpose

Two-column block used on:

- [`v2/pages/product_mobile_app.php`](../../../../v2/pages/product_mobile_app.php) (`/mitarbeiter-app`)
- [`v2/pages/branchen_gastronomie_neu.php`](../../../../v2/pages/branchen_gastronomie_neu.php) (`/branchen/gastronomie`)

Left: four `.mobile-app-text-section` blocks with `data-visual-id`. Right (desktop): sticky grey panel (`.mobile-visual-screen`) with stacked `.mobile-visual` images; one has `.active` at a time.

## Layout contract (do not break casually)

| Piece | Role |
|--------|------|
| `section#mobile-app-features` | Same outer spacing (`mt-16 pt-20 pb-16`) on both pages unless you intentionally diverge |
| `mobile-app-features--transparent-panel` | **Only** on [`product_mobile_app.php`](../../../../v2/pages/product_mobile_app.php): sets `--mobile-visual-panel-bg: transparent` for `.mobile-visual-screen` / `.mobile-visual-frame`. Gastronomie uses default grey (`#f2f2f2`). |
| `.mobile-app-text-section-first` | `padding-top`: `--mobile-app-features-first-padding-top` (default `9rem` / `4.5rem` ≤1023px) |
| `.mobile-app-text-section-last` | `padding-bottom: 10rem` / `5rem` |
| `.mobile-visual-spacer` | `calc(first-padding-top - --mobile-app-features-visual-lead)` so the grey panel **starts above** the first headline (`--mobile-app-features-visual-lead` default `2.5rem` / `1rem`) |
| `.mobile-visual-container-wrapper` | `position: sticky` + `top: var(--mobile-app-visual-sticky-top)` — **not** `top: 50%` + `translateY(-50%)` (that pulled the panel into the fixed header) |
| `--mobile-app-visual-sticky-top` | Defined in `:root` inside [`v2/css/mobile-app-components.css`](../../../../v2/css/mobile-app-components.css); header-safe clamp |

## JavaScript

[`v2/js/mobile-app-visual-switcher.js`](../../../../v2/js/mobile-app-visual-switcher.js):

- Listens to `scroll` and `resize` (passive), batches with `requestAnimationFrame`.
- Picks the active section by a **viewport reference line** at `referenceLineRatio` (default `0.3` × viewport height): prefer sections that **contain** that Y; else closest section center. Works for **short** (gastro) and **long** (mitarbeiter) text blocks without page-specific config.

## Assets

- Mitarbeiter-app: images under `/v2/img/mobile-app/`.
- Gastronomie-neu: responsive WebP under `/v2/img/branchen/` (see page PHP for generator script reference).

## Related docs

- [mobile-app-visual-testing-guide.md](mobile-app-visual-testing-guide.md)
- [mobile-app-visual-integration-guide.md](mobile-app-visual-integration-guide.md)
