## 2026-10-12 (night) — make_hero_clip.py: scenes keep their own length - **`--seconds` is no longer a fixed window.** Each scene now plays its full recorded length, read per file with `ffprobe` (operator ruling 2026-10-12: *„use the full length for all of them, they had been cut as I liked them”* — the raw file IS the edit). `--seconds N` stays as a cap, for trying a shorter loop; `0` (the default) means full length. - The xfade offsets are computed from the running sum of the scenes so far **minus one fade per transition already made** — xfade measures its offset on the chain it is handed, which is shorter than the raw sum. With equal-length scenes the old `i * (seconds - FADE)` was the same number; with unequal ones it is not. - **Output is `hero-clip.mp4` / `.webm` / `hero-poster.webp`** — no language suffix, because the same recordings serve `/` and `/en/`. `--lang hu` puts `-hu` back if the two ever differ. - Six real scenes, 36.6s after the fades: **mp4 1 134 KB, webm 1 295 KB, poster 53 KB.** Three times the 11.4s trial, as expected — the hero is the only page that loads it, and only once it is on screen. ## 2026-10-12 (evening) — make_hero_clip.py: the home page's laptop clip - `scripts/make_hero_clip.py` assembles the hero clip from the operator's raw app recordings: `NN-appname.ext` in, scaled and centre-cropped to the laptop screen's 1.626:1, crossfaded, out as **mp4 (h264) + webm (VP9) + a webp poster**. Runs on DooPlex; Windows has no ffmpeg. It is not part of any build, gate or deploy — the site has no build step, so its output is committed like any other picture. - **Why mp4+webm and not a GIF**, measured on DooPlex 2026-10-12 with six crossfaded scenes: | | 11.4s @ 904×556 | 11.4s @ 1130×696 | |---|---:|---:| | mp4 (h264 crf30) | **331 KB** | 775 KB | | webm (VP9 crf44) | 411 KB | 1 196 KB | | animated webp | — | 2 551 KB | | GIF | **2 676 KB for 6s** | — | A GIF is ~11× the mp4 for the same seconds, and dithers to 256 colours on a dark UI. - Proven end to end against six placeholder scenes built from the repo's own app screenshots: 21s loop → mp4 480 KB, webm 609 KB, poster 83 KB. ## 2026-10-12 (afternoon) — gate 22 also refuses an unscoped bare element rule - `site_gates.py` gate 22 gains a second half: a rule in `site.css` whose selector starts with a bare `nav`, `header`, `main` or `aside` and is not scoped `body:not(.shell)` / `.shell` is a failure, because those elements ARE the shell (`