On /alkalmazasok the Alkalmazasok group renders expanded, which gives the sidebar
a 16px scrollbar and narrows it from 239 to 224. At .95rem the Hungarian label
wrapped to two lines there (the English one still fitted, which is why it showed
on one page and not its twin). Sized to the narrow case, measured not guessed.
Measured at 390px on the LIVE pages, so this is pre-existing and not something the
shell introduced:
/letoltes scrollWidth 609 - the 64-character SHA-256 inside <code>
/adatkezeles scrollWidth 478 - a long facebook.com legal URL used as link text
and the same on their English twins.
overflow-wrap: anywhere changes only where the line breaks; selecting and copying
still yields the whole unbroken string, which matters for a checksum. The legal
pages' words are untouched - this is CSS.
Small enough to fix in the session rather than file.
Measured on the deployed M3 page: .btn-primary 4.01:1 (white on --blue, 13.6px/600)
and .nav-group-label 3.14:1 (--text-3), both under the 4.5 floor.
This is R-930 arriving a second time by a different route: fixing .cta-button on
the website did not fix the CONTROLLER's button, and the shell imports it. Same
remedy the operator already chose - 1.2rem/700 puts the label in WCAG's large-text
band where 3:1 applies - so --blue stays untouched.
The sidebar's own CTA becomes an OUTLINE button rather than a filled one: blue on
transparent passes comfortably, and a 19.2px filled button does not fit a 240px
sidebar without wrapping. Measured both ways rather than guessed.
The controller has both defects on its own surface. Not fixed here - that repo is
read-only this session - so it is going to the register.
The page header and the hero both carried a title, which read as two headings
stacked. The brief's shape is one: .page-header holds the h1 - and it holds
today's indexed headline, 'Sajat felhod, sajat szabalyaid', unchanged - and the
hero row below is the lede sentence plus the button beside the dashboard window.
shell.css loads after site.css, but later-wins is per PROPERTY, not per rule.
Where site.css declares something the controller's rule does not, the website's
value survives inside the shell. Measured: exactly six declarations, three
selectors, and the first one was visibly broken on the deployed page -
.nav-links display:flex + gap:32px -> the sidebar menu rendered as a
HORIZONTAL row spilling across the content column
.lang-globe-menu top + right -> fought the controller's bottom/left
.page-header padding + text-align -> the website's centred subpage header
fought the controller's left-aligned flex row
Reset in site.css, the website's own file, so shell.css stays a verbatim copy.
Found by diffing the two files' declaration sets per selector rather than by
spotting the one that happened to be visible.
The direction the operator chose: the controller's FRAME around the website's own
content. Staged at /preview/m3/, noindex, nothing live.
website/assets/shell.css - 117 rules COPIED VERBATIM from felhom-controller
style.css @ dcd89364a4 (sidebar, mobile top bar, off-canvas drawer, and the
component atoms the restyled pages use: btn, alert, app-info-card, launch-*,
stack-detail-card, form-*). Exactly ONE rule is not verbatim and says so:
body.shell { display:flex; min-height:100vh }, which lives in the controller's
base rather than in a component, scoped to .shell so other pages are untouched.
The generator NAMES every rule it copies and REFUSES to write the file if one has
disappeared upstream. That is not ceremony: it already caught two things this
session. It refused because .sidebar::-webkit-scrollbar does not exist (only the
-track override does), and because prefers-reduced-motion is split across FIVE
separate blocks in the controller - reading only the first would have silently
lost four rules. The M1 round lost a rule exactly this way.
The bare `body { flex-direction: column }` that broke M1's phone layout is copied
this time, by name, as are body.nav-open and the no-js/js pair.
Load order is deliberate: shell.css AFTER site.css. Thirteen selectors exist in
both files with different meanings (.nav-links, .page-header, .lang-globe*, .ico)
- a horizontal site nav there, a vertical sidebar here. Later wins, and a page
that does not load shell.css is completely unaffected.
website/preview/m3/index.html - the home page in the shell. Content is /preview/'s
cleaned text; body carries `shell page-index` so the existing .page-index content
rules (caps, flow, vs, band, who-mini) are reused rather than duplicated. Six
sections, left-aligned headers, the controller's cards. Head tags (title, meta
description, canonical, hreflang) are already the FINAL values, so the switch in
part D needs no head edit.
Four changes from the operator's mockup, each with its reason in the generator:
1. the active item follows the page (the mockups show Inditopult active on all)
2. Teszteles is ALSO a primary button at the top of the lower group - it is the
one action we want and the mockup buries it at the bottom
3. the Alkalmazasok categories are anchors on /alkalmazasok: real URLs, no
JS-only state
4. ADDED GYIK. It is in today's nav; dropping it silently would take a page out
of navigation, which is not a change a restyle gets to make.
scripts/site_gates.py - gate 3 extended rather than duplicated, as asked: a SHELL
set whose pages must carry an IDENTICAL <nav class="sidebar"> after the active
marker is normalised. RED-PROOFED: a one-character change to one menu label on a
second shell page convicts. It also prints "DIFFER" rather than a reassuring
"identical" count when it fails - a false reassurance printed beside a conviction
is the exact defect this repo files rows about.
documentation/design/design-system.md - new "Shell" section: what is shared (tokens
+ shell + atoms), what each side owns, how a change flows (controller first, the
website's copy the same week), and that the cross-repo gate is deliberately NOT
built yet.
.close-cta is text-align:center, so an inline-flex row flowed onto the same line
as the CTA button and pushed the whole group off-centre. flex + max-width 34rem +
margin auto puts it under the button as a centred block, with the hairline above
it spanning the row rather than the section.
Caught by looking at the deployed page rather than trusting the markup.
site.css?v= -> 14.
Operator's call after seeing the preview: the biography sat between the dashboard
gallery and "Hogyan mukodik?", interrupting "what it does" -> "how you get it"
with a life story. And its last sentence, "Ha irsz, en valaszolok", is a contact-
page sentence - it belongs next to "Valaszido", not mid-product-story.
/kapcsolat + /en/contact gain the full block (photo + the five approved
sentences). These are LIVE pages, so the bio and the photograph are public
from this commit. Both halves of the twin move together, as the twin rule
requires; the English promises nothing the Hungarian does not, and uses the
site's established "the box" rather than a new term.
/preview/ loses the section and gains a compact row in the closing call to
action: a 56x70 portrait, one line, and a link to the full block. This is
deliberate, not a compromise - the audit's R-11 finding was "nobody is
behind it" on the HOME page, and deleting every human trace from it would
re-open exactly that. The trace now sits where someone decides to write.
A dedicated /rolam page was considered and rejected: five sentences cannot
carry a page, and the alternative was inventing biography to fill one.
The .who* rules are now UNSCOPED (were .page-index .who*), because the block
lives on two pages and will live on the home page's twin later. Following
69035f4af5's lesson: a genuinely shared pattern goes site-wide rather than being
duplicated per page scope. No existing page uses .who, so nothing else moves.
assets/operator-portrait-small.webp - 160x200, 8.4 KB, cropped from the same
original outside the repo, metadata stripped and verified by read-back (0 EXIF
tags, 0 GPS entries, none of the phone's byte sequences present).
site.css?v= -> 13 on all 21 files.
The preview builder asserted a hardcoded "site.css?v=10" and broke the moment the
site moved to 12. It now follows whatever index.html pins and prints it.
site_gates.py green.
Two operator decisions from STOP 3, both independent of the home-page switch,
which was NOT approved and has NOT happened. index.html still serves the old
design; only the footer line and the button change on it.
1. The footer em dash, on all 21 page files (12 HU + 8 EN + the preview).
"(c) 2026 felhom.eu - Sajat felhod..." now uses the spaced en dash, which is
the correct Hungarian gondolatjel. Done as one sweep because site_gates.py
gate 3 requires every page in a language set to carry an IDENTICAL footer, so
this could never have been a one-page edit. Gate green: all 14 still match.
Scope, stated honestly: 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, testing 24, teszteles 23, index 17/19, ...). The
preview page is the only page at zero. The rest is NEXT.md work, page by page.
2. R-930, the operator's choice of the three offered: white on --blue measures
4.01:1, under WCAG AA's 4.5:1 for body text. .cta-button goes to 1.2rem/700,
which is >=18.66px at >=700 weight, so WCAG counts it as LARGE text and the
floor becomes 3:1 - which 4.01 clears without touching --blue. Darkening the
token was rejected because --blue is shared with the hub and controller UIs.
Horizontal padding trimmed 32->26px to protect the one-line rule for the
longest label; verified in the browser at 390px, not assumed.
.cta-button-secondary is unchanged: it already measures 7.17:1.
This reaches the primary button on 16 pages, which is the point - the defect
was never the home page's.
site.css?v= bumped to 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.
site_gates.py green.
Measured on the live preview, not assumed. --text-3 gave 3.14:1 (comparison
header), 3.57:1 (comparison rows) and 3.88:1 (hero caption) against their own
backgrounds, all under the 4.5:1 floor for body text. The audit's own rule was
that the existing 7.56:1 body contrast is an accessibility win to protect, so
dimming a column below AA to make it read as 'the quieter half' is a regression,
not a style. All three move to --text-2; the two halves of the comparison are
still told apart by the accent colour and the bold lead on the right.
Part C. The live home page is NOT touched: every CSS rule added is a new class
under .page-index, so index.html renders byte-for-byte as before.
website/preview/index.html (BOM + CRLF, noindex, Disallow: /preview/)
Ten sections, ten different layout families. The three repeats the audit found
are gone: why-grid ran 3x and apps-showcase 2x.
- hero: a real dashboard screenshot instead of the logo, sized by its content
instead of a forced 100vh band, no infinite float animation, and a sentence
made of four facts instead of "Professzionalis ... telepites es uzemeltetes".
- the ten capability cards become three labelled clusters. Their TEXT is
verbatim: the audit's own finding was that the writing is right and the
layout is wrong, so only the layout moved. Every hedge ("ha van") survives.
- NEW "Ki all mogotte" with the operator's photo and five approved sentences.
- the 3 cloud-problem cards + the 4 own-server cards merge into ONE two-column
comparison. No new claim about any competitor: all four left-hand sentences
already existed on the page.
- the two tile walls (10 + 7 tiles duplicating pages that already exist) shrink
to a two-item band that keeps the app names and the links.
- section headers are left-aligned and varied, not 11x centred-two-words-plus-
one-blue-word.
Em dashes in the page's own copy: 18 -> 0. Deliberately kept: the 6 in <title>,
meta description, OG, Twitter and JSON-LD (operator decision at STOP 1 - indexed
strings deserve their own pass), and 1 in the shared footer, which gate 3 requires
to be identical across all 14 pages. Both stated, neither swept silently.
JetBrains Mono is no longer fetched. Exactly 13 characters were loading 31 KB:
the 1..5 process badges, the 01..05 service numbers, and - the audit missed this
at first and it is corrected in the file - the 3/2/1 of the backup rule.
assets/operator-portrait.webp 720x900, 93 KB
Cropped from an original that stays OUTSIDE this public repo. All metadata
stripped and VERIFIED BY READ-BACK: 0 EXIF tags, 0 GPS IFD entries, and none of
EXIF/XMP/ICCP/samsung/SM-A705FN/2023:10:18 appear anywhere in the bytes. Built by
re-writing the pixels into a fresh image, so the source info dict cannot travel.
Honest correction to the brief's premise: this photo had NO GPS tag to begin with.
scripts/site_gates.py
preview/index.html registered in NO_TWIN, with the reason. It cannot go in TWINS:
gate 3 wants its nav identical to index.html's (globe -> / and /en/) while the
twin check wants a pair's globe pointing at the pair's own URLs. The English twin
is written in the same commit as the switch, as a real twin. Everything else still
runs on the preview - BOM, emoji, nav/footer, globe, analytics, CDN, tokens,
cache-busting, dash-language, viewer, tail.
site_gates.py green. The builder (kept in the session scratchpad) writes BOM + CRLF
and asserts both: it first wrote LF and turned the nav/footer gate red for the
preview, which is exactly the trap this CHANGELOG's morning entry records.
Root cause of "no formatting for the points": .info-card and .highlight-box are
scoped per page (.page-technologiak / .page-biztonsagimentes) and the new pages
carry .page-teszteles, so NONE of the card chrome applied - the sections were
unstyled text runs. The tester pages now join the technologiak scope, whose h3
is a flex row (these headings carry an icon).
Three more gaps the new pages exposed, all fixed site-wide rather than patched:
- There was no base `a` rule at all, so an inline link in body copy fell back
to the browser default and changed colour once visited. .legal was the only
place this had been fixed. /gyik, /technologiak and /biztonsagimentes each
carry such links and had the same bug.
- `code` was styled only under .legal.
- A <ul> inside an info-card was unstyled: wrong colour, wrong indent.
Justified body copy on the tester pages, as asked. NOTE: no other page
justifies today, so this is deliberately scoped to .page-teszteles and can be
rolled out site-wide or dropped in one edit. hyphens:auto, because Hungarian
sets badly when justified without it.
site.css -> v=10 on all 20 pages.
sitemap.xml: BOM removed. Search Console shows the freshly submitted clean
sitemap as "Sikertelen lekeres" with an empty last-read, and a BOM before the
XML declaration is a known irritant for its parser. The file is otherwise valid
(18 <url>, parses, served 200 as application/xml). No gate covers sitemap.xml
and the BOM rule is for website/*.html only.
Facts corrected - there are NO testers (operator, this evening): "Tester 1" is a
disposable virtual box and "Tester 2" is a friend whose machine is unassembled
and switched off. The page said "Nehany hely mar betoltve", which was untrue; it
now says the test is starting and all 5 places are open. Same correction in
OUTREACH.md (five people needed, not three), CONTEXT.md, and the terms-1.1 mail,
which in practice has one recipient, not two. No scheduled post claimed a
filled place, so none needed editing.
I used assets/logo_notext.svg for the header mark. That file is the
LIGHT-BACKGROUND variant: it has SEVEN #00408d fills and ZERO #ffffff, so on
the dark nav the cloud rendered as a hollow outline. The operator caught it.
logo_notext_white.svg is not the answer either -- it is a white OUTLINE
version, also unfilled. Rendered all four candidates side by side on the real
nav background to see it rather than infer it: only logo.svg (and logo.png)
carry the real artwork -- white cloud, #051343 house and servers, #008ddf
swoosh.
FIX: assets/logo-mark.svg, cut from logo.svg -- keep <defs>, path6 and g2;
drop the five wordmark paths and the two empty <text> elements; viewBox
cropped to the mark (70 0 505 295). Vector, correct fills, no text.
All 18 pages point at it; site.css cache-bust v7 -> v8. The CSS comment now
says which file NOT to swap back in, and why.
AND A CORRECTION THAT REMOVES AN OPERATOR TASK (R-916). That row says the
project has no usable vector master because logo.svg "sets felhom.eu as live
text" in 'M+ 2c'/'Vremena Grotesk', and it waits on "the machine with the
fonts". MEASURED today, while cutting the mark out of that very file:
- all five wordmark elements are <path> with real d= geometry
- NO <text> element has any content; the two present are empty leftovers
- the font-family strings the row cites are Inkscape METADATA left on
CONVERTED paths (-inkscape-font-specification). A grep for font-family
finds them and reads as live text -- the likeliest way the original
diagnosis went wrong.
- proof from a renderer that lacks both fonts: Chrome draws logo.svg's
lettering identical to logo.png's, side by side.
NOT re-tested: librsvg specifically -- DooPlex has no rsvg-convert, inkscape
or cairosvg installed today, so the original librsvg/DejaVu observation could
not be reproduced either way. It does not change the structural fact: there
is no font left to substitute. Consequence: the 645x408 PNG is not the only
faithful copy and does not cap picture size.
R-916 state -> READY with "re-check before doing any work: this may need
nothing from the operator at all", rather than closed on my say-so.
HEADER. logo.png carries its OWN "felhom.eu" lettering under the mark, so
putting it next to a typed <span class="logo-text"> said the name twice and
squeezed the mark down to 40px to make room. Now:
- the mark alone, bigger: assets/logo_notext.svg at 54px (44px under 600px).
Vector, so it stays crisp. Its two <text> elements are EMPTY, so R-916's
missing-font problem does not apply to this file -- checked, not assumed.
- the name beside it is the brand's OWN lettering, cropped from logo.png to
the new assets/logo-wordmark.png (632x108, tight bbox).
Why an image and not text: the wordmark's face is "M+ 2c"/"Vremena Grotesk"
(R-916). Nothing here has it, and the site deliberately loads NO external
font -- the privacy notice published this morning states exactly that, so
pulling in Google Fonts to match a logo would have made a published claim
false. Using the artwork is also what the Facebook covers already do. The
white/blue split the operator asked for is in the artwork itself.
Accessibility kept: the mark is alt="" aria-hidden (decorative), the wordmark
carries alt="felhom.eu", so the link still has its accessible name.
FOOTER. The legal links were unstyled, so the browser painted them default
blue and PURPLE once visited. They now follow the site's own convention
(.page-kapcsolat .sidebar-card a): --blue-bright, no underline, underline on
hover. :visited is pinned to the same colour deliberately -- a legal link
that changes colour after one read looks like it stopped working. The same
fix applied to .legal a on the two new legal pages, which had --blue instead
of --blue-bright.
18 of 18 pages carry the new lockup; the English pages keep their /en/ logo
href. site.css cache-bust v6 -> v7 on all 18, per the website rules. Verified
rendered in a browser on both a Hungarian and an English page: both images
load, no .logo-text left anywhere, footer links computed rgb(46,168,245).
site_gates OK (nav/footer per language, BOM, cache-busting, twins).
Two new Hungarian pages, live on push: /adatkezeles (privacy notice) and
/feltetelek (what the free closed test is, and is not). Operator rulings of
2026-10-09: no company exists yet, so the operator is named as a PRIVATE
PERSON with no postal address and no phone; publish before the lawyer has
seen it, because the site was collecting data with no notice at all; the full
ASZF, the impresszum and the review wait for the company (R-802, R-809).
- All 18 pages carry the operator, info@felhom.eu and both links in the
footer. Counted, not assumed: 18 pages found = 18 with both links = 18
structurally valid. English footers say the legal texts are Hungarian.
- The contact form stopped claiming something untrue. The old consent said
"az adatokat harmadik felnek nem adjuk ki" while Resend, Cloudflare and
Google carry the message. Both languages replaced; the link opens in a new
tab so a filled form is not lost.
- site_gates.py NO_TWIN gains the two pages ON PURPOSE, with the reason in a
comment: an unreviewed English legal text would be worse than an honest
pointer from the English footer.
- documentation/legal/{adatkezelesi-tajekoztato,feltetelek}-1.0.md are the
text of record, DERIVED from the published HTML so they cannot drift. The
drafts are kept and marked superseded for the closed test.
FOUR LOAD-BEARING CLAIMS WERE MEASURED, not copied from a vendor or a README:
cookies zero, and no local storage - checked in the browser WITH A
POSITIVE CONTROL (a probe cookie WAS visible to the same
method) after the tracker fired; no Set-Cookie on any response
beacon the exact Umami payload: site id, screen, language, title,
url, referrer - no visitor identifier
Cloudflare DNS only: the public A record 37.191.56.193 is not a
Cloudflare address, so site traffic cannot be proxied
fsn1 Falkenstein, Germany (Hetzner's own location list)
Also measured: felhom-ep0-copy-gc.timer is installed and RAN SUCCESSFULLY
(2026-10-09 08:00, exit 0), so "deleted within 30 days" is true today where
on 2026-10-08 it was written but not switched on.
Three retentions are stated as having NO deadline, deliberately and with the
operator's word: website statistics, web server logs and contact messages
have no automatic deletion, and the pages say so instead of promising a date
nothing enforces. Every other period is enforced by configuration and cited.
No placeholder survived onto either page (0 of "[[", control: the draft still
has 36). The impresszum and the full ASZF are NOT published.
R-813 -> NARROWED. R-915 unblocked: the operator enters the two URLs in the
Meta app's Basic settings; the Live switch stays a separate decision.
R-917 and R-920 -> DEFERRED on the operator's (c): park, publish as posts
once posting starts.
Git archaeology: the grid was never a deliberate removal. It lived as a fixed
`body::before` in index.html's inline <style> block and was dropped when bed8675
("D3 Part 2: index + kapcsolat on design system v2") migrated the page onto
site.css. dd54e4c, which created site.css, has no body::before — it was a
porting omission, and nothing took its place. No asset was lost; it was pure CSS.
Restored at its original geometry and subtlety (50px cells, 1px lines, 3%), not
redesigned. Only change: 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 to v=2 across all seven pages (nginx caches 7d).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nn3VgQk9iwEGgyx6QJ2NvE
- Both pages: Google Fonts links + preconnects removed; ONE stylesheet
(/assets/site.css?v=1); embedded <style> blocks deleted; body classes
page-index/page-kapcsolat; canonical nav/footer (active marker per
page; index's #szolgaltatasok href normalized to /#szolgaltatasok);
all emoji -> sprite icons (feature tiles = .ico-tile 48px bg-2
squares; headings .ico-lg; inline .ico) or plain text.
- kapcsolat: the contact form is functionally frozen — every field
name/id, the submit JS, and the /api/contact endpoint byte-identical;
only the visual layer changed (upload/paperclip + file-type icons as
sprite refs in JS strings, the x button as ×, status-message
emoji prefixes dropped).
- site.css: CSS-generated marks (content '✓'/'✗'/'⚠'/'★ …') replaced by
currentColor mask-based marks / plain text (emoji-free stylesheet;
gate now scans it too); .ico-tile is svg-as-tile (immune to container
display rules), .ico-lg added.
- Gates: zero failures for the two converted pages; the remaining five
convert in Part 3.
- website/assets/site.css: ONE stylesheet for all seven pages — vendored
@font-face (4 faces, latin+latin-ext, /assets/fonts/ paths), the
design-system v2 :root token block verbatim, a hand-written shared
base (reset, nav, two-tone heading as solid blue-bright, section/page
headers, buttons, card, footer, hamburger + mobile menu, icon-tile,
reduced-motion), and per-page sections mechanically converted from
the seven embedded style blocks (tokens renamed, radii → 2px,
box-shadows/text-gradients/hover-lifts removed, greens → blue per
exception-color) scoped under .page-<name> body classes.
- website/assets/fonts/: the 4 woff2 files copied byte-identical from
felhom-controller (self-hosted — removes the Google Fonts CDN / GDPR
exposure once the pages switch over).
- website/assets/icons.svg: 70-symbol Lucide sprite (the D0 30 + 40
marketing icons) for <use href="/assets/icons.svg?v=1#i-name">.
- scripts/site_gates.py: 8 gates (BOM bytes, Python-codepoint emoji,
nav/footer consistency after active-marker normalization, analytics
presence, no-CDN, banned legacy tokens, zero <style> blocks,
?v= cache-busting). Baseline against the unconverted pages: 84
problems, 182 emoji — goes green with the page conversion commits.
- Live site unaffected: nothing references the new assets yet.