# Nezávislý architektonický posudek: úraz a travel

Datum: 2. 11. 2026. Rozsah: statické zdroje travel `site/versions/travel-0.21.2` a úraz `releases/uraz/ferda-0.14.1`, s historickým integračním podkladem `D:/devel/_prototypes/cmp_uraz/site/ferda/IMPLEMENTACE.md` z 21. 10. Metodika staršího WordPress reportu je pouze historickým východiskem. Nejde o implementaci UI ani audit aktuální produkční Ferdy, úplný test přístupnosti nebo důkaz shody WCAG. Kde není uvedeno živé měření, jde o čtení kódu, výpočet z deklarovaných barev a doporučení k ověření.

## Rozhodnutí pro společný základ

Sdílet významové role, rozměry a kontrakty formulářů a interakcí; produktové otázky, kalkulaci, karty rizik, varianty dokumentů a kroky ponechat jako samostatné konfigurace. Zachovat schválené `#F42534` malé nadpisy, bílé písmo na zelených hlavních akcích, šedou stránku s bílými formuláři, patičku `#003B71`, cestovní produktovou hlavičku a čtyři fáze, bez prezentačního pruhu a odkazu na rozcestník. Zajistit celou místní průchodnost bez AI/API a bez skutečného odeslání, platby a sjednání. Červený a zelený kontrast má otevřený rozpor s požadavky čitelnosti; tichá změna preference není schválená.

| Role / metrika | Výchozí společná specifikace | Stav a produktová volnost |
|---|---|---|
| `accent.section` | `#F42534`, malé sekční nadpisy | Stabilní zákaz modrého přebarvení; kontrast dle následující tabulky vyžaduje rozhodnutí. Nezaměňovat s chybou. |
| `action.primary`, `action.onPrimary` | zelená `#00B53B`, bílá; hover `#009B33` | Podle `travel-refinement.css`; prověřit také počítané stavy úrazu. Zachovat barvy jako zadání, neprohlašovat za kontrastně vyhovující. |
| `surface.page`, `surface.form` | `#F2F4F7`, `#FFFFFF` | Ověřit dědičnost průhledných vnořených ploch i vybrané/neaktivní stavy; pod formulářem nesmí zmizet vyznačení stavu. |
| `text.primary`, `heading`, `heading.card` | `#231F20`, `#003B71`, `#002E5F` | Rozdělit role, nikoli přepsat všechny modré jedním hexem; `#03407C` pro sekční nadpis je stávající samostatná role. |
| `footer.surface`, `footer.text` | `#003B71`, bílá | Potvrzená preferovaná role. Odkaz a fokus potřebují i jiné rozlišení než barvu. |
| Typografie | Montserrat; tělo 16 px desktop; nadpis kroku 32/26 px, hero 48/34 px | Navrhovaný výchozí základ podle travel; produkt může mít odůvodněnou odchylku. Mobilní tělo travelu je nyní 14 px, nikoli 16 px. Testovat zvětšení textu a délky překladů. |
| Rozměry | jednotná škála 4/8/12/16/24/32 px, radius prvku 8 px, karty 15 px | Návrh pro nové komponenty; existující pozorované hodnoty nejsou důkazem jednotného systému. Cíl dotyku 44 × 44 CSS px; WCAG 2.2 AA uvádí minimum 24 × 24 s výjimkami, neplošnou povinnost 44 px. |
| Fokus, výběr, chyba, disabled | samostatné role kontrastu a obrysu, textový význam, žádná závislost jen na barvě | Hodnoty nejsou ještě schválené. Měřit proti skutečnému sousednímu pozadí v každém stavu, včetně sticky prvků a high-contrast režimu. |

## Kontrast: číselný rozpor k rozhodnutí

Výpočet dle [WCAG 2.2, relativní luminance a kontrast](https://www.w3.org/TR/WCAG22/#dfn-contrast-ratio): normalizovaná složka `c = sRGB/255`, lineární `c/12,92` pro `c ≤ 0,04045`, jinak `((c+0,055)/1,055)^2,4`; luminance `L = 0,2126R + 0,7152G + 0,0722B`; poměr `(Lsvětlejší+0,05)/(Ltmavší+0,05)`. Následující výsledek je pro jednolité deklarované barvy, nikoli automatický verdikt všech vykreslení.

| Text | Podklad | Poměr | Posouzení vůči SC 1.4.3 |
|---|---|---:|---|
| `#F42534` | `#FFFFFF` | 4,069:1 | Běžný informativní text pod 4,5:1; velký text nad 3:1. |
| `#F42534` | `#F2F4F7` | 3,693:1 | Stejný závěr, nižší rezerva. |
| `#FFFFFF` | `#00B53B` | 2,737:1 | Pod 4,5:1 i 3:1. |
| `#FFFFFF` | `#009B33` | 3,661:1 | Pod 4,5:1; velký text nad 3:1. |
| `#FFFFFF` | `#003B71` | 11,266:1 | Nad 4,5:1. |

[WCAG 2.2 SC 1.4.3](https://www.w3.org/TR/WCAG22/#contrast-minimum) požaduje pro běžný text 4,5:1 a pro velký text 3:1; existují výjimky například pro čistě dekorativní a neaktivní obsah. Kicker nesmí být automaticky prohlášen za dekorativní, pokud nese význam. Na rozhodnutí předložit varianty: zachovat přesný vzhled s výslovně evidovaným rozporem, nebo hledat způsob splnění při zachování schválených barevných hodnot a významu; konkrétní změnu posoudit s uživatelem. Netvrdit úplnou shodu WCAG ani ji neodvozovat z jediné dvojice barev. [Netextový kontrast](https://www.w3.org/TR/WCAG22/#non-text-contrast) má samostatná pravidla 3:1 pro potřebné hranice a stavy.

## Co kód skutečně dělá a co sjednotit

| Oblast | Travel 0.21.2 | Úraz 0.14.1 | Doporučená smlouva / ověření |
|---|---|---|---|
| Kaskáda | `index.html:6,13–15`: navigation → app → innovation → iteration → refinement → countries → accents. `travel-refinement.css` nastavuje `.eyebrow,.step-kicker` na modrou. | `index.html:9–11` načítá základ, řadu produktových a prezentačních vrstev, WordPress, header, unified, accents; `uraz-unified.css` nastavuje hero eyebrow na modrou. | `section-accents.css` je finální vrstva a používá široký `!important` pro více názvů, např. `.selected-summary__label` a `.results-toolbar__label`. V nové verzi nejdříve katalogizovat role podle skutečného významu, prověřit počítaný styl pro všechny stavy; poté definovat vlastníka a prioritu každé vrstvy. Není bezpečné prostě změnit `--blue`: přímé barvy a specifičnost mohou zůstat vítězi. |
| Plochy | `travel-refinement.css`: white cards a page `#F2F4F7`. | `uraz-unified.css`: bílé mnohé plochy i všechna `input,select,textarea`. | Prověřit, zda široký selector nepotlačuje výběr, disabled a validaci; vždy porovnat výsledné styly, ne pouze hodnoty tokenů. |
| Výběr destinace | `index.html:66–79` používá `fieldset/legend`, nativní radio a podmíněný `<select>`; `travel-countries.js:16–38` přepíná hidden/disabled/required a při volbě jiné země přesune fokus do selectu. | Volby frekvence v `experience.js` a dotazníku v `ferda-flow.js` také používají nativní fieldset/radio. | Jiná země: při průchodu radii šipkami může fokus okamžitě opustit skupinu; ručně ověřit klávesnicí a se čtečkou. `aria-expanded` na radiu přezkoumat proti [WAI-ARIA roli radio](https://www.w3.org/TR/wai-aria-1.2/#radio); není vhodné předpokládat její podporu. Po návratu zachovat hodnotu i označení, skryté pole nedělat povinným. |
| Chyby | `app.js:916–925` kontroluje required, přidá `is-invalid`, zaměří první neplatné; country select má `aria-describedby` pouze na hint, viz `index.html:78`. | `shared/ui.js:16` a `shared/refinement.js:23` tvoří `aria-invalid` a vazbu na text chyby. | Dodat stabilní ID a napojení viditelné chyby i u country selectu, test validace, opravy a opakovaného submitu; nerozšiřovat to tvrzením o všech polích bez testu. Povinné a podmíněné pole musí mít čitelný štítek, pomoc a stejnou informaci pro AT. |
| Dialog a návrat | `app.js` obsahuje vlastní vrstvy; jejich úplný focus management není tímto statickým čtením ověřen. | `shared/app.js:53–65` pamatuje kontext, otevírá nativní dialog, `releasePriceContext()` obnovuje jméno; `ferda-flow.js:102–107,147` otevírá dialog osoby, zaostří vstup a obnovuje fokus dle datového atributu. | Název, počáteční fokus, Tab/Shift+Tab, Escape, Zrušit beze změn, Uložit, návrat na existující spouštěč a fallback po překreslení nebo odstranění jsou nutné testovací případy. Nativní dialog je dobrý základ, sám nedokazuje správný workflow. [W3C APG dialog](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/). |
| Záložky a kroky | `index.html:54–64` tablist/tab/tabpanel; `iteration.js:21–33` doplňuje šipky, Home a End. | `ferda-flow.js:64–67` generuje fáze a `aria-current=step`. | Testovat selected, focus, vazby a skrytý obsah při změně; [APG tabs](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/). Produkty mohou mít vlastní podkroky, společná je sémantika průběhu a návratu. |
| Mobil a čitelnost | `travel-refinement.css` má mobilní body 14 px a 34px hero; země `travel-countries.css:2` min. výška 56 px. | `uraz-unified.css` má 34px hero a mobilní jednosloupcové formuláře; `experience.css` obsahuje i popisky 10–12 px. | Nevyvozovat splnění celé stránky z min-height jednotlivých prvků. Prověřit 320/375/768 px, 200% zvětšení, orientaci, překryv sticky ovládání a skutečné cíle na dotyk včetně rozestupů. Malé pomocné texty posoudit na reálném zařízení. [WCAG cíl 24 px a výjimky](https://www.w3.org/TR/WCAG22/#target-size-minimum). |

## Kontrakty komponent pro další kalkulačky

1. **Field / FieldGroup**: vstupní `id`, label, hodnota, povinnost, nápověda, podmínka zobrazení a chyba; výstupem sémanticky spojené `label`, `aria-describedby`, `aria-invalid` pouze při chybě; oprava chybu odstraní, podmíněný skrytý obsah není validován. Složená otázka používá `fieldset/legend`, nativní radio nebo checkbox a dostupný textový výběr. Serverová a klientská validace zůstávají oddělené a musí se při skutečné integraci sladit.
2. **Action / Choice / Counter**: tlačítko má jméno a typ, stav loading/disabled a zřetelný fokus; výběr má textový i sémantický stav a nespoléhá na barvu. Počítadlo má název, limity, použitelné +/- a přímý vstup; změna nezpůsobí nečekanou navigaci. Veškeré stavy mají stejný kontrakt pro klávesnici i dotyk.
3. **Step navigation / route**: čtyři srozumitelné fáze, produktové podkroky, `aria-current`, povolené návraty a explicitně řízený návrat na rekapitulaci. Při přechodu fokus na smysluplný nadpis/kontext a oznámení změny; neztratit neuloženou práci. Popis cesty a mapa rizik mají přímou offline alternativu.
4. **Dialog / detail nabídky**: jméno, spouštěč, dostupné zavření, ohraničená tabulace, Escape a definované uložení/zrušení. Oddělit draft od potvrzených dat; po zavření vrátit fokus podle identity spouštěče nebo na bezpečný náhradní cíl. Ověřit navíc opakované otevření, obnovu stránky a změnu kontextu.
5. **Offer / risk / summary**: nabídka dostává produktový identifikátor, stav dostupnosti, cenu a vysvětlení případných odchylek; komponenta nesmí vydávat model za závaznou skutečnou sazbu. Krytí a dotazník jsou produktová konfigurace. Přehled musí přenášet skutečně zvolená data, úpravy předchozího kroku zneplatní odvozený návrh a platbu podle pravidel konkrétního procesu.
6. **Integration adapter**: UI čte a zapisuje verzovaný lokální model a volá rozhraní jako *záměr* kalkulovat, vybrat či připravit návrh. Samostatný modelový adaptér nikdy neposílá síťové požadavky; skutečný adaptér je budoucí samostatně schvalovaná práce s ověřenou smlouvou, validací, chybou, dostupností a retry. Názvy záměrů nejsou endpointy. Nikdy nevydávat lokální potvrzení za odeslaný e-mail, skutečnou platbu nebo smlouvu.

## Připravenost pro Ferdu

Historický podklad `IMPLEMENTACE.md` výslovně popisuje pouze samostatnou statickou ukázku a čtecí audit z 21. 10. 2026. Ověřené v tomto podkladu jsou historické identity 130/132/142, čtyři desktopové fáze u zkoumané varianty a samostatné události Calc/Buy/Order; 132 a 142 nejsou totožné produkty. Prototypové `CMPFerda.toFerdaDraft` je vzor hranice UI, ne ověřený request ani záruka současného schématu. Historický dokument uvádí nutnost mapování číselníků, rizik, skutečných produktových atributů a serverové validace; dokumenty a platba tehdy integrovány nebyly.

**P0 před návrhem skutečného adaptéru:** znovu ověřit aktuální vlastníky, existující formulářové definice a životní cyklus stavu přímo u odpovědných zdrojů; doplnit smlouvu dat a chyb, dostupné integrační prostředí a odpovědnost za validaci. **P1:** mapování konkrétních produktů, verzování vstupů, invalidace odvozených výsledků, návaznost dokumentů a zabezpečená správa stavu. **P2:** sjednotit prezentační vrstvu a automatizované kontraktní testy bez nahrazování produktové logiky. Neznáme aktuální endpointy, auth, právní či provozní pravidla ani současné produkční brány; nic z toho tento report nedokazuje. Modelový průchod zůstává oddělený a funkční i při nedostupnosti budoucí integrace.

## Správa specifikace a přejímka

Založit společný verzovaný katalog: `primitives → semantic roles → shared components → product adapters → explicit exceptions`; u každé role evidovat vlastníka, příklady použití, zakázaná použití, stavy, kontrast, zdroj a datum rozhodnutí. Stanovit review změny tokenu napříč produkty a zpětnou kompatibilitu; odchylka má jméno produktu, důvod, trvání a ověřovací případ. Každá nová kalkulačka přidá příklady validního/nevalidního/dlouhého textu a offline větve, ne novou kopii stejné komponenty. Vydané adresáře a ZIPy zůstanou neměnné; změna se skládá reprodukovatelně jako nová verze.

Přejímka každé změny: obě verze startu, všechny fáze a větve, volby, nabídky, úprava/rekapitulace, offline bez AI/API; chybové a opravené formuláře; klávesnice, viditelný fokus, pořadí, dialog včetně návratu a kontrola čtečkou; mobil a zoom; kontrast skutečných barev ve stavech; porovnání vypočtených stylů a screenshotů na reprezentativních obrazovkách; ověřit modelová potvrzení bez skutečných vedlejších účinků. WCAG 2.2 je soubor více kritérií a vyžaduje samostatný úplný audit, nikoli pouze tyto kontroly.

## Cílená čerstvá kontrola klávesnice a stavů

Doplněna vlastní izolovaná kontrola v lokálním headless Chrome nad `file://` kopií `portal/site`, na šířkách 375 a 1440 CSS px, s blokací síťových požadavků; místní HTTP bylo v tomto sandboxu nepřístupné. Porovnané `index.html` a hlavní `app.js` obou produktů jsou byte shodné s posuzovanými vydáními; nebyl takto porovnán každý soubor portálu. Důkazy a opakovatelný skript: [`keyboard.json`](../evidence/gpt-6.1-terra/keyboard.json), [`keyboard.cjs`](../evidence/gpt-6.1-terra/keyboard.cjs), snímky `country-arrow-*`, `travel-dialog-*` a `uraz-dialog-*` v téže složce. Jde o výběrovou kontrolu, ne test se čtečkou ani na fyzickém telefonu.

- **Jiná země:** z fokusu na Polsku klávesa ArrowRight vybrala Jinou zemi a okamžitě přemístila fokus na povinný select, na obou šířkách. To je skutečně pozorované chování, nikoliv zatím prokázané porušení; může narušit pohodlné pokračování šipkami po skupině. Doporučuji upravit smlouvu tak, aby šipky navigovaly radio skupinou a vstup do závislého výběru následoval běžnou tabulací, s ověřením čtečkou.
- **Travel, dialog aktivit:** po plánované prodlevě 40 ms fokus přistál na zavíracím tlačítku. Dvanáct stisků Tab při tomto průchodu neopustilo dialog; Escape jej zavřel a fokus se vrátil na „Upravit“. Test nezkoumal všechny prvky a Shift+Tab.
- **Úraz, dialog rizika:** otevření umístilo fokus na select a Escape vrátil fokus na spouštěcí kartu. V opakovaných Tab cyklech nativního dialogu byl dvakrát jako `document.activeElement` hlášen `BODY`, nikoliv konkrétní ovládací prvek stránky; samotné toto měření nedokazuje, že se aktivoval podklad. Ověřit fyzicky oběma směry a ve více prohlížečích, včetně interakce se čtečkou.
- **Skutečné computed stavy:** při desktopovém hoveru mělo travel tlačítko bílou na `#009B33`, úrazové bílou na `#00B53B`. Na 375 px emulovaný hover travelu vykázal `rgb(0,180,59)`, tedy nemá smysl přisuzovat mobilnímu dotyku desktopový hover. Fokus travelu měl `3px solid rgba(244,36,52,.35)`, úraz `3px solid #002E5F`; hodnoty je nutné porovnat s konkrétním sousedním pozadím a nesměšovat s výsledkem kontrastu textu. Volání hover a focus probíhala postupně na stejném prvku, takže kombinované stavy závisejí i na kurzoru.

## Doplňující společné měření 2. 11. 2026

Nezávisle na výše popsaném selektivním klávesnicovém testu proběhlo čerstvé měření lokálně v Chrome přes HTTP: [`measurements.json`](../evidence/measurements.json) obsahuje 124 zachycených kontextů, výsledky osmi modelových průchodů (oba produkty × dva starty × 375/1440 px) a 22 snímků. Jde o evidence pro tyto scénáře a rozměry, nikoli o úplné pokrytí kombinací nebo produkční Ferdu. Položka `primary` v měřicím skriptu zahrnuje také některé navigační či druhotné prvky, takže její `count` nelze interpretovat jako počet hlavních CTA. Barvy zaznamenané během CSS animace neslouží jako ustálené tokeny.

| Konkrétní prvek | Travel | Úraz | Rozhodovací dopad |
|---|---|---|---|
| Hero H1 při 1440 / 375 px | 48 / 34 px, váha 600 | 48 / 34 px, váha 600 | Hodnota je už sjednocená; line-height a letter-spacing nejsou úplně totožné. |
| Pracovní H1 na obrazovce údajů při 1440 / 375 px | 32 / 26 px, váha 600 | 32 / 26 px, váha 600 | Zachovat jako společný výchozí pár, pokud projde schválením specifikace. |
| Datum na vstupu na 375 px | `#trip-date-from`, `#trip-date-to`: text 12 px, radius 7 px, výška 48 px | `#profile-age`: 16 px, radius 8 px, výška 48 px; nejde o shodný typ vstupu | Nesjednocovat pouze vnější výšku: cestovní datum má podstatně menší text. Ověřit fyzickou čitelnost a případné chování nativního date inputu na jednotlivých platformách. |
| Jméno v údajích na 375 px | `#client-form [name=firstName]`: 14 px, radius 7 px, výška 48 px | `#person-first`: 16 px, radius 8 px, výška 48 px | Doporučení k rozhodnutí: jednotných 16 px a radius 8 px pro nový společný Field; není to dosavadní shoda ani již schválená změna. |
| Datum a jméno travel při 1440 px | Změřené příklady 16 px, radius 7 px | Změřené úrazové příklady 16 px, radius 8 px | Nesjednocený mobilní obsah a rozdílný radius přetrvávají i přes podobný desktop. |

### Návrh úrovní pravidel pro schválení katalogu

**MUST – návrh závazného minima:** sémantické role tokenů a jejich vlastník; schválené uživatelské preference barev a layoutu včetně zdokumentovaného kontrastního rozporu; plné offline větve a zákaz skutečného odesílání, plateb a sjednání v modelu; označení polí, vazby chyb a náprava; nativní sémantika skupin a dostupná klávesnice; viditelný fokus, přístupná jména a návrat z dialogu; stavově oddělené koncepty návrh/potvrzení; reprodukovatelné nové vydání a zachování starších. Platnost konkrétních barevných preferencí a offline hranic již plyne ze zadání; formalizace ostatních položek jako společné katalogové smlouvy je návrh.

**SHOULD – doporučení ke schválení:** jednotný Field 16 px / radius 8 px / minimálně 48 px výšky; doporučený cíl dotyku 44 × 44 px; škála rozestupů 4/8/12/16/24/32; stávající velikosti hero 48/34 a pracovního H1 32/26; produktové výjimky s důvodem a revizí; test klávesnice, reflow a čteček napříč prohlížeči; oddělené produktové adaptéry. Jde o produktová doporučení, nikoli univerzální tvrzení, že WCAG vyžaduje uvedené hodnoty. Výjimky mají zůstat zdokumentované a hodnocené proti konkrétním kritériím; změny současných vydání nejsou tímto posudkem provedeny.
