# Pre-flight — taste-skill §14 plus the Felhom additions Run against the **deployed** preview at `https://felhom.eu/preview/`, 2026-10-10, not against the file on disk. Every measurement came from the browser. ## Headline numbers | | Old home page | New preview | | |---|---|---|---| | Page height, 1440 px | 10 922 px | **6 780 px** | 38% shorter | | Page height, 390 px | 19 913 px | **10 865 px** | 45% shorter, 23.6 → 12.9 phone screens | | Initial load (same conditions) | 13 requests, 308 KB | **11 requests, 260 KB** | | | Fully loaded (all assets) | 16 requests, ~540 KB | 15 requests, ~545 KB | **essentially unchanged** | | Third-party hosts | 0 | **0** | | | Em dashes in the page's own copy | 18 | **0** | | | Layout families for 11 / 10 sections | 8 (3 repeats) | **10 (no repeat)** | | | JetBrains Mono fetched | yes, 31 KB, for 13 characters | **no** | | **Honest reading of the weight.** The *initial* load is 48 KB lighter. The *fully scrolled* page is about the same: the new 93 KB portrait is paid for by dropping the 49 KB decorative `logo.png` and the 31 KB mono font. The redesign is not a weight win once you scroll; it is a weight win for the first screen, which is the one most visitors see. R-931 (no gzip anywhere on the site) is worth far more than anything on this page. ## taste-skill §14 | Check | Verdict | |---|---| | Brief inference declared (§0.B) | **Pass** — AUDIT.md §A | | Dial values explicit and reasoned | **Pass** — 6 / 3 / 4, AUDIT.md §I | | Design system chosen or aesthetic labelled honestly | **Pass** — Felhom design system v2, no new system | | Redesign mode detected, audit performed (§11) | **Pass** — preserve; AUDIT.md | | **ZERO em dashes** | **Pass with two stated exceptions** — 0 in the page's own copy. 6 remain in ``/description/OG/Twitter/JSON-LD **by operator decision at STOP 1** (indexed strings), 1 in the shared footer, which gate 3 forces to be identical on 14 pages. Neither swept silently | | Page Theme Lock — one theme | **Pass** — dark throughout, no section inverts | | Color Consistency Lock — one accent | **Pass** — `--blue` / `--blue-bright` only | | Shape Consistency Lock — one radius | **Pass** — `--radius: 2px` everywhere | | Button Contrast Check | **FAIL, pre-existing, filed** — `.cta-button` is 4.01:1 (white on `#0083D8`, 16px/600) against a 4.5 floor. **Identical on the live page**, so not a regression. R-930, needs a brand decision | | CTA Button Wrap — no 2-line label at desktop | **Pass** | | Form Contrast Check | **n/a** — no form on this page | | Serif discipline | **n/a** — no serif | | Premium-consumer palette ban | **n/a** — not that brief | | Italic descender clearance | **n/a** — no italic display type | | Hero fits viewport, ≤2-line headline, ≤20-word subtext | **Pass** — headline 2 lines, subtext **20 words**, CTA and a real screenshot both above the fold at 1440 and at 390 | | Hero top padding ≤ `pt-24` | **Pass** — 128 px, and the hero is sized by its content; the old one was a forced `100vh` band with the content floating in the middle | | Hero stack ≤ 4 text elements | **Pass** — headline, subtext, CTA, figure caption. No eyebrow, no tagline under the CTA, no trust strip | | **Eyebrow count ≤ ceil(sections/3)** | **Pass — 0 of an allowed 4.** The cluster headings are not eyebrows (no uppercase, no tracking, they head real groups), and the comparison's column headers were deliberately de-capitalised for this rule | | Split-Header Ban | **Pass** — every section header stacks headline over body | | Zigzag Alternation Cap | **Pass** — the two image+text splits (hero, portrait) are separated by two other families | | No Duplicate CTA Intent | **Pass** — one label, „Jelentkezem tesztelőnek", used for the one intent in both places | | Logo wall = logos only | **n/a** — no logo wall | | Bento Background Diversity | **n/a** — no bento | | „Used by" wall under the hero | **n/a** | | **Copy Self-Audit** | **Pass** — every visible string re-read. The ten capability texts are **verbatim from the live page** on purpose: the audit's finding was that the writing is right and the layout is wrong, so no hedge („ha van", „szinte mind") was rewritten away | | Motion motivated | **Pass** — there is no motion. The old hero's infinite float is gone | | Marquee max one | **n/a** — none | | Navigation one line, ≤80 px | **Pass** — unchanged from the live nav, spliced verbatim | | **Section-Layout-Repetition** | **Pass** — 10 sections, 10 families. Was 11 sections over 8 families, `why-grid` ×3 and `apps-showcase` ×2 | | Bento rhythm and exact cell count | **n/a** | | Long lists use the right component | **Pass** — the ten-card grid became three labelled clusters (§4.9 „grouped chunks") | | **Real images, no fake screenshots** | **Pass** — one real dashboard screenshot in the hero, four in the gallery, one real photograph of the operator. No AI image, no stock, no picsum, no div-built preview. The decorative logo is gone from the hero | | No pills over images | **Pass** | | No photo-credit decoration | **Pass** | | No version footers | **Pass** | | No micro-meta sentences under eyebrows | **Pass** | | No hero-bottom decoration strip | **Pass** | | No floating top-right sub-text | **Pass** | | No filled progress-bar comparisons | **Pass** — the comparison is text in two columns | | No locale / weather strips | **Pass** | | No scroll cues | **Pass** | | No version labels in the hero | **Pass** | | **No section-numbering eyebrows / generic step labels** | **Pass** — `1..5` and `01..05` are gone; the steps are named by their verb-noun and ordered by layout | | No decorative dots | **Pass** | | No `border-t`+`border-b` on every row | **Pass** — the comparison uses one divider between rows, not a box per row | | Content density sane | **Pass with a stated deviation** — the ten capability paragraphs run past §4.9's 25-word guide. Deliberate: see Copy Self-Audit | | Quotes ≤3 lines | **n/a** — no testimonials | | Motion claimed = motion shown | **Pass** — `MOTION_INTENSITY: 3` claims none and ships none | | GSAP skeletons | **n/a** | | No `window.addEventListener('scroll')` | **Pass** — the only JS is the existing nav toggle and `gallery.js` | | Reduced motion honoured | **Pass** — the global `prefers-reduced-motion` block is present, and there is no animation to suppress | | Dark mode tested | **Pass** — single locked dark theme, by brand decision | | Mobile collapse explicit | **Pass** — every new multi-column rule has its `<900px` and `<600px` fallback written in the same block | | Viewport stability, no `h-screen` | **Pass** — the new hero uses no viewport-height sizing at all; the old `.hero` used `100vh` | | `useEffect` cleanup | **n/a** — no framework | | Empty / loading / error states | **n/a** — static marketing page | | Cards omitted in favour of spacing | **Pass** — the ten cards became three clustered lists; the comparison is a divided table, not eight boxes | | Icons from an allowed library | **Pass, by the Felhom override** — the self-hosted `icons.svg` sprite is the library; no npm icon package | | Motion isolated in client leaves | **n/a** | | No AI tells from §9 | **Pass** | | Core Web Vitals plausible | **Partly** — the hero image is `fetchpriority="high"` with width/height set, so LCP and CLS are in hand; **but nothing is compressed on the wire** (R-931), which is the real limiter | | One design system | **Pass** | ## The Felhom additions (`felhom-web-design` §9) | Check | Verdict | |---|---| | UTF-8 BOM on every page file | **Pass** — asserted by the builder and by `site_gates.py` gate 1 | | Zero emoji | **Pass** — gate 2 | | Zero `—` including meta | **Pass with the two stated exceptions above** | | No `<style>` block; `site.css` `?v=` bumped | **Pass** — `?v=11` | | **Every request to `felhom.eu` or `stats.felhom.eu`, listed from the browser** | **Pass** — 11 requests: `felhom.eu` 8, `stats.felhom.eu` 2, third-party **0**. Full list in the session report | | Page weight compared and said out loud | **Pass** — table above, including the part that did not improve | | Body contrast at or above baseline | **Pass after a fix.** Three new styles measured **3.88 / 3.14 / 3.57** on first pass, all under AA. Moved to `--text-2` and re-measured on the deployed file: **7.56 / 6.12 / 6.96**. One pre-existing failure remains and is filed (R-930) | | Focus visible | **Pass** — `:focus-visible { outline: 2px solid var(--blue-bright) }` applies | | Reduced motion honoured | **Pass** | | **No horizontal scroll at 390 px** | **Pass** — `clientWidth == scrollWidth == 375` at 390, and `== 1425` at 1440 | | English twin in the same commit | **Deferred to Part D by design** — a preview URL cannot be a `TWINS` pair (AUDIT.md §K.6). The twin is written in the switch commit, as a real twin | | `repo_gates.py` green, new page registered | **Pass** — `site_gates.py` green; `preview/index.html` registered in `NO_TWIN` with its reason | ## A measurement that was wrong, and how it was caught The first contrast pass reported `.limits p` at **1.17:1**, which would have been a severe failure. It was an error in the measuring script, not in the page: the helper walked up for the first non-transparent background and found `--warn-dim`, which is `rgba(224,169,62,.12)`, then treated that translucent colour as if it were opaque. Compositing the whole ancestor stack over the page background gives the true value, **5.67:1**, which passes. The three real failures in the same run were real and were fixed. The lesson is the project's own: an instrument that can report a wrong number silently is not a measurement. The corrected helper is in the session transcript and composites every layer.