The two defects the operator found on his own phone are fixed and live since
5aeb36b5; this is what pins them so they cannot come back silently.
site_gates.py gate 22 parses site.css and shell.css into
(media context, selector, declarations) and fails on any property site.css
declares on a selector shell.css also styles that nothing overrides - neither
shell.css itself nor a `.shell ...`-scoped reset. site.css loads first, so
"later wins" is per PROPERTY, not per rule. Today: 689 site rules vs 119 shell
rules, 9 shared selectors, 0 leaks. .hamburger-box / .hamburger-line are an
explicit allow-list with the reason beside them.
It is media-aware precisely because the check it replaces was not. The STOP-1
leak diff excluded @media blocks and reported "exactly six" leaking
declarations; the real number is forty, and the worst of them
(@media (max-width: 900px) .nav-links { position: fixed; right: -100% })
parked the drawer's menu off-canvas and shipped.
Two decoys in test_gate_decoys.py, both the exact shape that went live, both
seen to convict:
site/shell-css-leak-in-media the body:not(.shell) scope taken back off that
one rule - the gate names the media query, the
selector and `right: -280px`
site/footer-outside-main <main> closed early on gyik.html - gate 3b's line
They plant and restore BYTES, with the anchor translated to the file's own line
ending: these files are CRLF in a Windows worktree and LF in a Linux one, and
replace_in's text-mode round trip would have rewritten a whole file on one side.
Also: CHANGELOG entries for both areas, the M3 report corrected where it quoted
its own wrong "exactly six", and one plain-language STATUS line.
7.9 KiB
REPORT — M3: the website in the controller's shell (2026-10-11)
REPORT-<topic>.md, notREPORT.md: that file belongs to another session and is overwritten per session.
In plain words
The website now looks and works like the box's own dashboard: a left menu with your logo, the phone version with a slide-out menu, and the same cards and buttons the controller uses. The pages say exactly what they said yesterday. The whole site switched at once, so nothing is half old and half new.
Two decisions you made during the run: the small dashboard window sits beside the headline rather than a second copy of the logo, and the first menu item is „Kezdőlap". You also chose to have the English home page rebuilt as a real twin of the Hungarian one before switching, which is what happened.
What is live
20 pages: 12 Hungarian (including the hidden prices page) and 8 English. website/preview/ is gone
entirely, taking the A, M1, M2 and M3 studies with it.
| before | after | |
|---|---|---|
| Home page height, desktop | 10 967 px | 4 340 px |
| Home page, first load | 13 requests / 308 KB | 12 requests / 282 KB |
| Third-party hosts | 0 | 0 |
| Em dashes on the home page | 18 | 0 |
| Em dashes replaced site-wide | — | 326 across 17 pages |
The two decisions, as answered
- Beside the headline: the dashboard window (not the logo). The sidebar already shows the logo and wordmark, so a second copy would have been the same mark twice on one screen.
- First menu item: „Kezdőlap" (not „Indítópult"). The home page is not a launcher, and a first-time visitor reads „Kezdőlap" without needing to know the product.
What the controller and the website now share
Recorded in documentation/design/design-system.md §Shell.
| Shared | Website owns | Controller owns | |
|---|---|---|---|
| The 18 tokens | yes, byte-identical in both :root blocks |
— | — |
| The shell: sidebar, top bar, drawer | yes — shell.css is a copy |
the menu items, the wordmark, the sidebar button, the globe's targets | its own menu, its POST language form |
Atoms: .btn*, .alert*, .app-info-card, .launch-*, .form-* |
yes, same copy | — | — |
| Page content and layout | no | all of it | all of it |
How a change flows: the controller changes first; the website's copy is regenerated the same week by re-running the generator against the controller's new commit. A cross-repo gate was deliberately not built (your brief) — the shell should settle first.
Proof, not assertion
- Head tags captured on all 19 pages before the switch and compared after
(
audits/m3-2026-10-11/head-before.json/head-after.json). The only difference anywhere is the dash substitution inside the two FAQ pages'FAQPageJSON-LD — proven by applying the same substitution to the before copy and getting an exact match. - Visible text identical to the live pages, word for word. Legal texts identical with no substitution permitted at all (1 396 and 608 words).
- Live read-back of all 20 URLs: 200, sidebar, footer, legal link and
?v=22on every one. - No page overflows at 390 px; the drawer opens, closes on Escape and returns focus.
- No contrast failures, measured with translucent ancestors composited.
Five faults found by measuring, which looking would not have found
- The home page was about to go live
noindex, nofollow, having also lost meta keywords, meta author, all seven Open Graph tags, all four Twitter tags and theLocalBusinessJSON-LD — its head was hand-built while every other page carried its live one over. The head-tag diff caught it. - The footer had been deleted from all 19 pages, taking the only route to the Adatkezelési
tájékoztató and the Feltételek, the operator's name and
info@felhom.eu. The legal pages are in no menu, so they would have become unreachable. - 168 words silently dropped — the „Fontos tudnivalók" / „Good to know" box on both apps pages
and the 404's English line — by a page-header transform that kept only the
<h1>and first paragraph. Found by a word-level diff. - The sidebar rendered as a horizontal row across the content column, because „later wins" is
per property and the controller's
.nav-linksnever declaresdisplay. Diffing the two files' declaration sets found six such leaks; only this one was visible. That diff was wrong, and the section below says how — the real number was forty. - The contact pages' header slid under the sidebar (content column at x=642 instead of 240,
form at two-thirds width) because those pages keep their header outside
<main>.
Fixed along the way, small enough not to file
/letoltesand/adatkezelesscrolled sideways on a phone — 609 px and 478 px at a 390 px viewport, on the live site, before any of this: a 64-character checksum and a long legal URL.- R-930 arrived a second time. Fixing the website's
.cta-buttonhad not fixed the controller's.btn-primary, which the shell imports; it measured 4.01:1 again. Your existing remedy applied..nav-group-labelwas 3.14:1 and moved to--text-2.
Two defects a real phone found, after the switch
Reported by you, from your own phone, hours after it went live. Both were mine. Fixed, live as
?v=23, and read back on all 20 pages at 390 / 860 / 1440 px.
- The phone menu was empty. The drawer slid open correctly and had nothing in it.
site.css's old mobile nav still reached the shell's sidebar: under@media (max-width: 900px)it sets.nav-links { position: fixed; right: -100% }, which parked the menu off-canvas inside the open drawer. Every old-chrome selector (29 occurrences) is now scopedbody:not(.shell)— scoped, not deleted, so a page without the shell still works. - The footer rendered as a second column at the top right of 16 pages.
bodyis a flex row on a shell page, and my insert moved the footer inside<main>only on pages that ended with</main>; a page with a<script>after it kept the footer as a direct child ofbody.
The first one is a failure of my own check, not bad luck. The leak diff I ran at STOP 1 — the one
whose „exactly six" this report quoted above — excluded @media blocks. Media-aware, the number
is forty, and the worst of them only apply below 900 px, which is exactly why the desktop screens
I took looked right. A check that silently skips part of its subject is not a check: it returned a
confident, wrong number, and I believed it rather than the phone.
Both are now gated, each red-proofed by putting the live defect back: gate 3b requires every shell
page's footer to sit inside <main class="content">, and the new gate 22 compares the two
stylesheets media-aware and fails on any declaration of site.css's that still reaches a shell
page. Today it reads 689 site rules against 119 shell rules, 9 shared selectors, 0 leaks. The two
decoys (site/shell-css-leak-in-media, site/footer-outside-main) are the exact shapes that shipped.
Still open
- R-931 — felhom.eu still serves nothing compressed.
shell.cssadds 15 KB per page, all of it uncompressed. This is now the cheapest win on the site by a wide margin. - R-932 — eight catalog strings carry an em dash and show on real customers' boxes.
- The controller has the same two contrast defects on its own screen (
.btn-primary4.01:1,.nav-group-label3.14:1). Fixed for the website only; that repo was read-only this session. - No cross-repo gate keeps
shell.cssin step with the controller, by your instruction.
Gates and register
site_gates.py green throughout, now with gate 22; full repo_gates.py --fast green on DooPlex,
decoy suite included. Register unchanged at 128 — nothing filed, because everything found was either
fixed in the session or already has a row, and the two live defects were found, fixed and pinned the
same day.