Files
felhom.eu/website/CHANGELOG.md
T
admin c4d1b0ff98
gates / gates (push) Successful in 6m27s
Website: the two download clients on the app page; the campaign's evidence; R-988 filed
The catalog published qBittorrent and Transmission today (app-catalog 9081a47). Here:

- two cards in the media category on both language sets, each with the project's own logo,
  each saying what a closed peer port costs (slower swarms, no incoming peers)
- the published count 58 -> 60 on every page that states it, FAQ JSON-LD with its visible twin
- documentation/audits/qbittorrent-2026-10-12/: both bench runs, both box walks and verdicts,
  verify-fixes.json, teardown-newapps.json, and the README brought to its final state
- the 2026-09-30 walk harness: a `type: path` deploy field is filled with the drive ROOT —
  the controller refuses a path inside a drive (409), so the walker could not install any app
  with a drive field at all
- R-988: the Usenet pair (SABnzbd, NZBGet), operator request, not started
- STATUS.md and REPORT-newapps-2026-10-12.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117kRTSgs3rJWUFGxyoWN6Y
2026-10-12 21:03:11 +02:00

759 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 2026-10-12 (night) — two download clients on the app page, and what they cost behind a tunnel
The catalog gained qBittorrent and Transmission (`app-catalog-felhom.eu` CHANGELOG, same day). The
website follows them.
- **Two new cards** in the media category on `alkalmazasok.html` and `en/apps.html`, each with the
project's own logo (`assets/qbittorrent-logo.svg`, `assets/transmission-logo.svg`): qBittorrent as
the full client, Transmission as the light one, with the sentence that says which to choose.
- **Each card states the limit the topology imposes**: the box opens no port at home, so port
mapping is off and the peer port is not published — downloads work, incoming peer connections do
not, which means slower swarms on thin torrents. It is a real limit and belongs on the page rather
than in a surprise.
- **The published count moves 58 → 60** on every page that states it (both language sets):
`index.html`, `szolgaltatasok.html`, `technologiak.html`, `gyik.html` and their twins. The FAQ's
JSON-LD answer moved with its visible answer, as the twin and FAQ gates require.
- `documentation/audits/qbittorrent-2026-10-12/` holds the whole campaign: the bench runs for both
apps, the box walk on scratch guest 9202, the six defects with their measurements, and the
re-measurement from two addresses that showed the apparent household lock-out to be an artefact of
measuring from one machine.
- `documentation/audits/pg-last-six-2026-09-30/tools/walk.py`: a `type: path` deploy field is filled
with the drive ROOT, not a folder on it — the controller refuses a path inside a drive (409), so
the walker could not install an app with a drive field at all.
## 2026-10-12 (evening) — the privacy notice says what happens to a tester's name
The first real tester answered on Prohardver today. His domain is bought **in his name** (test terms
1.1 §4), which means his name, address, e-mail and telephone number leave this house — and the
privacy notice did not say so. It does now, before the domain is bought, not after.
- **New §10, „A domained regisztrációja”:** what is asked (exactly the four fields the .hu
Domainregisztrációs Szabályzat §1.2.2.1 requires of a natural person — name, postal address,
notification e-mail, notification telephone; the optional mother's name, date of birth and ID
number are **not** asked for and **not** passed on), how it is asked (by e-mail, from him), who
receives it (Nethely Kft. as registrar, the .hu registry behind it, both named with their seats),
why, how long, and **what is public**: a natural person appears in the registry's own lookup as
„Természetes személy” and nothing else — *„A pontos személyes adatok nem nyilvánosak.”*
- **It also says whose Cloudflare account the zone sits in** (operator ruling, 2026-10-12: Felhom's,
during the test) and that the domain moves to the tester's own account when he leaves or the test
ends. That answers open point 9 of the privacy draft, which had stood unanswered since 2026-10-08.
- **§11 (recipients) gained the two new names.** A recipients list that omits two recipients is wrong,
so this one change beyond the new section was made deliberately; everything else is untouched.
- Version line → **1.1, hatályos: 2026. október 12.** Old §§10–13 are now 11–14; the single internal
cross-reference in the page points at §3.4 and was unaffected.
- **Proof that nothing else moved:** diffing the 1.0 record against the 1.1 record, the only removed
or changed lines are the record's own title and derived-on date, the version line, and the four
renumbered headings. Everything else in the diff is an addition.
- One more plural verb from yesterday's voice sweep fixed in the FAQ („megnézzük, felvehető-e” →
„megnézem”), in both copies of the answer, which is why gate 18 stayed green.
## 2026-10-12 (night) — the share card shows the product
The operator went to post the link and found the card out of date (2026-10-12): it was the
2026-07-18 design — a headline and two lines of text on a dark field, nothing of the product, and
older than everything the site has become since.
**Found while rebuilding the card:** the voice sweep reached the visible text and stopped there.
The contact pages' `description`, `og:description` and `twitter:description` still said „Írj nekünk
és személyre szabott ajánlatot készítünk” / „Write to us and we will make a personal offer” — six
lines nobody sees on the page and everybody sees under a shared link, which is precisely where the
operator was about to post one. First person now. The legal pages keep their plural on purpose:
their metas describe documents whose own text is plural and frozen.
- **`og-image.png` and `og-image-en.png` rebuilt around the laptop**, with the hero's own poster
frame on its screen: what somebody sees shared in a feed is now the thing itself.
- **The typography is the old card's, to the pixel.** The site's font is a woff2 and no font file
here can be handed to a drawing library, so `scripts/make_og_card.py` lifts the headline, the logo
and the button out of the previous card as pixels and composites them with `lighter` onto flat
`--bg-0` — the crop's own background is the same colour, so there is no seam. **Nothing in that
script draws a glyph, so new words cannot be made with it**: a new headline goes back to the
design tool and the script then takes that card as its source. The two lines of lede are gone
(they would have needed the font); the laptop says what they said.
- **`?v=2` on every `og:image` and `twitter:image`** (20 pages). A scraper caches by URL, so a new
picture at the old URL would have reached nobody. **A card already attached to a post does not
change** — that post has to drop the preview and re-add the link, after a re-scrape.
- The English card carries the same Hungarian-language Immich screen as the Hungarian one, because
it is the same recording the hero uses on both pages. Worth a retake if the English page ever
gets its own.
- **The wordmark is the brand's own now** (operator, 2026-10-12: *„the .eu is not blue”*). The old
card's lettering was plain white and set in some other face; the card takes
`assets/logo-wordmark.png` — the very file the sidebar shows — scaled to the old lettering's ink
height and alpha-composited in its place, so „felhom” is white, „.eu” is blue and the outline is
the drawn one. The cloud mark beside it is still the old card's pixels, which were always right.
`?v=3` on the og:image URLs.
## 2026-10-12 (review round) — the reviewer's findings, fixed
A page-by-page review of the live site (Playwright, 1440 px and 390 px) found six real defects and
two editorial questions. The operator answered three questions first; the answers are in
`REPORT-review-2026-10-12.md`.
**Fixed**
- **The contact form showed its consent error before anyone pressed anything** (both languages).
`#privacyError` sits OUTSIDE any `.form-group`, and the rule that hides error messages was scoped
to `.form-group`, so it never reached it — it was on screen from the first paint. Scoped to the
page instead. Checked: load (no error) — submit unticked (error) — tick (error gone).
- **The consent checkbox was the browser's own 18 px control.** It is the site's now: a 24 px box in
the design system's border and blue, a keyboard focus ring, and a second `<label for="privacy">`
wrapped round it at 44×44 px (pulled back with negative margins, so the layout does not move) —
a label toggles the control it names, so the whole square is tappable.
- **The contact page promised more than the terms allow.** It said „24 órán belül válaszolunk” while
`/feltetelek` 1.1 §4 says „Nem ígérünk válaszidőt”. Now: „Általában 1–2 napon belül válaszolok. A
zárt teszt alatt válaszidőt nem vállalok — ez a teszt feltételeiben is így áll.”
- **The services pages were missing from `sitemap.xml`.** `/szolgaltatasok` and `/en/services` added
with their hreflang pair; 18 URLs — 20.
- **A pre-shell mobile-menu script still ran on every inner page**, logging
`[mobile-menu] Missing elements` to the console. Removed from all 20 pages (the home pages never
had it). Its elements (`#hamburger`, `#mobileOverlay`) stopped existing with the M3 switch.
- **The sidebar's tester button looked second-class** — it was `btn-outline` while the hero's was
`btn-primary`. Both are primary now (that blue passes AA since R-930).
- **The home page's biggest section said nothing.** „Mit tud a doboz ma?” was three bare links; each
card now carries 2–3 of the services page's own item names, word for word, with the
„Minden szolgáltatás →” link kept under them.
- **A plain `Facebook` link in the footer** (all 22 pages, both languages), pointing at the Page. No
script, widget, pixel or embed — the privacy notice says the site loads nothing from anywhere
else, and that stays true.
**The voice** (operator ruling: *„‚I’ everywhere a person speaks”*)
- The contact, tester and FAQ pages in both languages now speak in the first person singular, which
is what the „Ki áll mögötte” bio already did and what is true: one person runs Felhom. The home
and services pages follow, so no sentence contradicts another.
- **An inclusive „we” stays plural** („Megbeszéljük”, „átbeszéljük”, „egyeztetjük” — you and I,
talking), and **the legal texts are untouched**, so `/adatkezeles` and `/feltetelek` are still
byte-for-byte what they were.
- Every FAQ answer exists twice (the FAQPage JSON-LD and the visible text) and gate 18 holds the two
equal, so each change was made to both copies — five answers carry `<strong>` inside the sentence
and the gate caught exactly those five when the first pass missed them.
- **„Miben segíthetünk?” is „Miben segíthetek?”**, and its list is what the closed test actually
offers (operator ruling): app installation, backup set-up, questions about the test. Server
consulting, maintaining someone else's server and remote-access set-up are gone.
**The hero clip, rebuilt**
- **Immich is the first scene**, so the poster — the still every blocked or paused video shows — is
a wall of real photographs rather than a cartoon llama.
- **The Jellyfin scene starts one second in**, after the demo's library wall. That removes eleven
pieces of film poster art whose licences cannot be quoted from a first-party source, and the
„Stable Demo” branding with them.
- **The film that does play is credited.** On Blender's own video platform *Caminandes 3: Llamigos*
carries `"licence": {"id": 1, "label": "Attribution"}` — CC BY, which **requires** attribution and
is **not** public domain, as this file wrongly said yesterday. The caption now reads
„A film a képernyőn: Caminandes: Llamigos © Blender Foundation, CC BY”, linked to the film's page.
- **1.3 s of blank screen is gone from the OnlyOffice scene** (a loading page, then an empty
spreadsheet before the data arrived): the scene is 0–3.30 s plus 4.60 s–end, cut on the frame.
- 34.3 s now: mp4 1 084 KB, webm 1 185 KB, poster 69 KB.
`site.css` — `?v=30` on all 22 pages; the clip and poster are `?v=2`.
## 2026-10-12 (night) — the headings are two-tone again, and the home page has rules between its sections
Both from the operator, 2026-10-12: the white/blue heading split was lost in the M3 switch and
should come back everywhere (*„on the apps page too, the categories should be white/blue”*), and the
home page's sections were hard to tell apart.
- **41 headings got their `<span>` back**, white lead-in and blue tail, which is what
`h1 span, h2 span, h3 span, h4 span { color: var(--blue-bright) }` has always rendered — the
rule never went away, the markup did. **No text changed**: the span is wrapped around words that
were already there, so every page says exactly what it said before.
- Home (5 + 5): the three that existed before M3 are split where they were split then
(`Mit tud | a doboz ma?`, `Így néz ki | a vezérlőpult`, `Hogyan | működik?`).
- Apps (6 + 6) and FAQ (6 + 7): **new**, these category headers never had it. A two-part name
splits at its `&` (`Fájlkezelés & | Irodai`), a phrase on its last words.
- Services (3 + 3): the three group headings.
- **Left plain, deliberately:** a one-word heading has nowhere to split — `Alapkérdések`,
`Költségek`, `Costs`, `Letöltés`, `Download`. Four other pages (technology, testing, backups,
contact) still carried their splits and were not touched.
- **A hairline between the home page's sections**, in the design system's own `--line`, with equal
air above and below it (2.75rem each) so the rule sits centred in the gap rather than hugging the
heading below. The first one also separates the hero from the page. Only the home page: every
other page is a single run of one kind of thing.
- Blue on the page background measures **7.9:1** — AA at any size, so the split is safe on the
small headings too.
- `site.css` — `?v=28` on all 22 pages.
## 2026-10-12 (night) — the laptop screen moves: six real apps behind the cut-out frame
The operator recorded the six scenes himself and ruled on their length: *„use the full length for
all of them, they had been cut as I liked them”*. Jellyfin, Paperless and RomM were filmed on those
projects' own public demo sites, so nothing in the clip is anyone's private library; ~~the films in
the Jellyfin scene are public-domain prints~~ — **that sentence was wrong, see the entry above
for 2026-10-12 (review round): the film that plays is CC BY, which is not public domain, and it is
credited on the page now.**
- **`website/assets/hero-clip.mp4` (1 134 KB) + `hero-clip.webm` (1 295 KB) + `hero-poster.webp`
(53 KB)** — Jellyfin, Tandoor, OnlyOffice, Immich, RomM, Paperless, in that order, 0.6s
crossfades, **36.6s** in all at 904×556 (2× the rendered size). Built by
`scripts/make_hero_clip.py`, which now plays each scene at its own length instead of a fixed
window.
- **The hero on `/` and `/en/` is the clip**, behind `hero-laptop-frame.webp`: `.hero-screen` sits
in the cut-out hole (`left 11.041%` / `top 12.345%` / `79.817%×64.305%`) at `z-index: 1`, the
frame above it at `z-index: 2`, so bezel, glare and keyboard stay in front of the moving picture.
- **Nothing autoplays by attribute.** `preload="none"` + a poster; the page's own script starts the
clip when it scrolls into view, pauses it when it leaves, and **never starts it at all under
`prefers-reduced-motion: reduce`**. With JavaScript off the poster simply stays. First paint costs
the frame (59 KB) + poster (53 KB); the clip is fetched after.
- **One set serves both languages** — the recordings are the same on both pages, so there is no
`-hu`/`-en` pair to keep in step. The still composites (`dashboard-laptop-{hu,en}.webp`) stay in
the repo, now unreferenced, as the fallback if the clip is ever pulled.
- Caption and `aria-label` name the six apps and claim nothing about whose box they ran on.
- **The language menu opened off the left edge of the window.** The controller's own rule centres
it on the globe (`left: 50%` + `translateX(-50%)`), which is right where the globe sits in the
middle of its row — but on the website the globe is at the far left of the sidebar footer, so
60 px of a 120 px menu hung outside the window and both labels were cut (operator, 2026-10-12).
Anchored to the button's left edge in the website's own file, opening rightwards into the
sidebar; `shell.css` stays a verbatim copy. Measured after: menu `x 24→144` inside a 240 px
sidebar.
- `site.css` — `?v=27` on all 22 pages.
- **Not verified: playback in this workstation's Chrome.** Its media pipeline loads nothing at all
today — a 1 KB generated WAV blob also stalls at `readyState 0` with no error, which rules the
clip out as the cause. Geometry, layering and the poster were verified in the browser; the moving
picture needs a Chrome restart to confirm.
## 2026-10-12 (evening) — the laptop frame, cut open for a moving screen
Prepared, **not yet on the page**: the live hero still shows the still. The clip itself is the
operator's to record (his decision, 2026-10-12: he films the apps, the assembly is built here).
- **`website/assets/hero-laptop-frame.webp`** (59 KB) — the same laptop render, with the **screen cut
out to transparency** so a clip can play underneath while the bezel, the keyboard and the glass
reflection stay on top. The reflection is painted, not lifted: lifting the bright pixels out of the
AI-drawn screen dragged a ghost of the drawn UI with it.
- The hole is `left 11.041% · top 12.345% · width 79.817% · height 64.305%` of the frame, ratio
**1.626:1**. Two pixels of slack: the lid keystones slightly, so a tight rectangle let the drawn
sidebar's highlight show and a loose one showed page background at the top left. Both were seen.
- **What will load, and when:** `<video muted loop playsinline preload="none">` with the first frame
as its poster, started only when the hero scrolls into view, and never started under
`prefers-reduced-motion`. First paint costs the frame (59 KB) + the poster (~80 KB) against today's
single still (57 KB); the clip itself (~330 KB) is fetched after, or not at all if the visitor
never reaches it. **No „loading" graphic is needed** — the poster is the loading state.
- Layering proven in the browser against a placeholder clip: content inside the bezel, frame on top,
and a magenta backdrop behind the frame showed the cut-out is clean all the way round.
## 2026-10-12 (afternoon) — four more notes, and the leak shape gate 22 could not see
`site.css?v=25`.
- **The home page talked about the operator in the third person** („Ha írsz, ő válaszol") while the
page it links to is in the first („Ha írsz, én válaszolok"). Both home pages now read
„**Nagyfenyvesi Viktor vagyok**, a Felhom mögött én állok" / „**I am Viktor Nagyfenyvesi**, and I
am the one behind Felhom", and the link after it is „Rólam bővebben →" / „More about me →" rather
than repeating the question the sentence has just answered. The legal pages keep the formal
third-person name, which is what they are for.
- **36px of dead space under the language globe, and the cause was a leak.** The old chrome's
`nav { position: fixed; padding: 20px 0; backdrop-filter: blur(12px); z-index: 200 }` is a **bare
element selector**, so it matched `<nav class="sidebar">` too — and `.sidebar` declares none of
those four properties, so all four were in force on the sidebar. The rule is scoped
`body:not(.shell)` now, and the footer row's own padding went from 16px to ~8px. Gate 22 could not
see this: it compares selectors that appear in BOTH stylesheets, and `nav` is not a selector
`shell.css` ever writes.
- **Gate 22 now also refuses a bare `nav`/`header`/`main`/`aside` rule** that is not scoped — the
shell's own elements are `<nav class="sidebar">`, `<header class="mobile-topbar">` and
`<main class="content">`, so an unscoped element rule reaches them whatever shell.css calls them.
It convicted a second one on its first run: `@media (max-width: 900px) and (scripting: none)
nav { position: static }`, R-903's no-JavaScript fallback, which had been overriding the sidebar's
`position: fixed` on a phone with scripting off. `footer` is deliberately NOT on the list: the
shell carries the website's own footer, so those rules are meant to apply.
- **The comparison table and the two cards under it were touching** on the home page — `.vs` ends on
its own border and `.band` opens with a 2px blue rule, so they read as one block. 2rem between them.
- **„Minden alkalmazás" is now „Az alkalmazásokról" / „About the apps".** Every app is on that one
page, so the first submenu item is not a filter — it is the top of the page, where the intro and
the „Fontos tudnivalók" box are.
## 2026-10-12 — the operator's seven notes from his own screens
Seven things, found by looking at the live site on a desktop and a phone. Five were defects, two were
design. `site.css?v=24`.
- **The category links in the sidebar were dead — all 100 of them.** The five app-category items
pointed at `#fajlkezeles-irodai`, `#media-szorakozas` and friends; the sections' ids are
`#fajlkezeles`, `#media`. The sidebar is copied into every page, so one wrong fragment was wrong
twenty times, and a dead fragment raises no error anywhere — the browser simply stays put.
**New gate 23** resolves every in-site `#fragment` against the page it names (360 of them today),
and it found two more live ones while being written: the home page's four hero tiles pointed at
`/alkalmazasok#immich` and friends, which nothing had ever carried, and the FAQ's contact button
pointed at a home-page section that moved out. **Every app card now carries its slug as an id**, so
`/alkalmazasok#immich` works — the slug comes from the card's own logo file, which gate 21 already
ties to the catalog.
- **„Szolgáltatások" is a page now**, `/szolgaltatasok` and `/en/services`, not an anchor into the
home page. The ten capability items moved verbatim; the home keeps the promise sentence, the three
group names as links, and a button. The home page is 345 Hungarian words shorter.
- **The home headline is back in the hero**, beside the picture, two lines with the second in
`--blue-bright` at `clamp(2.1rem, 4.4vw, 3.2rem)` — the shape and size it had before M3. It had
been moved into `.page-header`, which is the INNER pages' heading, so it shrank to 2.1rem and the
domain badge ended up stranded beside it.
- **The hero picture is a real screenshot in a laptop.** The frame is the operator's own supplied
render; the screen is `dashboard-start-{hu,en}.webp` composited into it, so what a visitor sees is
a real box's Launcher and not a drawing of one. 57 KB, named `dashboard-laptop-<lang>.webp` so
gate 19 holds it to the page's language like every other dashboard picture.
- **`.page-lede` had no CSS at all** — on 16 pages it rendered as a bare paragraph the full width of
the content column, hard against the box beneath it. It now shares the box's 760px measure, sits
over its centre, and has 28px of air beneath.
- **The sidebar logo**: the wordmark was 0.67× the mark's width where the real lockup
(`assets/logo.png`, measured) has it at 1.28× — less than half the intended size. Mark 112px,
wordmark 25px tall, and 28px less vertical padding.
- **The scrollbars are the page's own**, thin and in the palette. The first attempt missed the big
one: the viewport's scrollbar is painted from `<html>`, and a `body.shell ::-webkit-…` rule only
reaches scrollers inside the page.
- **The two Latin font subsets are preloaded.** With `font-display: swap` the page reflowed after
first paint; measured on `/alkalmazasok#media`, the anchor target sat 1339px lower once the font
arrived.
## 2026-10-11 (evening) — the two M3 defects a real phone found, and the gate that now holds them
Both were mine, both shipped in the morning's switch, and both were reported by the operator from his
own phone rather than caught here. `site.css?v=23` / `shell.css?v=23`, live 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, because under `@media (max-width: 900px)` it sets
`.nav-links { position: fixed; right: -100% }` — which parked the menu off-canvas *inside* the open
drawer. Fixed at the source: every selector belonging to the website's OLD chrome (`nav`,
`.nav-links*`, `.mobile-overlay`, `.hamburger`, `.logo*`, `.lang-globe-li` — 29 occurrences) is now
scoped `body:not(.shell)`. Scoped, not deleted, so a page without the shell still works.
`.hamburger-box` and `.hamburger-line` stay unscoped on purpose: the shell's burger uses them.
- **Why the morning's check missed it.** The STOP-1 leak diff compared the two stylesheets'
declaration sets **with `@media` blocks excluded**, and reported „exactly six" leaking declarations.
Media-aware, the number is **forty** — and the worst of them only apply below 900 px, which is why
the desktop looked right and a phone did not. A check that silently skips part of its subject is not
a check; this one returned a confident wrong number and was believed.
- **The footer rendered as a second column** at the top right of 16 pages. `body` is a flex row on a
shell page, and the 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 of `body` — a flex
sibling of the sidebar. Moved inside `<main class="content">` on all 16, each move asserted to have
landed inside.
- **Both are now gated, each red-proofed by putting the live defect back** (`site_gates.py` gate 3b
and the new gate 22; decoys `site/footer-outside-main` and `site/shell-css-leak-in-media`).
## 2026-10-11 (M3) — the whole site moves into the controller's shell
The operator's own direction, after three mockups were rejected: the **controller's frame** (left
sidebar, phone top bar, off-canvas drawer) around **the website's own content**. Switched in one
commit — never half old, half new. 20 pages: 12 Hungarian, 8 English.
- **`website/assets/shell.css`** — **117 rules copied VERBATIM** from
`felhom-controller/controller/internal/web/templates/style.css` @ `dcd89364a4`, plus **exactly one
adapted rule** that says so (`body.shell { display:flex; min-height:100vh }`, which lives in the
controller's base rather than in a component, scoped so a page without the shell is untouched).
The generator **names every rule it copies and refuses to write the file if one has disappeared
upstream** — which already caught two things: a selector that no longer exists, and
`prefers-reduced-motion` being split across **five** separate blocks, four of which a naive copy
would have lost. That is M1's failure, prevented.
- **`shell.css` loads after `site.css` deliberately.** Thirteen selectors exist in both with
different meanings. „Later wins" is **per property, not per rule**, so six declarations still
leaked through and are reset in `site.css`: `.nav-links` `display:flex`+`gap` (the sidebar rendered
as a horizontal row across the page), `.lang-globe-menu` `top`+`right`, `.page-header`
`padding`+`text-align`. Found by diffing declaration sets, not by looking — only one was visible.
- **The footer is kept**, carried verbatim into the bottom of the content column. Stripping the old
chrome had removed it from all 19 pages, taking with it the only route to the **Adatkezelési
tájékoztató and the Feltételek**, the operator's name and `info@felhom.eu`. Caught before the
switch.
- **The English home page is now a true twin** of the Hungarian one (operator's decision): every
string lifted verbatim from the live English page, except twelve faithful translations of sentences
the `/preview/` round introduced. 35.8 KB → 25.4 KB.
- **Em dashes: 326 replaced** with the Hungarian gondolatjel across 17 pages. The FAQ pages' JSON-LD
is swept with the same substitution so it still equals the visible answers (gate 17 green).
**The legal texts are byte-identical** — proven by a word-level diff with no substitution allowed.
- **`site.css`** gains the M3 page rules, the six leak resets, AA fixes for the copied
`.btn-primary` and `.nav-group-label`, and `overflow-wrap` for long checksums and URLs — the last
one repairing a **pre-existing** sideways scroll on `/letoltes` and `/adatkezeles` (609 px and
478 px at a 390 px viewport, measured on the live pages).
- **`website/preview/` deleted entirely** (the A, M1, M2 and M3 studies) with its `robots.txt` line.
`site.css?v=22` / `shell.css?v=22` everywhere.
- **`scripts/site_gates.py`**: gate 3 extended rather than duplicated — a `SHELL` set whose pages must
carry an **identical sidebar and footer**. `is_en()` makes the language gates path-aware.
`norm_block()` also normalises `is-open`/`aria-expanded`. Every change red-proofed, the loosening
one **both ways**: a one-character menu difference convicts, a state-only difference does not.
**What the head-tag diff caught, and why it was worth doing.** Head tags were captured on all 19
pages before the switch and compared after. The home page was about to ship carrying
**`noindex, nofollow`** from the preview, and had lost `meta keywords`, `meta author`, all seven
Open Graph tags, all four Twitter tags and the `LocalBusiness` JSON-LD — because its head was
hand-built while every other page carried its live one over. Nothing on the rendered page would have
shown it. After the fix the **only** head-tag difference anywhere is the dash substitution inside the
two FAQ pages' JSON-LD, verified by applying the same substitution to the „before" copy and getting
an exact match.
**Live read-back, all 20 pages:** 200, sidebar present, footer present, legal link present,
`?v=22` on both stylesheets. Home page: 12 requests, 282 KB, zero third-party hosts, `index, follow`,
canonical and JSON-LD intact, **0 em dashes**, 10 967 px → 4 340 px tall.
## 2026-10-11 (este) — „Ki áll mögötte" a kapcsolati oldalakra költözött
Operator's call after seeing the preview. **This one IS live**, on `/kapcsolat` and `/en/contact`;
the home page itself is still the old design.
- **The full block moved to `/kapcsolat` + `/en/contact`.** On the home page it sat between the
dashboard gallery and „Hogyan működik?", interrupting *what it does* → *how you get it* with a
life story — and its last sentence, „Ha írsz, én válaszolok", is a contact-page sentence that
belongs beside „Válaszidő". Both halves of the twin moved in the same commit; the English uses the
site's established „the box" and promises nothing the Hungarian does not.
- **The home page preview keeps a compact trace** in its closing call to action: a 56×70 portrait,
one line, and a link to the full block. Deliberate, not a leftover — the audit's **R-11** finding
was „nobody is behind it" *on the home page*, so deleting every human trace would have re-opened
it. The preview is now **9 sections, 9 layout families**, 6 385 px at 1440 and 10 145 px at 390
(from 10 922 / 19 913: 42% and 49% shorter).
- A dedicated `/rolam` page was weighed and rejected: five sentences cannot carry a page, and filling
one would have meant inventing biography.
- **The `.who*` rules are no longer page-scoped.** They were `.page-index .who*`; the block now lives
on two pages and will live on the home page's twin later, so it follows `69035f4af5`'s lesson that
a genuinely shared pattern goes site-wide rather than being duplicated per scope. No existing page
used `.who`, so nothing else moved.
- `assets/operator-portrait-small.webp` — 160×200, 8.4 KB, same crop, metadata stripped and verified
by read-back.
- **A layout bug caught by looking at the deployed page**, not at the markup: `.who-mini` was
`inline-flex` inside a `text-align: center` block, so it flowed onto the same line as the CTA
button and pushed the pair off-centre. Now `flex` with `max-width` and `margin: auto`.
- `site.css?v=` → 14 on all 21 files.
## 2026-10-11 — the footer dash site-wide, and the primary button meets WCAG AA
Two operator decisions taken at the redesign review. **The home page itself was NOT switched** — the
operator chose to sit with the preview, so `/` still serves the old design. Only these two things
changed on it, and on every other page.
- **The footer's em dash became the correct spaced en dash, on all 21 page files** (12 Hungarian,
8 English, plus the preview). It could never have been a one-page edit: `site_gates.py` gate 3
requires every page in a language set to carry an **identical** footer. Verified on all 18 live
URLs after deploy: `em=0 en=1` on each.
**Scope, stated:** this clears the footer only. **300 em dashes remain in the bodies of the other
19 pages** (`gyik` 53, `en/faq` 53, `adatkezeles` 33, `szolgaltatasok-nonpublic` 27, `teszteles` 23,
`en/testing` 24, `index` 17, `en/index` 19, …). Enumerated per page in
`documentation/audits/redesign-2026-10-10/NEXT.md`. The preview is the only page at zero.
- **R-930 — `.cta-button` is now 1.2rem/700** (was 1rem/600). White on `--blue` measures **4.01:1**,
under WCAG AA's 4.5:1 floor for body text; at ≥ 18.66 px and ≥ 700 weight WCAG counts the label as
**large text**, where the floor is 3:1 and 4.01 clears it. Chosen by the operator over darkening
`--blue`, which is shared with the hub and controller UIs. Horizontal padding trimmed 32→26 px to
protect the one-line rule for the longest label.
**Measured, not assumed:** every primary button renders on **one line** and **no page overflows**,
checked in the browser on 11 pages at both 390 px and 1440 px. The defect was pre-existing and
site-wide — it measured the same 4.01:1 on the live page before any of this work — so the fix
reaches the primary button on 16 pages, which is the point. `.cta-button-secondary` is untouched at
7.17:1.
- **`site.css?v=` → 12 on all 21 files.** The pages sat at `v=10` and the preview at `v=11`; leaving
them split would have served a returning visitor the old stylesheet and the change would have
looked like it did not deploy.
## 2026-10-10 (este) — a redesigned home page, staged at /preview/
- **Why:** the home page read as AI-made — eleven sections but only eight layout families, every
section header the same centred two-word-plus-blue-tail shape, the hero showing the **logo** where the
product belongs, and a value proposition („Professzionális otthoni szerver telepítés és
üzemeltetés") that says nothing. Measured audit, against the live site:
`documentation/audits/redesign-2026-10-10/AUDIT.md`.
- **`website/preview/index.html`** — the new home page, `noindex` + `Disallow: /preview/`, not in the
sitemap, linked from nowhere. It becomes `index.html` only on the operator's go.
- **New: „Ki áll mögötte"** with the operator's photograph and five sentences in his own words.
Every claim traced in `audits/redesign-2026-10-10/ki-all-mogotte.md`. The photo
(`assets/operator-portrait.webp`) is cropped from an original that **stays outside the repo**, and all
metadata is stripped and **verified by read-back** (0 EXIF tags, 0 GPS entries, and none of the phone's
identifying byte sequences survive). The original carried no GPS tag to begin with; it did carry the
phone model and the timestamp.
- **Ten sections, ten different layout families.** `why-grid` no longer runs three times and
`apps-showcase` no longer twice: the ten capability cards become three labelled clusters, the three
cloud-problem cards and the four own-server cards merge into **one two-column comparison**, and the two
tile walls shrink to a two-item band that keeps the app names and links to the pages that already list
them.
- **The hero** shows a real dashboard screenshot instead of the logo, is sized by its content instead of a
forced `100vh` band, and drops the infinite float animation. Its sentence is now four concrete facts.
- **Numbers off the mono font.** The `1..5` process badges and `01..05` service numbers are gone
(taste-skill §9.F), and the 3-2-1 figures move to the UI font — together these were the **only** 13
characters on the page loading JetBrains Mono, so the page no longer fetches it.
- **Em dashes: 18 → 0** in the page's own copy. The `<title>`, meta description, Open Graph, Twitter and
JSON-LD keep theirs by operator decision (they are indexed strings; changing them deserves its own
pass). **One remains in the shared footer**, which gate 3 requires to be identical on all 14 pages —
a site-wide edit, carried as a separate decision.
- **CSS: additions only.** Every new rule is a new class under `.page-index`; nothing existing was
modified, so `index.html` and every other page render exactly as before while the preview exists.
`site.css?v=11` on the preview page only.
- **Gate:** `preview/index.html` is registered in `site_gates.py` `NO_TWIN`, with the reason in a comment
— a preview URL **cannot** go in `TWINS`, because gate 3 wants its nav identical to `index.html`'s
(globe pointing at `/` and `/en/`) while the twin check wants the globe pointing at the pair's own URLs.
The English twin is written in the same commit as the switch, as a real twin.
- **CRLF, again.** The page builder wrote LF and the nav/footer gate went red for the preview exactly as
the 2026-10-10 morning entry above describes. Builder now writes **BOM + CRLF** and asserts both.
## 2026-10-10 — a tester recruitment page, and terms 1.1 (the domain)
- **New page pair: `/teszteles` + `/en/testing`** — the website asked for testers without saying what a
tester needs or what Felhom pays for. The page states it: who it is for (a Hungarian household, no IT
knowledge, but patience), **what you need** (a machine that can stay on and home internet — both
**quoted verbatim from the FAQ** rather than invented, plus a domain), **what you get** (the six
promises of the test terms §3, nothing new), what we ask for (feedback; the terms' own „keep your own
copy"), and **how many places there are**. No price, no availability promise, no response-time promise.
- **Operator ruling D1 (2026-10-10) — the domain:** registered in the **tester's own name**, Felhom pays
its fee **for two years**, and **the tester keeps it** when the test ends or they leave. DNS is managed
with a token scoped to **that one zone only**. Recorded in `CONTEXT.md`.
- **Operator ruling D2 (2026-10-10):** the closed test runs with **at most 5 households**; the page says
„legfeljebb 5 háztartás".
- **Terms 1.1** (`feltetelek.html`, record `documentation/legal/feltetelek-1.1.md`): one new section,
**§4 (the domain)**, with the D1 text. Sections 4–11 of 1.0 are renumbered 5–12; nothing else changed.
No document or page referenced those numbers — checked before renumbering. The terms' §11 promises
testers an e-mail before a change, so one is drafted at `marketing/testers/EMAIL-terms-1.1.md` for the
operator to send.
- **Every „Jelentkezem tesztelőnek" button now goes to the page**, not to an anchor or the contact form:
the home page hero (was `#zart-teszt`) and its „Zárt teszt" section (was `/kapcsolat?tema=zart-teszt`),
and the English pair. **The contact form needed no change** — `?tema=zart-teszt` already preselects the
closed-test subject on both contact pages, so the page's apply button uses it.
- **Registered and listed:** the pair is in `site_gates.py` `TWINS` and `URL` (gate 13 refuses a page the
gates do not scan), and both URLs are in `sitemap.xml` with their hreflang trio — 18 URLs now.
- **Encoding, the hard way:** rewriting pages with a Python helper converted five files from the working
tree's **CRLF to LF**, which made `index.html`'s nav and footer differ from every other page's and
turned the nav/footer gate red for all 15 pages at once. The cause looked like a content change and was
not. Restored to CRLF, BOM intact; `site_gates.py` green.
## 2026-10-10 (afternoon) — the phone menu works with JavaScript off; the dashboard pictures retaken
- **R-903: on a phone with JavaScript off the menu links and the language globe were unreachable** (the three-line
button is scripted; the list sat off-canvas). `site.css` now has `@media (max-width: 900px) and (scripting: none)`:
the list sits in the header as a wrapped row and the header scrolls with the page. Script-on pages are unchanged.
`site.css?v=9` on all 18 pages. Measured in headless Chrome at 376 px, JavaScript off, `/` and `/en/`: links reachable
0/7 before, 7/7 after; with JavaScript on, the closed menu is as before
(`documentation/audits/register-shrink-2026-10-10/r903-phone-nojs.txt`).
- **R-910: all eight `dashboard-*.webp` retaken** on demo-hp's household guest (Launcher, Apps, Paperless-ngx's page on
controller 0.305.0; Backup → Apps on 0.307.0), hu + en, 1440 × 900, WebP q82. The Apps card shows the new header
(tags on their own row). Captions unchanged — every caption's claim still holds. Privacy scan:
`documentation/audits/register-shrink-2026-10-10/r910/`.
## 2026-10-10 — two new apps on the apps page: Grocy and LubeLogger
- **Two cards added** to the „Otthon & Életmód" / "Home & Lifestyle" section of both apps pages, in the
same commit: **Grocy** (household stock, shopping list, barcodes, chores) and **LubeLogger** (the family
car's services, fuel, reminders and costs). Both went through `NEW-APP-CHECKLIST.md` end to end;
the records are in the catalog and the evidence in `documentation/audits/new-apps-2026-10-10/`.
- **Assets**: `grocy-logo.svg` is grocy's own `public/img/icon.svg` with its single fill made white, like
the other logos; `lubelogger-logo.png` is the app's own icon with its dark background dropped and the
mark made white, the same rule SparkyFitness's PNG follows. The six screenshots are each app's own
**Hungarian** UI with a household's own data, taken headless on the bench from the published template.
- **The app count moved 56 → 58** in every place the website states it, in both language sets (15 places
each): the apps page title, meta description, og:title, twitter:title, the JSON-LD `numberOfItems`, the
page's own sentence and its stats tile; the home page's meta description, feature heading and line; two
FAQ answers and their JSON-LD copies; and the technology page's bullet. The open-source tile moved
**49 → 51** (both apps are MIT). Checked by re-running the same patterns against the new number.
- **Not changed, and said here instead:** `marketing/facebook/COPY.md` §2 still says „56 alkalmazás" in
the post drafts, and the post scheduled for 2026-10-12 carries that number. It is already written and
the brief forbids editing posted text, so it stays — the next post should say 58.
## 2026-10-08 (evening) — every app logo white; five logo sets renamed to the catalog's names
- **Seven coloured logos made white like the other 49** (operator request): Mealie (one fill → white), Homebox (white
line drawing), Dawarich, Komga, Radicale, Recipe Importer (an in-file `feColorMatrix` filter: coloured and dark parts
white, white parts see-through; Dawarich keeps only its route, Recipe Importer keeps the white cloud), SparkyFitness
(PNG, same rule). Checked rendered in headless Chrome against the white logos. These files are also the dashboard's
logos (the controller and hub builds copy `*-logo.*` from here).
- **Renamed to the catalog slug** (the dashboard asks for `<slug>-logo.svg` / `<slug>-screenshot-N.webp`, so these five
showed the grey placeholder and no pictures there): `crafty` → `crafty-controller`, `grampsweb` → `gramps-web`,
`homeassistant` → `home-assistant`, `plantit` → `plant-it`, `uptimekuma` → `uptime-kuma` (24 files, `git mv`); 40
references each in `alkalmazasok.html` and `en/apps.html` (paths and `data-gallery` set names).
## 2026-10-08 (late afternoon) — one picture viewer for the whole site
- **`assets/gallery.js`** — the viewer that lived twice inline on the two apps pages is one shared file now (`defer`,
`?v=2` — v2 keeps focus inside the viewer when the last „next" turns off), its markup built by the script. The dashboard pictures (home and technology, both languages) open in it too,
as one set: Launcher → Apps → an app → Backups.
- **A set is declared, not guessed:** every picture is a real `<a href="/assets/…webp" data-gallery="<set>">`; an app
card's further pictures are hidden links in the card. The old probing for `-screenshot-N.webp` files is gone (no
request for a picture that is not in the page). JavaScript off: the link opens the picture, as before.
- **New: a click or tap on the big picture closes the viewer** (the close button, Esc and a click beside it still do);
a swipe changes the picture and does not close. Labels follow `<html lang>`; focus goes to the viewer and back to the
clicked picture; the page does not scroll behind it.
- `site.css`: the `.lightbox-…` rules are no longer scoped to the apps page; `?v=4` → `?v=5` on all sixteen pages.
- Gate 20 (`scripts/CHANGELOG.md`).
## 2026-10-08 (afternoon) — the dashboard, shown
- **A new section after „Mit tud a doboz ma?" / „What the box does today"**: „Így néz ki a vezérlőpult" / „What the
Dashboard looks like" — four real screenshots (Launcher, Apps, an app's page, Backup → Apps), each with a one-line
caption; the technology page's dashboard card gets the Apps and Backup pictures. Hungarian pages show the Hungarian
dashboard, English pages the English one.
- Taken on demo-hp's household guest (controller 0.303.0, no warnings, last night's backups OK); 1440 × 900 WebP,
31–83 KB each; `loading="lazy"`, `width`/`height` set, each links to its full-size picture (no script).
- `site.css`: `.dash-grid` / `.dash-shot` (two per row, one below 700 px); `?v=3` → `?v=4` on all sixteen pages.
- Gate 19: a page may only show dashboard pictures in its own language (decoy seen failing first).
- Evidence, captions-to-capability rows and the privacy scan: `documentation/audits/website-dashboard-2026-10-08/`.
## 2026-10-08 — the FAQ's GDPR answer tells the truth about where copies and traffic go (R-900; operator approved the text in chat)
- `gyik.html` and `en/faq.html`, the GDPR answer, both the visible text and its structured-data copy: the line „az adataid a
saját infrastruktúrádon vannak — nem harmadik félnél" / „not with a third party" is replaced. It now says the data lives
on the household's own box; backup copies are encrypted on the box before they leave and stored at Hetzner in the EU
(Germany), where the provider cannot read them; remote access goes through Cloudflare, which could technically see that
traffic; small businesses are pointed to the privacy notice (not published yet, so no link). The „not lawyers" line
stays. Searched the rest of the site (ASCII fragments, positive control „Hetzner" = 2 per page): no other page makes
the claim.
## 2026-10-08 (later) — the language switch becomes a globe, like the dashboard's
- The text link in every page's nav („English" / „Magyar") is replaced by a **globe** (`i-globe` from the sprite): a
`<details>` whose list names each language in its own language — Magyar, English, in that order on every page. The
page's own language is marked (bold, a blue rule, `aria-current="true"`); the other item goes to the twin page.
`aria-label`/`title` „Nyelv" / „Language". Works with JavaScript off; no script added (the controller adds none).
- Phone: inside the opened menu the globe is the last item and its list opens in place.
- `site.css`: the globe's rules (desktop and the ≤900 px menu); `?v=2` → `?v=3` on all sixteen pages. There was no
`.lang-switch` rule to retire — the text switch was unstyled.
- `404.html` and the hidden prices page carry the globe too (their foreign item points at `/en/`): the shared nav
must compare equal across the Hungarian set, so they keep what every page carries.
- Gates: the globe replaces `SWITCH_RE` in gates 3 and 13 (`scripts/CHANGELOG.md`).
## 2026-10-08 — the website catches up with the product: true numbers, the missing apps, an English twin of every page
The last content refresh was 2026-07-18. Every claim on the eight public Hungarian pages was checked again against
`documentation/architecture/00-capability-map.md` (and `07`, `09`, `10`, the catalog, the licence read) — the
table is `documentation/audits/website-refresh-2026-10-08/claims.md`. No redesign; the July tone and layout stay.
- **One app count, measured: 56.** The catalog has 58 templates; `plant-it` (abandoned) and `wger` (hidden) are
not offered to a household (`visibleCatalogStacks`). „53" and „több mint 45" are gone from every page, title,
meta tag and JSON-LD (`numberOfItems` read 45).
- **„100% nyílt forráskódú" was false.** The licence read (`audits/licences-2026-10-02/TABLE.md`): Plex and Emby are
proprietary; n8n, Outline, Tandoor and SparkyFitness carry restricted licences; Recipe Importer is Felhom's own.
Now „szinte mind"; each exception carries its own badge (*Zárt forráskód* / *Korlátozott licenc* /
*Felhom saját*); the stat reads 49 open source.
- **The apps page shows what a household can install.** Plant-it and wger cards cut; ten cards added (Dawarich,
Docmost, Grimmory, Homebox, Karakeep, Mealie, MeTube, Radicale, Recipe Importer, SparkyFitness), Hungarian
from the catalog's own text. FileBrowser stays, badged *Beépített* (it is on every box, not in the catalog).
Calibre-web → Calibre-Web Automated (the image the catalog ships). Twelve logos pointed at a missing `.svg`
and fell back to `.png` through an `onerror` — they point at the `.png` now.
- **Claims cut or softened** (no capability row): firewall/Fail2ban/geo-blocking/WireGuard-for-households, RAID,
„pillanatkép minden változtatás előtt" (the update path takes a backup and undoes itself — that is now said),
„egy új gépre visszaállítható", the „önálló modell", „bármilyen nyílt forráskódú alkalmazás telepíthető",
household VPN, „soha nem vész el" ×4, the off-site „havi pár száz forint" (the operator's own price is per
100 GB), „TV-re streamelés hamarosan" (now „még nincs").
- **Added, each on a PROVEN-LIVE row:** backups on three levels (on the box, a second drive, encrypted off-site);
careful app updates (tested versions only, a backup first, the box undoes a failed update); the dashboard in
Hungarian or English; OS security updates (the kernel lane is not claimed).
- **`technologiak.html` showed a file-dump footer** („Summary: 13 files included, 218 skipped") under `</html>`
— removed; a gate now refuses text after `</html>`.
- **`404.html`** — nginx's `error_page 404` pointed at a page that did not exist. Hungarian first, one English line,
a link home; `noindex`.
- **The English twin of every public page** (operator ruling 2026-10-08; choice B — public at once):
`/en/`, `/en/apps`, `/en/technology`, `/en/backups`, `/en/faq`, `/en/contact`, and `/en/download` moved onto the
new English nav and footer. `hreflang` hu/en/x-default both ways, `canonical` to itself, `lang="en"`, English
JSON-LD (the FAQ's JSON-LD is now rebuilt from its visible answers on both pages — the Hungarian one had drifted
from them), an English `og-image-en.png` (the card carries Hungarian text). The English footer says Felhom
serves households in Hungary. The contact form posts to the same `/api/contact` with English subject labels
marked „(EN)"; `?tema=` takes the same values.
- **The language switch** — one nav item on every page, „English" / „Magyar", pointing at the twin; it replaces the
header link R-559 put on the two download pages. No redirect, no cookie.
- **`sitemap.xml`** lists both languages with `xhtml:link` alternates.
- Gates: `scripts/site_gates.py` gates 3 and 13–18, eleven new decoys (see `scripts/CHANGELOG.md`).
**Published:** push to `main`, git-sync. No `site.css` or `icons.svg` change, so no cache-bust bump.
## 2026-09-18 — an English download page (R-559)
- **`website/en/download.html`** — the English twin of `letoltes.html`. Same installer, same checksum,
same structure; `<html lang="en">`, its own English nav and footer, `hreflang` alternates both ways
(`x-default` points at the Hungarian), and an entry in `sitemap.xml`.
- **`letoltes.html` changed by FOUR lines and nothing else**: three `hreflang` alternates and one
`English` link in the page header. The link is deliberately **not** in the nav — the nav is a shared
block that `site_gates.py` pins across every page, and the gate convicted the first attempt, which
is how the link found its right home.
- **The rest of the marketing site stays Hungarian** (operator ruling 1b, 2026-09-17).
- **New gate 12: the two download pages must name the SAME installer file and the SAME checksum.**
Publishing an ISO now means editing a filename, a size and a 64-character hash on two pages; update
one and forget the other and an English reader checks a new image against an old hash, fails, and is
told by the page itself not to use the file. Red-proofed both ways.
- `en/download.html` is registered in `PAGES` and in the new `EN_PAGES` set, which exempts it from the
Hungarian nav/footer comparison and from nothing else.
**Published:** the site's normal path — push to `main`, git-sync picks it up in ~1–2 min. No
`site.css` change, so no cache-bust bump was needed.
# website/ changelog (newest on top)
## 2026-09-15 — New page: /letoltes (the installer download)
The volunteer guide sends people to `felhom.eu/letoltes`; the page did not exist. It now names installer
**1.27.1**, its size and SHA-256, how to check the sum on Linux/Mac and Windows, and — first — the disk
warning: the installer erases the disk you choose, never picks one, unplug the backup drive, call the
operator if unsure. `noindex` (it is for people holding the guide). Same skeleton as the other pages, no
nav entry; added to `sitemap.xml` and to `scripts/site_gates.py` PAGES; site gate OK. Published together
with the ISO (round trip verified first), so the link never pointed at a missing file.
## 2026-07-19 — Restored: the index grid background
The subtle grid behind the hero was **not** removed on purpose. It lived as a fixed `body::before` in
`index.html`'s inline `<style>` block and was dropped when `bed8675` ("D3 Part 2") migrated the page
onto the shared `assets/site.css`; `dd54e4c`, the commit that created `site.css`, has no
`body::before` at all. A porting omission, and nothing took its place. No asset was lost — it was
pure CSS (two stacked `linear-gradient`s), so there was nothing missing from the worktree to notice.
Restored, not redesigned: same 50px cells, same 1px lines, same 3% opacity, same `position:fixed` /
`z-index:-1` so it does not scroll. One deliberate difference — the accent is the v2 `--blue`
`#0083D8` instead of the retired legacy `#0088cc`, which `site_gates.py` bans. Scoped to
`body.page-index`, because index is the only page that ever had it.
`site.css` cache-bust bumped `?v=1` → `?v=2` on all seven pages (nginx caches 7 days). Verified live
on desktop and in a 376px viewport: grid renders, no horizontal overflow, mobile layout unchanged.
## 2026-07-18 — Pre-Facebook content refresh: capability-map alignment + „Zárt teszt" landing
The site's audience changes from zero-stakes to real Hungarian households arriving from a Facebook
post, mostly on phones. Every claim re-checked against
`documentation/architecture/00-capability-map.md`; overclaims cut, the last week's shipped
capabilities added. No redesign — the design language, nav, footer, and CSS are untouched.
- **Naming ruling applied — „Felhő Felügyelő" is gone (0 occurrences site-wide).** The brand is
**Felhom**; the customer-facing interface is the **vezérlőpult** (matching the controller login
page). 14 occurrences replaced across `index.html` + `technologiak.html`, incl. `<title>`,
meta description, keywords, og/twitter descriptions, and the JSON-LD `description`.
- **`index.html` — new „Mit tud a doboz ma?" section** (8 cards, every one map-traceable):
photos/documents/media, **Hálózati megosztás** (Windows Intéző + Mac Finder, map §E
PROVEN-LIVE 2026-07-18), two-tier automatic backup, **the recovery code only the customer
knows** (zero-knowledge wording, map §A escrow PROVEN-LIVE), 53 apps, remote monitoring +
automatic updates, LAN-works-when-the-internet-is-down, restore-when-something-breaks.
- **`index.html` — new „Zárt teszt" section** (the Facebook post's landing target): what being a
tester means, and the **stated limitations** — one shared household password for the vezérlőpult
(map §E multi-user = MISSING), **TV-re streamelés hamarosan** (map §E DLNA = MISSING), and an
explicit "you will find bugs, that's the point". CTA wires to the **existing, live**
contact-mailer as `/kapcsolat?tema=zart-teszt`; no new backend.
- **`kapcsolat.html`** — new „Zárt teszt — jelentkezem tesztelőnek" subject option + its label
mapping (mail subject `Jelentkezés — zárt teszt`), and a `?tema=` preselect that ignores
unknown values.
- **`og:image` was a 404 site-wide** — every page pointed at `/assets/og-image.png`, which did not
exist (only `.svg` did). A branded **1200×630** card is now generated from the existing logo and
brand tokens, plus `og:image:width/height/alt`. This was load-bearing for the Facebook post:
the link previously would have rendered with no image.
- **App count corrected 45+ → 53** (real catalog count: 53 `*.felhom.yml` templates) in
`index.html`, `technologiak.html`, and the four `alkalmazasok.html` head tags.
- **Overclaims cut:**
- The whole **Kubernetes/k3s section** in `technologiak.html` (+ its TOC entry and the
multi-node hardware tier) — no customer-facing capability-map row backs it, and it carried a
bare availability promise („a szolgáltatás nem állhat le") on a page now read by recruits.
- **Tailscale VPN** → **WireGuard VPN** (Tailscale is not what ships).
- The **RAID** card → an honest two-tier backup card; the „4-8 TB (RAID)" spec row → „4-8 TB".
(RAID has no map row; the shipped model is second-drive tier-2 + encrypted offsite.)
- **`gyik.html` multi-user answer** rewritten in both copies (JSON-LD **and** the visible
accordion — they must stay in sync): apps do have per-person accounts, the **vezérlőpult has
one shared household password**. Previously it read „Minden családtag saját fiókot kap".
- **`biztonsagimentes.html`** — „azonnal értesítést kapsz" softened (map §F health-degradation
e-mail is IMPLEMENTED, never live-fired), and a new **helyreállítási kód** block stating both
sides plainly: nobody else can read the remote backup, and without the code neither can we.
- Gates: `python scripts/site_gates.py` green (BOM, emoji=0, nav/footer identical, analytics,
no CDN, no legacy tokens, no `<style>`, cache-busted assets). Mobile verified by measurement at
380 px: `scrollWidth == clientWidth == 365` (no horizontal scroll), CTA 275×58.
## 2026-07-02 — TASK-D3: design system v2 re-skin (content-preserving)
All seven pages re-skinned to the v2 language (`documentation/design/design-system.md`); URLs,
copy, meta/SEO, analytics, and the contact form's functional markup unchanged.
- **One stylesheet:** the seven near-identical embedded `<style>` blocks (≈120 KB combined)
extracted into `assets/site.css?v=1` — vendored `@font-face`, the v2 `:root` tokens, a deduped
shared base, and per-page sections scoped by `page-<name>` body classes. Zero `<style>` blocks
remain.
- **Self-hosted fonts:** Plus Jakarta Sans + JetBrains Mono (variable woff2, latin+latin-ext,
copied byte-identical from felhom-controller) served from `/assets/fonts/` — the Google Fonts
CDN (a GDPR exposure for a data-sovereignty product) is gone, preconnect hints included.
- **Icons:** all 182 emoji replaced by a 70-symbol external Lucide sprite
(`/assets/icons.svg?v=1#i-name`): feature tiles as `.ico-tile` 48px bg-2 squares, heading icons
`.ico-lg`, inline `.ico`; the alkalmazasok "Open Source" green checkmark image → sprite check
(`.ico-yes`, blue). CSS-generated ✓/✗/★ content → currentColor mask marks / plain text.
- **Nav/footer normalized** across all seven pages (index's `#szolgaltatasok` →
`/#szolgaltatasok`); byte-identical after the active-marker strip.
- **Visual v2:** navy tokens, single 2px radius, no shadows/gradients/hover-lifts, two-tone
heading kept as solid `--blue-bright`, `prefers-reduced-motion` respected.
- **Gates:** `scripts/site_gates.py` (BOM ×7, emoji, nav/footer, analytics, no-CDN, banned
tokens, style-blocks, `?v=` cache-busting) — baseline 84 problems + 182 emoji → **all green**.
- kapcsolat: form fields/JS/endpoint byte-identical; live TESZT submission accepted
(contact-mailer `[OK] Email sent`, resend id logged).