AGENTS.web.md — webový profil
1:1 KOPIE SOUBORU
# AGENTS.web.md — profil WEB
Profil média **web** (prezentační weby a webové aplikace, formát `.dc.html`). Nadřazený kontrakt je [`AGENTS.md`](../AGENTS.md) — role barev, typografické role, rytmus a značka jsou tam; tady je jejich webová realizace a všechno, co má jen web (stavy, pohyb, overlaye, komponenty).
**Čti celý.** Katalog webu `design-system-web.dc.html` negrepuj celý (430 kB) — jen konkrétní blok komponenty podle handle z inventáře v § 0 (`grep` na název, např. `>Timeline<`).
| soubor | role |
|---|---|
| `../AGENTS.md` | core — společné pro web, prezentace i dokumenty |
| `AGENTS.web.md` | **tento soubor** — webový profil (ve `docs/`) |
| `../src/design-system-web.dc.html` | **katalog webu** — Foundations + Components (referenční implementace); odsud se kopírují komponenty |
| `../src/design-system.dc.html` | obecný katalog — společná rozhodnutí napříč médii |
| `AGENTS.slides.md` / `AGENTS.docs.md` | profily prezentací a dokumentů (tatáž složka `docs/`) |
| `../tokens/tokens.core.json` | strojová pravda: značky, palety, škály, převody px ↔ pt |
## 0. Inventář komponent — čti první
**Než cokoli postavíš, projdi tenhle seznam.** Když komponenta existuje, nepiš ji znovu — najdi ji v katalogu `design-system-web.dc.html` grepem na uvedený handle a zkopíruj i s jejími metodami. Vlastní varianta existující komponenty je chyba, i kdyby dodržela všechna ostatní pravidla.
| komponenta | grep handle | co v katalogu je |
|---|---|---|
| Tlačítka | `>Tlačítka<` | primary, secondary, ghost, danger, ikonový, sm/md, disabled |
| Štítky & badge | `>Štítky<` | badge, pill, stavové tečky, chip |
| Avatar | `>Avatar<` | velikosti, iniciály, se statusem, skupina |
| Textová pole | `>Textová pole<` | text, focus, error, s ikonou, s jednotkou, spinner |
| Select / multiselect / textarea | `>Select, multiselect<` | select, multiselect s chipy, textarea, počítadlo znaků |
| Volby & přepínače | `>Volby<` | radio group, checkbox, switch, disabled |
| Rozsah | `>Rozsah<` | range, dual range od/do, disabled |
| Datum & čas | `>Datum<` | DatePicker, RangePicker s presety, TimePicker |
| Disabled stavy | `>Disabled stavy<` | pole, select, textarea v disabled |
| **Hlavička** | `>Hlavička<` | sticky header webu: logo, navigace, jazyk, CTA |
| **Patička** | `>Patička<` | patička webu: značka + sociální ikony, dva sloupce odkazů, spodní pruh s copyrightem |
| Hlavička sekce | `>Hlavička sekce<` | eyebrow → nadpis → popis → dělič |
| Dropdown | `>Dropdown<` | menu, row-actions, sdílené `.ds-menu` / `.ds-menu-item` |
| Tooltip | `>Tooltip<` | čtyři strany, na ikoně |
| Accordion | `>Accordion<` | rozbalovací otázka |
| Alert | `>Alert<` | info, success, warning, danger, se zavřením |
| Toast | `>Toast<` | čtyři barvy, s akcí, progress do zmizení |
| Modal | `>Modal<` | formulářový, profilový |
| Confirm modal | `>Confirm modal<` | ano/ne, destruktivní smazání |
| Stavy obsahu | `>Stavy obsahu<` | EmptyState, Loading skeleton, ErrorState, ProgressBar |
| Stats panel | `>Stats panel<` | pás čísel s ikonami a countupem |
| **CompareBars** | `>CompareBars<` | srovnání dvou hodnot na společné ose — referenční a accent pruh, dělič mřížky, popis osy, countup šířky |
| Grafy | `>Grafy<` | sloupcový, čárový, donut, gauge, s tooltipem |
| **Hero** | `>Hero<` | dvousloupcové hero: meta řádek, nadpis s accent řádkem, lead, dvě akce, řada tří faktů |
| **DeviceFrame** | `>DeviceFrame<` | rám monitoru se snímkem produktu — perspektiva, brada s logem, noha se září |
| **FlowDiagram** | `>FlowDiagram<` | živý diagram toku: zdroje → jádro → výstupy, ambientní tečky po spojích, otázky jako vstup, skládaná odpověď |
| Tabulka | `>Tabulka<` | základní tabulka |
| Tabulka — pokročilá | `>Tabulka —` | řazení, filtr, hledání, stránkování, row-actions |
| Seznamy | `>Seznamy<` | řádkový seznam, checklist, feed |
| Paper | `>Paper<` | základní plocha, s hlavičkou, zvýrazněná |
| Karty | `>Karty<` | StatCard, MetricCard, GoalCard, BarCard, GradientCard, ServiceCard, TeamCard |
| Timeline | `>Timeline<` | svislá osa s ikonami a časy |
| Logo marquee | `>Logo marquee<` | nekonečný pás log |
Chybí-li komponenta v inventáři, teprve pak ji navrhni — a rovnou ji doplň do katalogu i sem.
---
## 1. Jak systém používat
**Nový web zakládej jako samostatný celek** — vlastní repozitář, `README.md` a `robots.txt` v kořeni, v `src/` pak `<produkt>.dc.html` v `kebab-case`, `support.js` a `assets/` jen s tím, co web opravdu používá. Výchozí dokument nastaví server; přesměrovací `index.html` nepiš. Assety ze systému se **kopírují** (loga značek), nikdy se na ně neukazuje cestou do systému — jinak se web nedá nasadit samostatně. Systém se do webu nekopíruje celý: čte se z domény nebo z lokální kopie a do výstupu jde jen blok tokenů a použité komponenty.
Čtyři neměnná východiska:
1. **Web je dark only.** Jediný režim webu je tmavý, `--color-bg:#0e0f14`. Světlou variantu na webu nedělej — světlý režim (`paper-light`) existuje jen pro dokumenty a tisk a řídí ho [`AGENTS.docs.md`](AGENTS.docs.md).
2. **Vše z tokenů.** Barva, velikost písma, mezera, rozměr, poloměr, stín, trvání i easing se berou z tokenu. Hodnota „od oka" je chyba, i když vypadá stejně.
3. **Inline styly.** Stylujeme inline na elementu. CSS třídy jen pro to, co inline být nemůže: `@keyframes`, resety a sdílené `.ds-menu` / `.ds-menu-item`.
4. **Tokeny jsou lokální.** Blok tokenů (§ 15) žije na kořenovém elementu každého DC souboru a nedědí se. Chybějící token selže **tiše** — vlastnost se prostě nevykreslí.
Komponenty v kapitole 02 katalogu jsou referenční implementace těchto pravidel, **ne zdroj pravdy**.
Strojová podoba všech hodnot (včetně převodů do pt pro prezentace a dokumenty) je v `tokens.core.json`.
---
## 2. Značka & režim
Multi-brand přes jediný tweak `brand` (povinný prop na každé stránce). Nastaví `--color-accent` na přesný hex, `--h` na hue a `--h2` na druhý odstín značky. `--color-accent-hi` se odvodí z `--h`; `--color-accent-2` z `--h2` — ten je **vlastní hodnota každé značky** (Techfides 205, Tech It Out 148, RTSG 78), ne dopočet z `--h`.
```js
const brands = { 'Techfides': { hex: '#0075c9', h: 250, h2: 205, logo: 'assets/techfides-logo.png' },
'Tech It Out': { hex: '#84bd23', h: 128, h2: 148, logo: 'assets/tech-it-out-logo.png' },
'RTSG': { hex: '#eb7500', h: 56, h2: 78, logo: 'assets/rtsg-logo.png' } };
r.style.setProperty('--h', String(b.h));
r.style.setProperty('--h2', String(b.h2));
r.style.setProperty('--color-accent', b.hex);
r.querySelectorAll('[data-brand-logo]').forEach((el) => el.setAttribute('src', b.logo));
```
- **Text a ikony na accent plochách jsou vždy `#fff`** (primary tlačítka, badge, vybrané položky, fajfky) — ne `--color-fg`.
- `--color-accent-hi` = `oklch(0.73 0.15 var(--h))` — hover na accent ploše, druhá datová série.
- `--color-accent-2` = `oklch(0.74 0.13 var(--h2))` — druhý konec gradientu, sekundární série. `--h2` je **vlastní hodnota každé značky** (Techfides 205, Tech It Out 148, RTSG 78), ne dopočet z `--h`: pevný posun by u teplých značek přetáhl gradient do jiné barevné rodiny (oranžová do růžové, zelená do oranžové).
- Průhledné accent plochy vždy `color-mix(in oklab,var(--color-accent) 15%,transparent)` — nikdy ručně míchaná barva ani `opacity` na celém prvku.
- Nikdy čtvrtá značková barva ani nový odstín mimo tuto trojici.
---
## 3. Barvy & povrchy
| token | hodnota | kdy použít |
|---|---|---|
| `--color-accent` | dle brand | primární akce, aktivní stav, eyebrow, hodnoty v grafech, focus ring |
| `--color-accent-hi` | oklch(.73 .15 h) | hover na accent ploše, druhá datová série |
| `--color-accent-2` | oklch(.74 .13 h2) | světlý konec gradientů, sekundární série; `h2` je per značka |
| `--color-bg` | #0e0f14 | pozadí stránky; nikdy jako pozadí karty |
| `--color-surface-1` | #14161d | neprůhledné vyvýšené plochy — menu, dropdown, modal, tooltip |
| `--color-panel-2` | white 2,5 % | druhá plocha ležící přímo na pásu — nižší dlaždice vedle karty |
| `--color-inset` | white 2,5 % | plocha **uvnitř** panelu — dlaždice, řádek, ukázka (§ 11) |
| `--color-panel` | white 4,5 % | plocha karty (Paper) nad pozadím stránky |
| `--color-panel-hi` | white 6 % | výplň v hoveru — řádek seznamu, dlaždice, skeleton |
| `--color-line-2` | white 5,5 % | jemný vnitřní dělič — mezi řádky, pod hlavičkou karty |
| `--color-line` | white 9 % | ohraničení karet, inputů a menu |
| `--color-line-hi` | white 16 % | ohraničení v hoveru, scrollbar thumb |
| `--color-fg` | #eef1f6 | primární text, nadpisy, hodnoty |
| `--color-muted` | #98a1b2 | sekundární text, popisky, meta, prázdné stavy |
| `--color-muted-on-accent` | white 85 % | sekundární text na accent ploše (primární je vždy `#fff`) |
| `--color-knob` | #f5f7fa | knob u switche a range |
| `--color-scrim` / `--color-scrim-hi` | black 35 / 55 % | tmavá plocha nad obrázkem a její hover |
| `--color-backdrop` | rgb(6,7,10) 60 % | backdrop modalu, vždy s `--blur-overlay` |
**Průhlednost a gradienty mají pevné hodnoty — jiné se nepoužívají:**
| token | hodnota | kdy |
|---|---|---|
| `--tint` | 15 % | výplň barevné plochy: `color-mix(in oklab,var(--color-accent) var(--tint),transparent)` |
| `--tint-hi` | 30 % | hover téže plochy, barevné ringy (`--ring-dot`) |
| `--edge` | 32 % | ohraničení barevné plochy |
| `--grad-accent` | 135°, accent-2 → accent | plochy: dlaždice, avatar, sloupec grafu, zvýrazněné tlačítko |
| `--grad-accent-h` | 90°, accent-2 → accent | vodorovné pruhy: progress, range track, škály |
| `--grad-line` | 90°, accent → transparent | dělič pod otvírákem kapitoly |
Paleta je záměrně malá. Hloubku dělá vrstvení průhlednosti a stín, ne nová barva.
## 4. Sémantické barvy
| token | hodnota | význam |
|---|---|---|
| `--color-success` | oklch(0.72 0.15 155) | úspěch, dokončeno, online, kladná změna |
| `--color-warning` | oklch(0.80 0.14 85) | upozornění, čeká na akci, blízko limitu |
| `--color-info` | oklch(0.70 0.14 235) | neutrální informace, tip, probíhá |
| `--color-danger` | oklch(0.66 0.17 25) | chyba, destruktivní akce, validace, záporná změna |
- Aplikace: `background:color-mix(in oklab,var(--color-danger) var(--tint),transparent)` + `border:1px solid color-mix(in oklab,var(--color-danger) var(--edge),transparent)` + text v plné barvě. Procenta jen z `--tint` / `--tint-hi` / `--edge`.
- Destruktivní akce vždy `--color-danger`, vždy s potvrzením, nikdy jako výchozí zvýrazněné tlačítko v dialogu.
- **Nikdy jako dekorace** — ne pro grafy bez významu, ikony sekcí ani zvýraznění textu.
---
## 5. Typografie
Dvě rodiny, vždy přes token: `--font-display` (Inter, nadpisy a čísla) · `--font-body` (IBM Plex Sans, všechno ostatní — text, labely, eyebrow, hodnoty, osy grafů, meta popisky).
**Na webu se monospace nepoužívá vůbec.** Systém ho drží jen pro kód ve výpisu v dokumentu (core § 4); web žádný takový obsah nemá, proto tu token `--font-mono` neexistuje a nezavádí se. Technický dojem nese `--tracking-eyebrow` + kapitálky, zarovnání číslic `font-variant-numeric: tabular-nums`.
Velikost výhradně ze škály 10 kroků:
| token | velikost | role |
|---|---|---|
| `--text-display` | clamp 34→54 | Display / H1 stránky · Inter 600 · `--tracking-h` |
| `--text-h1` | clamp 30→44 | otvírák kapitoly · Inter 600 · `--tracking-h` |
| `--text-h2` | 30px | nadpis sekce · Inter 600 · `--tracking-h` |
| `--text-h3` | 24px | sub-head / H3 large · Inter 600 · `--tracking-h` |
| `--text-h4` | 20px | podnadpis komponenty, karty nebo bloku · Inter 600 |
| `--text-lead` | 16px | lead / úvodní odstavec sekce · Plex Sans 400 |
| `--text-body` | 15px | běžný text, popisy · Plex Sans 400 |
| `--text-body-sm` | 14px | tlačítka, řádky menu, hustý text · Plex Sans 400–500 |
| `--text-caption` | 13px | formulářový label, sekundární řádek · Plex Sans 500 |
| `--text-caption-sm` | 12px | caption pod prvkem · Plex Sans 400 · **a eyebrow / meta / osa grafu** · Plex Sans 500 + `--tracking-eyebrow` + uppercase |
Line-height: `--leading-tight` 1.1 (nadpisy) · `--leading-snug` 1.5 (víceřádkové popisky v hustém UI) · `--leading-body` 1.6 (běžný text).
Tracking: `--tracking-h` −.02em (všechny nadpisy) · `--tracking-label` .05em · `--tracking-eyebrow` .12em.
## 6. Ikony
Phosphor icon-font (MIT). `ph-bold` pro UI a akcenty, `ph` regular pro klidnou dekoraci. Barva se dědí přes `currentColor`.
```html
<i class="ph-bold ph-arrow-right" style="font-size:var(--icon-md)"></i>
```
| token | velikost | kdy |
|---|---|---|
| `--icon-sm` | 14px | ikona u drobného textu, micro indikátor |
| `--icon-md` | 16px | **výchozí volba v UI**, u textu `--text-body-sm` |
| `--icon-lg` | 20px | ikonový button, zvýrazněná ikona v řádku |
| `--icon-xl` | 24px | dlaždice, hlavička karty |
| `--icon-hero` | 84px | dekorativní prvek sekce |
- Uvnitř klikacích prvků přidej `pointer-events:none`, aby cílem kliku bylo tlačítko.
- Ustálená sada: `ph-code` `ph-device-mobile` `ph-sparkle` `ph-cloud` `ph-shield-check` `ph-lightbulb` `ph-arrow-right` `ph-check` `ph-envelope-simple` `ph-phone` `ph-map-pin` `ph-caret-down`.
- **Nikdy** textový glyf (→, +, ×, ✓) ani ručně kreslené SVG ikony.
## 7. Spacing
4px mřížka. **Osm kroků na vnitřní mezery komponent, tři velké kroky na layout stránky.** Mezi 32 a 48 px nic není — když ti krok chybí, používáš špatný.
| token | px | kdy |
|---|---|---|
| `--spacing-1` | 4 | mezera ikona ↔ micro popisek, offset ringu |
| `--spacing-2` | 8 | label ↔ input, mezi chipy |
| `--spacing-3` | 12 | vnitřní gap prvku (ikona ↔ text), vertikální padding ovladače, výška tracku progress baru |
| `--spacing-4` | 16 | padding hlavičky karty, gap v hustých mřížkách |
| `--spacing-5` | 20 | horizontální padding ovladače md, gap mezi kartami |
| `--spacing-6` | 24 | vnitřní padding karty, odsazení popisu sekce od obsahu |
| `--spacing-7` | 28 | volnější vnitřní padding karty |
| `--spacing-8` | 32 | vodorovný padding kontejneru stránky, gap velké mřížky |
| `--spacing-lg` | 48 | padding velkého bloku, odsazení ikony v inputu, horní padding stránky |
| `--spacing-xl` | 72 | velký odstup uvnitř pásu — mezi bloky sekce |
| `--spacing-2xl` | 100 | dolní padding kontejneru stránky |
`--spacing-inset` (4px) = mezera mezi interaktivním kontejnerem a jeho položkami — sdílí ji segmented control, list selectu i menu.
## 8. Poloměry
| token | px | kdy |
|---|---|---|
| `--radius-xs` | 6 | checkbox |
| `--radius-sm` | 8 | tlačítko, input, řádek menu, chip, swatch |
| `--radius-lg` | 12 | menu, dropdown, toast, vnořený blok |
| `--radius-xl` | 16 | karta, Paper, modal |
| `--radius-pill` | 100 | pill, badge, range track, avatar |
Čtyři kroky, pevné přiřazení — poloměr nese informaci o tom, co prvek je. Nikdy vlastní px hodnota.
## 9. Rozměry & hustota
Rozměry prvků mají vlastní škálu `--size-*` a šířky ploch `--container-*`. **Nepoužívej pro ně spacing tokeny**, i když se hodnota shoduje.
**Každý md ovladač má výšku přesně `var(--size-3xl)` (44px) — ne odvozenou z paddingu.** Výška se píše explicitně (`height:var(--size-3xl)`; u multiselectu, který roste s chipy, `min-height`) a vertikální padding je pak `0`; horizontální zůstává `--spacing-4` u polí a `--spacing-5` / `--spacing-6` u tlačítek. Padding-based výška se rozejde s každou jinou velikostí písma — proto se nepoužívá. Chip v multiselectu má `height:var(--size-lg)`, aby se pole vešlo do 44px.
| token | px | kdy |
|---|---|---|
| `--size-3xs` | 3 | hairline pruh — progress toastu, legenda grafu |
| `--size-2xs` | 6 | tečka stavu |
| `--size-xs` | 8 | indikátor, malý knob, řádek skeletonu, track range |
| `--size-sm` | 16 | checkbox, radio, malá ikona v kruhu |
| `--size-md` | 20 | switch knob, avatar xs |
| `--size-lg` | 24 | výška badge, malý avatar, barevný swatch |
| `--size-xl` | 32 | ikonový button, logo v hlavičce, avatar sm |
| `--size-2xl` | 40 | minimální výška řádku menu |
| `--size-3xl` | 44 | **výška každého md ovladače** (input, select, multiselect, picker, tlačítko, ikonový button), minimální hit-area, řádek tabulky |
| `--size-4xl` | 64 | avatar lg, hero ikonová plocha |
| `--container-menu` | 184 | min. šířka menu, dropdownu, popoveru, sloupce stat panelu |
| `--container-modal-sm` | 400 | confirm dialog — `width:min(var(--container-modal-sm),100%)` |
| `--container-modal` | 460 | standardní modal |
Kontejner stránky `max-width:1120px`, textový blok `max-width:700px` — **jiná šířka odstavce neexistuje.**
**Výjimka: geometrie obsahu.** Výška plátna grafu, výšky sloupců v %, šířka mockupu nebo ilustrace jsou obsah, ne token — píšou se v px a netokenizují se.
**Hustota — nesmlouvavé:**
| prvek | hodnoty |
|---|---|
| tlačítko / input md | `padding:var(--spacing-3) var(--spacing-5)`, `font-size:var(--text-body-sm)`, výška ≥ 40px |
| řádek menu | `padding:var(--spacing-3) var(--spacing-4)`, `font-size:var(--text-body-sm)`, výška ≥ 40px |
| menu / dropdown | `min-width:var(--container-menu)`, `padding:var(--spacing-inset)`, `--radius-lg`, `--color-surface-1`, `--shadow-3` |
| hit-area | `--size-3xl` (44px) u všeho klikacího — doplň `min-height` nebo padding, ne jen vizuál |
| řádek tabulky | `padding:var(--spacing-3) var(--spacing-4)`, hlavička `--text-caption-sm` uppercase + `--tracking-eyebrow`, tělo `--text-caption` |
**Kanonické paddingy — jiný nevymýšlej:** ovladač md `var(--spacing-3) var(--spacing-5)` · ovladač sm `var(--spacing-2) var(--spacing-3)` · chip `var(--spacing-1) var(--spacing-2)` · badge `var(--spacing-1) var(--spacing-3)` · řádek `var(--spacing-3) var(--spacing-4)` · blok `var(--spacing-4) var(--spacing-5)` · hlavička karty `var(--spacing-4) var(--spacing-6)` · tělo karty `var(--spacing-6)` · sekce stránky `var(--spacing-8)`.
**Referenční hustota celého systému = list u selectu.** Select, multiselect, dropdown, row-actions i presety používají **sdílené třídy `.ds-menu` / `.ds-menu-item`** — nikdy vlastní styl položky. Modifikátory `[data-sel]`, `[data-disabled]`, `.ds-danger`. Definice zkopíruj z `<helmet><style>` v katalogu.
## 10. Layout & breakpointy
```
stránka <main style="display:flex; flex-direction:column"> — bez max-width, bez gap
sekce = pás full-width; border-top:1px solid var(--color-line-2); padding:var(--spacing-2xl) var(--spacing-8)
kontejner uvnitř pásu: max-width:1120px; margin:0 auto
mřížka karet display:grid; grid-template-columns:repeat(auto-fit,minmax(360px,1fr)); gap:var(--spacing-5)
odstavec max-width:700px
```
**Sekce je full-width pás, ne blok v jednom kontejneru.** Odsazení dělá vnitřní padding pásu (`--spacing-2xl` nahoře i dole), **ne mezera mezi sekcemi** — `gap` na `main` se nepoužívá. Plochy pásů se **střídají** `bg` ↔ `surface-1`, začíná se `bg`; první pás (hero) má horní padding `--spacing-lg`, protože nad ním je hlavička. Každý pás má nahoře vlásovou linku `--color-line-2` — drží hranu i na displeji, kde je rozdíl obou ploch sotva vidět.
**Třetí plocha ani accent pás neexistuje.** Dvě plochy jsou rytmus, tři jsou chaos; zvýrazněná plocha zůstává jedna na obrazovku a bydlí uvnitř pásu (CTA karta), ne v jeho pozadí.
Breakpointy jsou **konstanty, ne tokeny** (media query CSS proměnné neumí): sm 640 · md 768 · lg 1024 · xl 1280. Logická mřížka 12 sloupců, v praxi `auto-fit`.
**Anatomie sekce — pořadí je pevné:**
```html
<section id="moduly" style="position:relative;overflow:hidden;background:var(--color-surface-1);border-top:1px solid var(--color-line-2);padding:var(--spacing-2xl) var(--spacing-8)">
<div aria-hidden="true" style="position:absolute;inset:0;overflow:hidden;pointer-events:none"><!-- vrstva atmosféry, § 10b --></div>
<div style="position:relative;max-width:1120px;margin:0 auto">
<div style="font-weight:500;font-size:var(--text-caption-sm);letter-spacing:var(--tracking-eyebrow);color:var(--color-accent);margin-bottom:var(--spacing-3)">01 · ZÁKLADY</div>
<h2 style="font-family:var(--font-display);font-weight:600;font-size:var(--text-h2);letter-spacing:var(--tracking-h);margin:0 0 var(--spacing-2)">Nadpis sekce</h2>
<p style="font-family:var(--font-body);font-size:var(--text-body);line-height:var(--leading-body);color:var(--color-muted);max-width:700px;margin:0 0 var(--spacing-6)">Popis…</p>
<!-- obsah: karty na ploše Paper -->
</div>
</section>
```
Pás bez vlastního pozadí (`bg`) vypadá stejně, jen bez `background`.
Otvírák kapitoly navíc uzavírá `<div style="height:1px;background:var(--grad-line);margin-top:var(--spacing-6);opacity:.6"></div>`.
**Paper** — základní plocha každé karty:
```
border:1px solid var(--color-line); border-radius:var(--radius-xl); background:var(--color-panel);
backdrop-filter:blur(var(--blur-panel)) saturate(var(--glass-saturate)); overflow:hidden
```
Hlavička karty `padding:var(--spacing-4) var(--spacing-6)` + `border-bottom:1px solid var(--color-line-2)`; tělo `var(--spacing-6)`.
Skupiny prvků vždy `display:flex` / `grid` + `gap` — nikdy odsazení mezerami mezi elementy ani margin na každém prvku.
---
## 10a. Vysvětlující grafika
**Abstraktní sdělení se kreslí, ne vypisuje.** Tok dat, architektura, proces, srovnání, závislost — to všechno je diagram s pohybem a jedním interaktivním vstupem. Statický sloupec boxů pod sebou je náhrada, která nevysvětlí nic, a v tomto systému je chyba.
Anatomie diagramu (referenční implementace: komponenta `FlowDiagram` v katalogu, handle `>FlowDiagram<`):
| část | pravidlo |
|---|---|
| plátno | `position:relative` s pevným `aspect-ratio` (např. `1000/320`) a `min-height`; uzly jsou absolutně umístěné v procentech, aby seděly na koncích spojů |
| spoje | SVG přes celé plátno, `viewBox` shodný s poměrem stran, `preserveAspectRatio="none"`, křivky (`C`), `vector-effect="non-scaling-stroke"`, klidová barva `--color-line` |
| ambientní tok | po každém spoji nepřetržitě putují tečky (`animateMotion` + `animate` na `opacity`), rozfázované po ~0,5 s; plátno musí žít i bez zásahu uživatele |
| uzly | dlaždice na `--color-panel-2` s ikonou, názvem a metadaty v `--text-caption-sm`; aktivní uzel má `--tint` výplň a `--edge` obrys v accentu |
| jádro | plocha `--grad-accent` se sheenem (`tf-flow`) a **stavovým řádkem**, který se v průběhu mění: čeká → čte → skládá → hotovo |
| vstup | právě jeden ovladač — sada otázek, přepínač nebo krokovač; nikdy „samo běžící" video bez možnosti zasáhnout |
| výsledek | skládá se před očima: text se vypisuje po znacích, číslo dobíhá countupem, zdroje naskočí jako chipy. Nikdy se neobjeví celý naráz |
| reduced motion | `@media (prefers-reduced-motion:reduce)` — tečky a sheen zmizí, výsledek naskočí celý. **Informace se nikdy neztrácí, mizí jen pohyb** |
Sekvence se řídí z logiky (`setTimeout` v metodě, ne `@keyframes` s pevnými prodlevami), aby šla navázat na uživatelský vstup. Ambientní smyčky jsou naopak čistě CSS/SMIL — neběží přes React.
**Každý diagram musí unést tři různé průchody.** Jedna cesta a jedna odpověď vypadá jako dekorace; teprve tři různé kombinace zdrojů a výstupů ukážou, že systém opravdu čte napříč.
---
## 10b. Atmosféra pásu
**Pozadí není plocha, je to prostor.** Každý pás nese pod obsahem vrstvu atmosféry — světelnou hranu nahoře a dvě mlhoviny. Kreslí se výhradně z barev značky, takže se s přepnutím značky přebarví celá stránka, ne jen ovládací prvky.
```html
<section style="position:relative;overflow:hidden;background:var(--color-surface-1);border-top:1px solid var(--color-line-2);padding:var(--spacing-2xl) var(--spacing-8)">
<div aria-hidden="true" style="position:absolute;inset:0;overflow:hidden;pointer-events:none">
<div style="position:absolute;top:0;left:38%;transform:translateX(-50%);width:56%;height:180px;background:radial-gradient(ellipse at top,color-mix(in oklab,var(--color-accent) var(--tint),transparent),transparent 70%)"></div>
<div style="position:absolute;top:34%;right:-10%;width:38%;height:400px;background:radial-gradient(ellipse at center,color-mix(in oklab,var(--color-accent-2) 9%,transparent),transparent 70%)"></div>
<div style="position:absolute;bottom:-14%;left:6%;width:26%;height:260px;background:radial-gradient(ellipse at center,color-mix(in oklab,var(--color-accent) 6%,transparent),transparent 70%)"></div>
</div>
<div style="position:relative;max-width:1120px;margin:0 auto">…</div>
</section>
```
Pás má `position:relative;overflow:hidden`, vrstva je `aria-hidden="true"` a `pointer-events:none`, kontejner obsahu **musí** mít `position:relative` — jinak skončí pod vrstvou.
| vrstva | barva | síla | úloha |
|---|---|---|---|
| světelná hrana | `--color-accent` | `--tint` | navazuje pás na vlásovou linku nahoře |
| hlavní mlhovina | `--color-accent-2` | 7–10 % | barevný nádech, který prosvítá pod kartami |
| protiváha | `--color-accent` | 6–8 % | vyváží pás na opačné straně |
**Žádné dva pásy nemají stejnou kompozici.** Mění se poloha hrany (38–62 % šířky), strana, velikost i síla mlhovin v rozsahu 6–10 %. Pouhé střídání levá/pravá je při scrollování čitelné jako opakovaný vzor — to není atmosféra, to je tapeta.
**Barva se nikdy nepíše ručně.** Vždy `color-mix(in oklab, var(--color-accent | --color-accent-2) …%, transparent)`; `--color-accent-2` je dopočítané `oklch(… calc(var(--h) − 45))`, takže Techfides dostane modrou do azurové, RTSG oranžovou do červené, Tech It Out zelenou do žlutozelené. Ruční je jen síla.
**Hero je nejsilnější místo stránky:** tři mlhoviny na horní hranici rozsahu (`--tint` / 10 % / 8 %) a mihotavé uzly. Běžný pás má dvě mlhoviny bez uzlů. Nikdy naopak — jinak se sekce navzájem překřikují.
---
## 10c. Srovnání na společné ose — CompareBars
Rozdíl mezi dvěma stavy (dřív / teď, ručně / s AI, plán / skutečnost) se **kreslí, ne vypisuje** (core § 1, pravidlo 7). Dvě čísla vedle sebe nutí čtenáře počítat poměr v hlavě; dva pruhy na společné ose ho ukážou dřív, než přečte první znak.
| část | pravidlo |
|---|---|
| osa | společná pro všechny řádky, **vždy od nuly**, delší hodnota = 100 % šířky; dělič mřížky 1px `--color-line-2` v pravidelném kroku uvnitř dráhy |
| dráha | `--color-panel-2`, výška `--size-xl`, `--radius-sm`, `overflow:hidden` — vidět musí být i zbytek osy za výplní |
| referenční pruh | výplň `--color-line-hi`, popisek a hodnota v `--color-muted` |
| cílový pruh | výplň `--grad-accent-h` + `box-shadow:0 0 var(--spacing-6) color-mix(in oklab,var(--color-accent) 45%,transparent)`, popisek `--color-accent`, hodnota `--color-fg` |
| hlavička řádku | popisek vlevo (`--text-caption-sm`, uppercase, `--tracking-eyebrow`) a hodnota vpravo (`--font-display` 600, `--text-h3`, `tabular-nums`) na jedné `baseline` lince |
| popis osy | řádek pod pruhy, `--text-caption-sm` `--color-muted`, stejná mřížka sloupců jako dělič, `aria-hidden` |
| animace | handle `data-hbar` + `data-w="33.3%"` — sdílený IntersectionObserver nastaví `width` na `data-w`; přechod `width var(--dur-3) var(--ease-out)`, cílový pruh navíc `transition-delay:calc(var(--stagger) * 5)`, aby dojel jako druhý |
**Nejvýš dva pruhy.** Tři a víc už není srovnání, ale graf — patří do komponenty Grafy.
**Bez rámu.** Pruhy stojí přímo na ploše pásu; obalit je do karty znamená dvě soutěžící ohraničení. Karta je pro widget, srovnání je sazba.
**Accent smí být jen na jednom pruhu** — na tom, o kterém sekce mluví. Obarvit oba znamená nemít pointu.
Číslo, které z rozdílu plyne („3× rychleji"), se píše jako věta pod grafem v `--text-body`, ne jako displejová číslice. Číslo bez důkazu nad sebou se nepoužívá.
Při `prefers-reduced-motion: reduce` naskočí pruhy rovnou na cílovou šířku.
---
## 10d. Anatomie prezentačního webu
Prezentační web je vždy **jedna stránka složená ze stejných dílů v tomto pořadí** — nic se nevynechává, nic se nepřidává:
```
<header> sticky hlavička z inventáře (§ 0) — logo, navigace na kotvy, jazyk, primární CTA
<main> hero (§ 10e)
01…N pásy obsahu — střídání bg ↔ surface-1, číslované eyebrow
poslední pás: CTA — jedna zvýrazněná plocha, jeden e-mail, jedno tlačítko
<footer> patička z inventáře (§ 0)
```
**Hlavička, patička a hlavička sekce se nikdy nepíšou znovu** — kopírují se z katalogu. Vlastní patička na webu byla reálná chyba: končí tím, že se web tváří jako jiná značka.
**Levá a pravá hrana musí sedět na pixel přes celou stránku.** Kontejner je vždy `max-width:1120px; margin:0 auto` a **padding pásu leží mimo něj**, na vnějším elementu:
```html
<header><div style="padding:var(--spacing-5) var(--spacing-8)"><div style="max-width:1120px;margin:0 auto">…</div></div></header>
```
Padding **uvnitř** elementu s `max-width` zúží obsah o dvojnásobek paddingu (1120 → 1056) a hlavička se rozejde s tělem. Platí pro hlavičku, patičku i každý pás.
Číslování pásů (`02 · MODULY`) je průběžné a začíná u prvního pásu **po hero** — hero eyebrow nemá.
---
## 10e. Hero
První obrazovka rozhoduje. Hero je **dva sloupce: tvrzení vlevo, důkaz vpravo** — `grid-template-columns:repeat(auto-fit,minmax(min(100%,440px),1fr))`, `gap:var(--spacing-xl)`, `align-items:center`; pás má horní padding `--spacing-lg` a atmosféru na horní hranici rozsahu (§ 10b).
| pořadí | část | pravidlo |
|---|---|---|
| 1 | **meta řádek** | živá tečka `--size-2xs` v `--color-success` s `tf-pulse` + jeden fakt o stavu produktu velkými písmeny (`--text-caption-sm`, `--tracking-eyebrow`, `--color-fg`), za ním vlásová linka `--grad-line` `flex:1` dotažená k hraně sloupce |
| 2 | **nadpis** | `--text-display`, `--leading-tight`, dva řádky; **druhý řádek v `--color-accent`** — je to sdělení, ne dekorace |
| 3 | **lead** | `--text-lead`, `--color-muted`, `max-width:520px` (užší než 700px odstavce — vedle sloupce s obrázkem) |
| 4 | **akce** | dvě: primární `--grad-accent` + sekundární ghost s `1px solid var(--color-line)`, obě `height:var(--size-3xl)`, `gap:var(--spacing-3)` |
| 5 | **řada faktů** | tři sloupce, každý `border-top:1px solid var(--color-line-2)` + `padding-top:var(--spacing-4)`; číslo `--font-display` 600 `--text-h3` `tabular-nums`, popisek `--text-caption` `--color-muted`. Vlásová linka nahoře, **nikdy svislá čára vlevo** — řada musí sedět do stejné sazby jako fakta ve zbytku stránky |
| 6 | **důkaz** | pravý sloupec: snímek produktu v rámu podle § 10f, `display:flex;justify-content:center`, přetečení k pravé hraně přesně `margin-right:calc(var(--spacing-8) * -1)` — tedy o padding pásu, nikdy víc |
**Odznaky (pills) jako úvod hero neexistují.** Dvě barevné bubliny nad nadpisem jsou nejgeneričtější prvek, jaký web může mít — sdělení nesou nadpis a lead, stav produktu nese meta řádek.
**Jeden důkaz, ne koláž.** Druhý plovoucí snímek přes rám prvního zakrývá to podstatné a v úzkém sloupci vylézá z plátna. Další obrazovky patří do pásů níž.
---
## 10f. Snímek produktu — DeviceFrame
Snímek nikdy neleží na pásu nahý ani v obyčejné kartě — patří do rámu monitoru. Rám je součást komponenty, jeho hodnoty jsou pevné:
| část | pravidlo |
|---|---|
| perspektiva | obal `perspective:1800px`, vnitřek `transform:rotateY(-9deg) rotateX(3deg)` — konstanty komponenty, ne volba |
| tělo | `1px solid var(--color-line-hi)`, `--radius-xl`, plocha `linear-gradient(180deg,color-mix(in oklab,var(--color-fg) 9%,var(--color-surface-1)),var(--color-surface-1))`, `padding:var(--spacing-3)`, `box-shadow:var(--shadow-3)` |
| horní hrana | `--grad-accent-h` 1px na `opacity:var(--dim)`, zatažená `left:12%;right:12%` — světlo na hraně, ne rámeček |
| plátno | `aspect-ratio:16 / 10`, `--radius-lg`, `overflow:hidden`, plocha `--color-inset`, `1px solid var(--color-line-2)` |
| snímek | `<img>` `width:100%;height:100%;object-fit:cover;object-position:top left` — horní hrana UI musí zůstat vidět; `alt` popisuje, co je na obrazovce |
| brada | `height:var(--size-xl)`, obsah vycentrovaný, logo `--icon-md` na `opacity:var(--dim)` + název produktu `--text-caption-sm` `--tracking-eyebrow` `--color-muted` |
| noha | krček `width:var(--size-4xl)`, `height:var(--spacing-8)`, stejný gradient dolů do `--color-bg`, svislé linky `--color-line-2`; podstavec `width:44%`, `height:var(--size-2xs)`, `--radius-pill`, pod ním záře `0 var(--spacing-5) var(--spacing-8) color-mix(in oklab,var(--color-accent) 18%,transparent)` |
**Skutečný snímek, nebo nic.** Rám s vykresleným falešným UI je horší než žádný obrázek. Do rozpracovaného webu patří placeholder plochy `--color-inset` s popisem, co tam bude — a explicitní žádost o snímek.
**Anonymizace je součást vložení, ne pozdější úklid** (core § 1, pravidlo 8): e-maily, jména, klienti, čísla dokladů. Anonymizovaná kopie jde do `assets/`, originál z `uploads/` se nepoužívá.
---
## 11. Elevation, průhlednost & vrstvy
| token | hodnota | kdy |
|---|---|---|
| `--shadow-1` | 0 1px 2px | jemné oddělení, karty |
| `--shadow-2` | 0 16px 40px −16px | dropdown, tooltip, popover, **karta v hoveru** |
| `--shadow-3` | 0 24px 60px −24px | modal, menu, velké plochy |
| `--shadow-knob` | 0 2px 5px | jen knob u range a switche |
| `--inset-shadow-1` | inset 0 1px 2px | vnitřní stín — track switche a range |
| `--blur-panel` | 18px | `backdrop-filter` na Paper plochách a menu |
| `--glass-saturate` | 170% | sytost skla — pouští barvu atmosféry pod plochu |
| `--blur-overlay` | 4px | `backdrop-filter` na backdropu modalu |
| `--disabled` | .5 | neaktivní prvek (vždy i s `disabled` a `cursor:not-allowed`) |
| `--dim` | .5 | ztišená dekorace — dělič pod nadpisem sekce |
| `--dim-2` | .28 | nejtišší vrstva — mřížka grafu, vodoznak |
| vrstva | z-index | co |
|---|---|---|
| `--z-dropdown` | 20 | select, dropdown, popover, row-actions |
| `--z-tooltip` | 30 | tooltip, chart tooltip |
| `--z-nav` | 50 | sticky navigace a hlavička |
| `--z-modal` | 100 | modal a backdrop |
**Vlastní `box-shadow` z ručně míchané černé, vlastní `opacity` ani `z-index` „od oka" se nepíše.**
**Sklo se ladí sytostí, ne průhledností.** Každá Paper plocha má `backdrop-filter:blur(var(--blur-panel)) saturate(var(--glass-saturate))` — mlhovina pod ní pak prosvítá barevně, ne jen jako světlejší flek. Krycí sílu plochy (`--color-panel`) kvůli tomu **nikdy nesnižuj**: text na kartě musí držet kontrast 4,5:1 a průhlednější plocha ho ztratí.
**Sklo má dvě úrovně a třetí neexistuje.** Průhledná plocha nemá vlastní barvu — její výsledek určuje to, co je pod ní. Protože se pásy střídají `bg` ↔ `surface-1`, vyšla by stejná karta na každém pásu jinak. Proto:
| úroveň | leží na | token | síla |
|---|---|---|---|
| 1 | přímo na pásu | `--color-panel` / `-2` / `-hi` | **kompenzuje ji pás** |
| 2 | uvnitř panelu | `--color-inset` | konstantní, nikdy se nemění |
Pás na tmavém pozadí (`--color-bg`) proto přepisuje sílu skla hned na `<section>`:
```
--color-panel:rgba(255,255,255,.072);
--color-panel-2:rgba(255,255,255,.048);
--color-panel-hi:rgba(255,255,255,.083);
```
Pás na `--color-surface-1` nepřepisuje nic — základní hodnoty platí pro něj. Markup karty se přitom nemění vůbec: autor píše `var(--color-panel)` a nemusí vědět, na jakém pásu stojí. **Vnořená plocha ale musí být `--color-inset`** — přepis na sekci se dědí do celého podstromu, takže `--color-panel-2` uvnitř panelu by se na tmavém pásu zesvětlilo podruhé (krok 10,7 místo 5,4).
**Karta, ve které se něco vysouvá, musí být `data-overlay-host`.** `backdrop-filter` na kartě zakládá stacking context — `z-index` overlaye uvnitř pak nedosáhne nad následující karty a menu/picker/tooltip se schová pod obsah pod sebou. Kontrakt (v `<helmet>`):
```css
[data-overlay-host]{position:relative}
[data-overlay-host]:hover,
[data-overlay-host]:focus-within,
[data-overlay-host]:has([data-open="1"]){z-index:var(--z-dropdown)}
```
Karta hostující overlay navíc nesmí mít `overflow:hidden` — `overflow:visible`.
**Input s ikonou vlevo** je běžný input (stejný rám, výška, focus ring i barvy jako ostatní) — jen s vlastní rezervou vlevo. Ikona je `position:absolute;left:var(--spacing-4)` ve velikosti `--icon-lg`, input má `padding-left:var(--spacing-lg)`; mezera ikona ↔ text tak vyjde přesně na `--spacing-3`. Nikdy nedělej z pole flex řádek s bezrámovým inputem — rozejde se výška i kurzor.
## 12. Pohyb
| token | hodnota | kdy |
|---|---|---|
| `--dur-1` | 140ms | barva, hover, active — okamžitá odezva |
| `--dur-2` | 240ms | otevírání, prolnutí, pop, delší přesun |
| `--dur-3` | 600ms | vstup dat — růst sloupců, šířka pruhů, vjezd řádků |
| `--dur-draw` | 1400ms | kreslení SVG — čáry grafu, prstenec, dlouhý spring (ne checkbox — ten je `--dur-1` bez zpoždění) |
| `--stagger` | 60ms | krok zpoždění v sekvenci: `calc(var(--stagger) * 3)` |
| `--ease-out` | cubic-bezier(.16,.8,.3,1) | výchozí — veškerý pohyb a otevírání |
| `--ease-spring` | cubic-bezier(.34,1.56,.5,1) | playful výběr — toggle, checkbox, chip |
| preset | složení | kdy |
|---|---|---|
| `--t-base` | dur-1 · ease-out | **výchozí přechod ovladače** — background, border-color, color, transform, box-shadow, opacity |
| `--t-overlay` | dur-2 · ease-out | overlay a rozbalování — opacity, transform, visibility, max-height |
| `--t-pop` | dur-2 · ease-spring | playful výběr (toggle, checkbox, chip) |
**Vlastní `cubic-bezier`, vlastní hodnota v ms, ručně skládaný `transition` ani ručně psané zpoždění je chyba.** Sekvence se skládá z `--dur-3` + `calc(var(--stagger) * N)`.
Animace hodnot: spouštěč je `IntersectionObserver` (ne časovač po načtení) — countup u čísel, kreslení čar a prstenců, růst sloupců. Průběžné hodnoty (range, progress, počítadla) se animují, nikdy neskáčou.
Trvání `@keyframes` smyček (shimmer, spin, marquee, indet) tokenizované není — jsou to smyčky, ne přechody; `--dur-*` platí pro `transition`.
Sdílené `@keyframes` v `<helmet><style>` s prefixem `tf-`: `tf-shimmer` (skeleton), `tf-spin`, `tf-indet`, `tf-pulse`, `tf-check-pop` / `tf-check-out` / `tf-check-ripple`, `tf-line-draw`, `tf-bar-grow`, `tf-row-in`, `tf-toast-prog`, `tf-marquee`.
## 13. Interakční stavy
Nejdůležitější pravidlo systému: **žádný „mrtvý" klik.**
**Pět povinných stavů každého interaktivního prvku:**
| stav | co musí platit |
|---|---|
| `default` | ovladač na `--color-panel` nebo `--color-surface-1` s rámečkem `--color-line` |
| `hover` | vždy viditelná odezva: posun 2–4px (`translateY`), zvětšení, ring, nebo glow ≤ 4px z accentu; přechod `--t-base` |
| `active` | stlačení nebo zmenšení, `--dur-1`, okamžitá reakce |
| `focus-visible` | `box-shadow:var(--ring-focus)` nebo `outline:2px solid var(--color-ring)` s offsetem 2px |
| `disabled` | atribut `disabled` + `opacity:var(--disabled)` + `cursor:not-allowed` + žádné hover efekty — **funkční, ne jen vizuální** |
**Čtyři stavy datového widgetu** (tabulka, graf, karta s daty, seznam):
| stav | co musí platit |
|---|---|
| `default` | hodnoty se animují při vstupu do viewportu, graf ukazuje konkrétní hodnotu při hoveru |
| `loading` | skeleton s `tf-shimmer` v rozvržení skutečného obsahu — ne spinner přes celou kartu |
| `error` | ikona a text v `--color-danger` + akce „Zkusit znovu" — nikdy prázdná karta |
| `empty` | Phosphor ikona v `--color-muted`, jednořádkové vysvětlení, primární akce — nikdy jen „žádná data" |
**Luxury feel:** reakce na každý stav · playful přechody `--ease-spring`, pohyb `--ease-out` · zvýrazněné plochy `var(--grad-accent)` + vrstvený stín · zdrženlivě (posun 2–4px, glow ≤ 4px, low-alpha). Luxus je klid, ne křiklavost.
**Sklo na pásu `--color-bg`** — tmavší podklad ubere kartě kontrast, proto pás přepíše tři role hotovými tokeny, ne ručním procentem:
```html
<section style="--color-panel:var(--color-panel-on-bg);--color-panel-2:var(--color-panel-2-on-bg);--color-panel-hi:var(--color-panel-hi-on-bg)">
```
Přepis patří **na pás**, ne na kartu. `--color-sheen` je jediná světlá průhledná bílá mimo tuto trojici — používá ji přejezd lesku (`data-core-sheen`).
---
## 14. Focus & přístupnost
- **Focus ring:** `outline:2px solid var(--color-ring)` + `outline-offset:2px`, nebo `box-shadow:var(--ring-focus)` u ovladačů s vlastním rámečkem. Globálně `:focus-visible`, nikdy `:focus` bez rozlišení.
- **Ring tokeny:** `--color-ring` barva · `--ring-focus` 3px z `--tint` accentu · `--ring-dot` z `--tint-hi` accentu pro kruhové ovladače · `--ring-dot2` totéž z `--color-accent-2`.
- **Hit-area:** ≥ 44px u všeho klikacího, řádek menu ≥ 40px. Malý glyf potřebuje větší obal, ne menší cíl.
- **Kontrast:** text ≥ 4.5:1, velký text a ikony ≥ 3:1. `--color-muted` nikdy na `--color-panel-2` pro důležitou informaci.
- **Labely:** každý input má `<label for>` nebo `aria-label`; chybová zpráva přes `aria-describedby`.
- **Klávesnice:** overlay se zavírá **klikem mimo i Escapem**; Tab v logickém pořadí, focus se nezacyklí mimo modal.
- **Pohyb:** dekorativní animace respektují `prefers-reduced-motion` — vypni pohyb, ne informaci.
---
## 15. Blok tokenů (kopíruj beze změn)
Na kořenový `<div>` každé nové stránky nebo komponenty:
```
--h:250;
--h2:205;
--color-accent:#0075c9;
--color-accent-hi:oklch(0.73 0.15 var(--h));
--color-accent-2:oklch(0.74 0.13 var(--h2));
--color-bg:#0e0f14;
--color-surface-1:#14161d;
--color-panel:rgba(255,255,255,.045);
--color-panel-on-bg:rgba(255,255,255,.072);
--color-panel-2-on-bg:rgba(255,255,255,.048);
--color-panel-hi-on-bg:rgba(255,255,255,.083);
--color-sheen:rgba(255,255,255,.65);
--color-panel-2:rgba(255,255,255,.025);
--color-panel-hi:rgba(255,255,255,.06);
--color-inset:rgba(255,255,255,.025);
--color-line:rgba(255,255,255,.09);
--color-line-2:rgba(255,255,255,.055);
--color-line-hi:rgba(255,255,255,.16);
--color-fg:#eef1f6;
--color-muted:#98a1b2;
--color-muted-on-accent:rgba(255,255,255,.85);
--color-knob:#f5f7fa;
--color-scrim:rgba(0,0,0,.35);
--color-scrim-hi:rgba(0,0,0,.55);
--color-backdrop:rgba(6,7,10,.6);
--color-success:oklch(0.72 0.15 155);
--color-warning:oklch(0.80 0.14 85);
--color-info:oklch(0.70 0.14 235);
--color-danger:oklch(0.66 0.17 25);
--tint:15%;
--tint-hi:30%;
--edge:32%;
--grad-accent:linear-gradient(135deg,var(--color-accent-2),var(--color-accent));
--grad-accent-h:linear-gradient(90deg,var(--color-accent-2),var(--color-accent));
--grad-line:linear-gradient(90deg,var(--color-accent),transparent);
--font-display:'Inter',system-ui,sans-serif;
--font-body:'IBM Plex Sans',system-ui,sans-serif;
--text-display:clamp(34px,4.5vw,54px);
--text-h1:clamp(30px,4vw,44px);
--text-h2:30px;
--text-h3:24px;
--text-h4:20px;
--text-lead:16px;
--text-body:15px;
--text-body-sm:14px;
--text-caption:13px;
--text-caption-sm:12px;
--leading-tight:1.1;
--leading-snug:1.5;
--leading-body:1.6;
--tracking-h:-.02em;
--tracking-label:.05em;
--tracking-eyebrow:.12em;
--icon-sm:14px;
--icon-md:16px;
--icon-lg:20px;
--icon-xl:24px;
--icon-hero:84px;
--size-3xs:3px;
--size-2xs:6px;
--size-xs:8px;
--size-sm:16px;
--size-md:20px;
--size-lg:24px;
--size-xl:32px;
--size-2xl:40px;
--size-3xl:44px;
--size-4xl:64px;
--container-menu:184px;
--container-modal-sm:400px;
--container-modal:460px;
--spacing-1:4px;
--spacing-2:8px;
--spacing-3:12px;
--spacing-4:16px;
--spacing-5:20px;
--spacing-6:24px;
--spacing-7:28px;
--spacing-8:32px;
--spacing-lg:48px;
--spacing-xl:72px;
--spacing-2xl:100px;
--spacing-inset:4px;
--radius-xs:6px;
--radius-sm:8px;
--radius-lg:12px;
--radius-xl:16px;
--radius-pill:100px;
--shadow-1:0 1px 2px rgba(0,0,0,.4);
--shadow-2:0 16px 40px -16px rgba(0,0,0,.8);
--shadow-3:0 24px 60px -24px rgba(0,0,0,.85);
--shadow-knob:0 2px 5px rgba(0,0,0,.45);
--inset-shadow-1:inset 0 1px 2px rgba(0,0,0,.35);
--blur-panel:18px; --glass-saturate:170%;
--blur-overlay:4px;
--z-dropdown:20;
--z-tooltip:30;
--z-nav:50;
--z-modal:100;
--color-ring:var(--color-accent);
--ring-focus:0 0 0 3px color-mix(in oklab,var(--color-accent) var(--tint),transparent);
--ring-dot:0 0 0 3px color-mix(in oklab,var(--color-accent) var(--tint-hi),transparent);
--ring-dot2:0 0 0 3px color-mix(in oklab,var(--color-accent-2) var(--tint-hi),transparent);
--dur-1:140ms;
--dur-2:240ms;
--dur-3:600ms;
--dur-draw:1400ms;
--stagger:60ms;
--ease-out:cubic-bezier(.16,.8,.3,1);
--ease-spring:cubic-bezier(.34,1.56,.5,1);
--t-base:background var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out),box-shadow var(--dur-1) var(--ease-out),opacity var(--dur-1) var(--ease-out);
--t-overlay:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out),visibility var(--dur-2) var(--ease-out),max-height var(--dur-2) var(--ease-out);
--t-pop:opacity var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-spring);
--disabled:.5;
--dim:.5;
--dim-2:.28;
```
Plus na kořeni: `background:var(--color-bg); color:var(--color-fg); font-family:var(--font-body); min-height:100vh; -webkit-font-smoothing:antialiased;`
Do `<helmet>`:
```html
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css">
<link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/bold/style.css">
```
**Nepřidávej nové tokeny.** Chybí-li krok, doplň ho do `tokens.core.json`, do core kontraktu `AGENTS.md`, sem a do katalogu — nikdy jen lokálně.
### Jména tokenů = Tailwind v4 namespace
Tokeny jsou pojmenované podle konvence Tailwind v4, aby ten samý blok byl použitelný jako `@theme` v reálné aplikaci. Export je v **`theme.css`** (`@import "tailwindcss"` + `@theme` s celým blokem a `--*: initial` resetem defaultních škál) — z něj Tailwind sám vygeneruje utility.
| namespace | tokeny | utility, které z toho vzniknou |
|---|---|---|
| `--color-*` | accent, bg, surface-1, panel, line, fg, muted, knob, scrim, backdrop, success/warning/info/danger, ring | `bg-accent`, `text-muted`, `border-line` |
| `--font-*` | display, body | `font-display` |
| `--text-*` | display, h1–h4, lead, body, body-sm, caption, caption-sm | `text-h2` |
| `--leading-*` / `--tracking-*` | tight, snug, body / h, label, eyebrow | `leading-body`, `tracking-eyebrow` |
| `--spacing-*` | 1–8, lg, xl, 2xl, inset | `p-5`, `gap-4` |
| `--radius-*` | sm, lg, xl, pill | `rounded-xl` |
| `--shadow-*` / `--inset-shadow-*` | 1, 2, 3, knob / 1 | `shadow-2` |
| `--blur-*` | panel, overlay | `backdrop-blur-panel` |
| `--ease-*` | out, spring | `ease-out` |
| `--container-*` | menu, modal, modal-sm | `w-modal` |
**Bez namespace** (utility negenerují, jen `var(--…)`): `--h`, `--tint` / `--tint-hi` / `--edge`, `--grad-*`, `--icon-*`, `--size-*`, `--z-*`, `--ring-focus` / `--ring-dot` / `--ring-dot2`, `--dur-*`, `--stagger`, `--t-*`, `--disabled` / `--dim` / `--dim-2`.
**V `.dc.html` se dál píší inline styly s `var(--…)`, ne utility classy** — classy se v tomto runtime nevykreslí, dokud nedoteče celý stylesheet. Tailwind je cílový formát pro dev handoff, ne autoring formát katalogu.
---
## 16. Chování a `data-*` kontrakt
Interakce v katalogu jsou psané jako **data-atributy + metody na `class Component extends DCLogic`** — ne jako samostatné komponenty. Když komponentu přenášíš do nového souboru, **vezmi i její metody**, jinak bude mrtvá.
| komponenta | atributy | metody |
|---|---|---|
| Select | `data-open` na wrapperu, `data-sellist`, `data-selval`, `data-selchev`, `data-sel` | `toggleSelect`, `selectOption`, `closeSel` |
| Multiselect | `data-multiwrap`, `data-multi-opt`, `data-multi-val`, `data-ms-default`, `data-chip-x` | `initMulti`, `multiToggle`, `multiClick`, `multiSync` |
| Dropdown / row-actions | `data-pop`, `data-popwrap`, `data-pop-chev`, `data-kebab`, `data-rowaction` | `openPop`, `closePop`, `ddToggle`, `ddItemClick` |
| Modal | `data-modal`, `data-dialog`, `data-open-modal`, `data-modalscope` | `showModal`, `hideModal`, `modalBackdrop` |
| Tabulka | `data-dtable`, `data-dt-body`, `data-dt-foot`, `data-sort`, `data-page` | `initTables`, `renderTable`, `dtSearch`, `dtFilter`, `dtSort`, `dtPage` |
| Grafy | `data-chart`, `data-bar`, `data-line`, `data-donut`, `data-charttip` | `chartTipShow`, `chartTipHide` |
| Countup | `data-countup` | `setupCounters`, `countUp` |
| Toast / Alert | `data-toaststack`, `data-toast`, `data-toast-prog`, `data-toast-action` | `pushToast`, `toastSpawn`, `alertClose` |
| Pickery | `data-datepicker`, `data-rangepicker`, `data-timepicker`, `data-day`, `data-preset` | `dateToggle`, `drawDate`, `rangeToggle`, `drawRange`, `timeToggle`, `drawTime` |
| Switch / range / radio / checkbox | `data-switch`, `data-switch-knob`, `data-dual-lo/hi`, `data-radio*`, `data-check*` | `switchToggle`, `rangeInput`, `dualInput`, `radioSelect`, `checkToggle` |
| Accordion / segmented / tooltip | `data-answer`, `data-seg`, `data-seg-btn`, `data-seg-ind`, `data-tip` | `faqClick`, `initSegs`, `segClick`, `tipShow`, `tipHide` |
Globální listenery (klik mimo, Escape) registruj v `componentDidMount` a odregistruj v `componentWillUnmount`.
- `data-brand-logo` — `<img>` s logem značky; `applyTheme()` mu podle tweaku `brand` nastaví `src` z `assets/<značka>-logo.png`. Logo se nepřebarvuje filtrem ani nenahrazuje textovým názvem.
---
## 17. Technika
- Vše je **Design Component** (`Name.dc.html`): inline styly, tokeny na kořenovém elementu, logika v `class Component extends DCLogic` s `renderVals()`.
- **Input s předvyplněnou hodnotou používá `defaultValue`, nikdy `value`** — v tomto React runtime by byl zamčený.
- Tweaky deklaruj jako props v `data-props`; `brand` je povinný na každé stránce.
- Nekonstruuj UI přes `React.createElement` — jen tam, kde stav animace musí přežít re-render.
- Statické styly nikdy nepředávej přes `{{ }}` holes; jen skutečně živé runtime hodnoty.
---
**Dvě výjimky z „nula literálů":**
1. **Vzorek hodnoty v katalogu.** Swatch, který ukazuje `#0075C9`, tu hodnotu musí obsahovat — je to obsah, ne styl. Platí jen pro plochu vzorku a text vedle ní.
2. **Zmenšené schéma** (`data-schema`) — náhled slidu, stránky nebo mřížky v katalogu. Jeho rozměry i velikost písma jsou geometrie náhledu, ne sazba; token by schéma rozbil. Vše ostatní uvnitř schématu (barvy, poloměry) z tokenů zůstává.
---
## 18. NIKDY
1. Hodnota „od oka" tam, kde existuje token — `font-size:17px`, `padding:15px`, `#1a1c22`, `300ms`, `border-radius:14px`, `z-index:99`.
2. Nový token vymyšlený lokálně místo doplnění do `tokens.core.json`, core kontraktu a katalogu.
3. Vlastní styl položky rozbalovacího menu místo `.ds-menu-item`, nebo vlastní varianta komponenty, která už je v inventáři (§ 0).
4. Textový glyf jako ikona (→, +, ×, ✓) nebo ručně kreslené SVG ikony.
5. Světlý režim na webu, čtvrtá značková barva, nový odstín mimo `--color-accent` / `--color-accent-hi` / `--color-accent-2`.
6. Sémantická barva jako dekorace.
7. Interaktivní prvek bez hover / active / focus-visible / funkčního `disabled`; datový widget bez loading / error / empty.
8. Klikací plocha < 44px, řádek menu < 40px, menu užší než 180px.
9. Overlay bez zavření Escapem nebo bez `--z-*`.
10. `value` na předvyplněném inputu.
11. CSS třídy a stylesheety pro layout (mimo `.ds-menu*`, `@keyframes`, resety), nebo `React.createElement` pro rozvržení.
12. Nový soubor bez zkopírovaného bloku tokenů z § 15.
13. Monospace kdekoli na webu — ani na eyebrow, hodnotu, meta řádek nebo osu grafu. Číslice zarovnává `tabular-nums`, ne jiná rodina.
14. Vlastní procento v `color-mix` místo `--tint` / `--tint-hi` / `--edge`, nebo gradient mimo `--grad-accent` / `--grad-accent-h` / `--grad-line`.
15. Ručně míchaný stín z `rgba(0,0,0,…)` místo `--shadow-1/2/3`, nebo ručně míchaná průhledná bílá místo `--color-panel*` / `--color-line*`.
16. Ručně skládaný `transition` z longhandů místo `--t-base` / `--t-overlay` / `--t-pop`, nebo ručně psané zpoždění místo `calc(var(--stagger) * N)`.
17. Spacing token použitý jako rozměr prvku (a naopak) — rozměry jsou `--size-*` / `--container-*`.
18. Vlastní šířka odstavce místo `max-width:700px`, vlastní `min-width` menu místo `--container-menu`, vlastní `opacity` místo `--dim` / `--dim-2` / `--disabled`.
19. Lineární gradient jako plocha pásu nebo celé stránky (atmosféra podle § 10b je radiální vrstva **pod** obsahem, plocha zůstává `bg` / `surface-1`), emoji, dekorativní čísla bez významu.
20. Statický sloupec boxů tam, kde se vysvětluje tok, proces nebo architektura — patří tam diagram podle § 10a. Diagram bez pohybu, bez vstupu nebo s jedinou možnou cestou.
21. Pás bez vrstvy atmosféry, nebo dva pásy se stejnou kompozicí mlhovin (i pouhé zrcadlení levá/pravá je stejná kompozice).
22. Mlhovina z literální barvy nebo z jiné než `--color-accent` / `--color-accent-2` — pozadí se musí přebarvit se značkou. Ruční je jen síla, v rozsahu 6–10 %.
23. Snížená krycí síla `--color-panel`, aby bylo pozadí víc vidět — od toho je `--glass-saturate`. Přebarvená karta, aby seděla na pás — opravuje se síla skla na pásu, ne karta. `--color-panel*` na ploše uvnitř panelu (patří tam `--color-inset`) a `--color-inset` na ploše ležící přímo na pásu.
24. Dvě čísla vedle sebe tam, kde jde o rozdíl mezi dvěma stavy — patří tam CompareBars podle § 10c. Osa, která nezačíná nulou; tři a víc pruhů; accent na obou pruzích; srovnání zabalené do karty.
25. Odznaky (pills) jako úvod hero, dva plovoucí snímky přes sebe, nebo hero bez důkazu o produktu — anatomie hero je v § 10e.
26. Vlastní hlavička, patička nebo hlavička sekce místo té z inventáře (§ 0). Padding **uvnitř** elementu s `max-width` — hrany hlavičky, patičky a pásů se pak rozejdou (§ 10d).
27. Snímek obrazovky bez rámu podle § 10f, s vykresleným falešným UI místo skutečného snímku, nebo s neanonymizovanými daty (jména, e-maily, klienti, čísla dokladů).
---
## 19. Hotovo, když
- [ ] Každá použitá komponenta pochází z inventáře (§ 0) — nic z toho, co katalog už má, není psané znovu.
- [ ] Každý pás má vlastní vrstvu atmosféry podle § 10b — jiná poloha, velikost i síla než sousední pás, barvy jen z `--color-accent` / `--color-accent-2`, obsah v `position:relative` kontejneru.
- [ ] Každé abstraktní sdělení je diagram podle § 10a: ambientní pohyb, jeden vstup, tři různé průchody, skládaný výsledek, varianta pro reduced motion.
- [ ] Pás na `--color-bg` přepisuje sílu skla podle § 11; plocha uvnitř panelu používá `--color-inset`, ne `--color-panel*`.
- [ ] Blok tokenů je na kořenovém elementu a **žádný `var(--…)` neukazuje na nedefinovaný token**.
- [ ] Nula literálních `font-size` v px — vše `--text-*` nebo `--icon-*`. Nula literálních `font-family`; **nikde monospace**.
- [ ] Rozdíl mezi dvěma stavy je nakreslený jako CompareBars podle § 10c — společná osa od nuly, accent jen na jednom pruhu, závěrečné číslo jako věta pod grafem.
- [ ] Nula literálních barev mimo `#fff` na accentu; nula literálních ms a `cubic-bezier`.
- [ ] Spacing, rozměry a poloměry výhradně z `--spacing-*` / `--size-*` / `--radius-*`.
- [ ] Každý interaktivní prvek má všech pět stavů; každý datový widget čtyři.
- [ ] Každý overlay se zavírá klikem mimo i Escapem a má `--z-*`.
- [ ] Ikony jsou Phosphor ve velikosti `--icon-*`; hit-area ≥ 44px; kontrast ≥ 4.5:1.
- [ ] Sekce jsou full-width pásy se střídáním `bg` ↔ `surface-1`, padding `--spacing-2xl`, horní linka `--color-line-2`, uvnitř kontejner 1120px; anatomie sekce v pořadí eyebrow → nadpis → popis → obsah.
- [ ] Nula literálních px v `width` / `height` / `min-width` mimo geometrii obsahu; nula ručních zpoždění.
- [ ] Nula ručně míchaných průhlednosti, gradientů, stínů a `transition` — vše z `--tint*` / `--edge` / `--grad-*` / `--shadow-*` / `--t-*`.
- [ ] Stránka má díly v pořadí podle § 10d: hlavička z inventáře → hero → číslované pásy → CTA pás → patička z inventáře.
- [ ] Levá i pravá hrana hlavičky, pásů a patičky sedí na pixel — padding leží mimo kontejner `max-width:1120px`.
- [ ] Hero má všech šest částí podle § 10e v pořadí, žádné pills, jeden důkaz produktu v rámu podle § 10f.
- [ ] Každý snímek obrazovky je anonymizovaný, uložený v `assets/` a má `alt` popisující obsah.
- [ ] Tweak `brand` funguje — přepnutí značky změní celý accent bez artefaktů.