:root {
  --bubble-bg: #ffffff;
  --bubble-text: #111418;
  --bubble-font-size: 18px;
  --accent: #4ba82e;
  --talk-size: 96px;
  /* BARVA TLAČÍTEK NABÍDKY = BARVA BUBLINY AVATARA (Sebastian 2026-08-28: „všechna tlačítka mají
     mít možnost přebarvení, přece logicky … má to být normálně přebarvitelné").
     Do 28. 8. stála natvrdo v tenantových blocích (#0E3A2F u Škody, #001D60 u hokeje) a
     xlab-avatar ji neměl vůbec → padal na --accent. Zdroj je --bubble-bg, kterou config.js plní
     z bubbles.avatarBg: nabídka „mluví za avatara" úplně stejně jako jeho bublina a startovací
     tlačítko (táž úvaha jako u --start-glass). Číselně to sedí — avatarBg je dnes u Škody
     #0E3A2F a u hokeje #001D60, tedy přesně ty hodnoty, které tu stály natvrdo.
     Proměnná zůstává jako ruční přepínač: kdo ji v tenantovém bloku nastaví, přebije nastavení. */
  --choice-bg: var(--bubble-bg, #ffffff);
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: #0b1020; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; }
#avatar-canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }

#ui { position: fixed; inset: 0; pointer-events: none; }
#ui > * { pointer-events: auto; }

/* Bublina titulků — roztáhne se až do krajů, text se zalomí a VEJDE celý (žádný ořez) */
#speech-bubble {
  position: absolute; left: 50%; top: 5%; transform: translateX(-50%);
  max-width: min(960px, 96vw); background: var(--bubble-bg); color: var(--bubble-text);
  font-size: var(--bubble-font-size); line-height: 1.3; padding: 9px 18px;
  border-radius: 20px; box-shadow: 0 8px 30px rgba(0,0,0,.25); text-align: center;
}
#speech-bubble p { margin: 0; }
/* bublina UŽIVATELE (jeho přepis) — barvy uživatele */
#speech-bubble.user { background: var(--bubble-bg-user, #2f7bff); color: var(--bubble-text-user, #fff); }

/* Obrázek/obsah — VYSTŘEDĚNÝ, tenký rámeček, velikost+výška z nastavení */
#content-panel {
  position: absolute; left: 50%; top: var(--img-vert, 50%);
  transform: translate(-50%, -50%) scale(var(--img-scale, 1));
  width: min(540px, 88vw); max-height: 86vh; overflow: visible;
  /* rámeček přebírá barvu bubliny avatara */
  background: var(--bubble-bg, #fff); color: var(--bubble-text, #111);
  border-radius: 18px; padding: 10px; box-shadow: 0 12px 44px rgba(0,0,0,.45);
}
#content-panel img, #content-panel video, #content-panel iframe { display: block; max-width: 100%; border-radius: 12px; }
/* webové okno (iframe) — vlastní velikost (--web-scale) a výška (--web-vert), širší než obrázek */
/* webové okno = NA VÝŠKU 9:16 (jako web na telefonu); velikost/výška přes --web-scale/--web-vert */
#content-panel.panel-web { top: var(--web-vert, 50%); transform: translate(-50%, -50%) scale(var(--web-scale, 1)); width: min(360px, 86vw); }
#content-panel.panel-web img { width: 100%; height: auto; max-height: 78vh; }
#content-panel.panel-web iframe { width: 100%; aspect-ratio: 9 / 16; max-height: 80vh; }
/* ODCHOD WIDGETU (Sebastian 2026-08-28: „jakmile já začnu mluvit, měl by zmizet ten widget …
   chci vidět toho avatara, ke kterému mluvím"). Mizení musí být PLYNULÉ, ne skok do display:none —
   stejný princip jako odchod nabídky (#choices.leaving). Třídu .leaving nasazuje main.js
   (hidePanelForSpeech) na dobu animace a teprve po jejím dojezdu přijde .hidden.
   Dvě sady snímků, protože obrázek a webové okno mají KAŽDÝ SVOU škálu z nastavení (--img-scale
   vs. --web-scale) — kdyby snímky psaly transform natvrdo, widget by při odchodu skočil na
   výchozí velikost. V klidovém stavu se pravidlo neuplatní (třída tam není), takže computed
   styly panelu u žádného tenanta nemění. */
#content-panel.leaving { animation: panelOut .22s ease both; pointer-events: none; }
@keyframes panelOut {
  from { opacity: 1; transform: translate(-50%, -50%) scale(var(--img-scale, 1)); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--img-scale, 1) * .94)); }
}
#content-panel.panel-web.leaving { animation: panelWebOut .22s ease both; }
@keyframes panelWebOut {
  from { opacity: 1; transform: translate(-50%, -50%) scale(var(--web-scale, 1)); }
  to   { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--web-scale, 1) * .94)); }
}
/* tlačítko „Otevřít stránku" — JEN na telefonu (kiosk/tablet/PC ho NEmají) */
.web-open { display:none; text-align:center; margin-top:10px; padding:13px 18px; border-radius:12px;
  background: var(--accent, #2f7bff); color: var(--bubble-text-user, #fff); font-weight:700; text-decoration:none; font-size:18px; }
.web-open:active { transform: scale(.97); }
/* červený kulatý zavírací křížek (vpravo nahoře) */
.panel-close {
  position: absolute; top: -16px; right: -16px; width: 46px; height: 46px; border-radius: 50%;
  background: #e23b3b; color: #fff; border: 3px solid #fff; font-size: 20px; font-weight: 700; cursor: pointer;
  display: flex; align-items: center; justify-content: center; box-shadow: 0 4px 16px rgba(0,0,0,.5); z-index: 3; line-height: 1;
}
.panel-close:active { transform: scale(.94); }
/* e-mail okno */
.email-box { display: flex; flex-direction: column; gap: 12px; padding: 6px; }
.email-title { font-size: 20px; font-weight: 700; text-align: center; color: var(--disclaimer-text, #fff); }
#email-input {
  font-size: 22px; padding: 14px 16px; border-radius: 12px; border: 2px solid var(--accent, #2f7bff);
  outline: none; text-align: center; background: #fff; color: #111;
}
#email-input.bad { border-color: #e23b3b; background: #fff2f2; }
.email-send {
  font-size: 20px; font-weight: 700; padding: 14px; border-radius: 12px; border: none; cursor: pointer;
  background: var(--accent, #2f7bff); color: var(--bubble-text-user, #fff);
}
/* dotyková klávesnice (PC/kiosk) — barvy z bublin (přepsatelné v nastavení) */
/* širší okno když je klávesnice (ať je standardní/obdélníková, ne vysoká) */
.panel-wide { width: min(780px, 96vw) !important; }
#osk { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.osk-row { display: flex; gap: 6px; justify-content: center; }
.osk-key {
  flex: 1 1 0; min-width: 0; padding: 11px 2px; border-radius: 8px; border: none; cursor: pointer;
  background: var(--kbd-key, var(--accent, #2f7bff)); color: var(--kbd-text, #fff); font-size: 18px; font-weight: 600;
}
.osk-key:active { filter: brightness(.85); }
.osk-space { flex: 5 1 0; }
/* MAZACÍ KLÁVESA se má od ostatních odlišit, ale odstínem TÉŽE palety — do 28. 8. tu byla
   oranžová #e2683b natvrdo, která se s žádnou klientskou barvou nepotká. Odstín se počítá ze
   živé --kbd-key (config.js: keyboard.color, jinak bubbles.userBg), ne jako hotová konstanta.
   Bez color-mix zůstane klávesa v barvě ostatních kláves — pořád čitelná, jen bez odlišení. */
.osk-back { flex: 1.6 1 0; background: var(--kbd-key, var(--accent, #2f7bff)); }
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  .osk-back { background: color-mix(in srgb, var(--kbd-key, var(--accent, #2f7bff)) 72%, #000); }
}

/* Řádek voleb se NEROZTAHUJE přes celou obrazovku (Sebastian 2026-08-26: „tlačítka jsou moc
   dlouhá na svůj text"). Šířka jde z obsahu, blok je vycentrovaný, 94vw je jen strop.
   STRUKTURA (od 2026-08-26): #choices je SLOUPEC = nepovinný #choices-title + #choices-row
   s pilulkami. Bez nadpisu má sloupec jediné dítě, takže rozvržení vychází přesně jako dřív. */
#choices {
  position: absolute; left: 50%; bottom: var(--choice-vert, 18%); transform: translateX(-50%) scale(var(--choice-scale, 1));
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  width: max-content; max-width: 94vw;
  animation: choicesIn .55s ease both;   /* plynulý nástup nabídky (Sebastian: „hezký fade-in") */
}
@keyframes choicesIn {
  from { opacity: 0; transform: translateX(-50%) translateY(14px) scale(var(--choice-scale, 1)); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0)    scale(var(--choice-scale, 1)); }
}
/* ODCHOD NABÍDKY (Sebastian 2026-08-28: „tlačítka mi zmizela, pak se mi na chviličku vrátila
   … takovéhle blikání" — mizení má být plynulé, ne skok). Třídu .leaving nasazuje main.js
   (hideChoices / openPanel) na dobu animace a teprve po jejím dojezdu přijde .hidden.
   pointer-events: none = po kliknutí už mizející tlačítka nejdou zmáčknout podruhé.
   V klidovém stavu se pravidlo NEUPLATNÍ (třída tam není), takže computed styly nabídky
   u žádného tenanta nemění. */
#choices.leaving { animation: choicesOut .2s ease both; pointer-events: none; }
@keyframes choicesOut {
  from { opacity: 1; transform: translateX(-50%) translateY(0)    scale(var(--choice-scale, 1)); }
  to   { opacity: 0; transform: translateX(-50%) translateY(10px) scale(var(--choice-scale, 1)); }
}
#choices-row {
  display: flex; gap: 14px; flex-wrap: nowrap; justify-content: center;
  width: 100%; min-width: 0;
}
/* NADPIS NAD NABÍDKOU (pole "title" od mozku, např. „Co tě zajímá?"). BEZ pozadí — plotna
   evokovala další tlačítko; je to nadpis, ne ovládací prvek. Čitelnost nad světlou scénou
   drží stín písma. */
#choices-title {
  max-width: 100%; box-sizing: border-box;
  padding: 0 12px 2px;
  color: var(--bubble-text, #fff); font-size: 20px; font-weight: 700; line-height: 1.25; text-align: center;
  letter-spacing: .01em; text-wrap: balance;
  text-shadow: 0 1px 4px rgba(0,0,0,.55), 0 0 14px rgba(0,0,0,.35);
}
/* Tlačítka voleb = PILULKA se sklem (Sebastian 2026-08-26).
   BARVA: --choice-bg, default = --accent (Škoda/xlab beze změny). Hokej tenant si ji přepisuje
   na navy #001D60 (viz sekce tenanta níž) — červená #DC2300 patří JEN bublině uživatele,
   všechno, co „mluví za avatara" (bublina avatara + nabídka), je navy.
   Vrstvy: (a) plná barva = fallback pro prohlížeč bez color-mix, (b) poloprůhledná barva,
   (c) sklo s blurem. Vnitřní 1px okraj je box-shadow inset, NE border — border by tlačítku
   přidal 2 px na rozměru a na telefonu rozhodil sloupec (šířka jde z obsahu). */
#choices button {
  flex: 0 1 auto; min-width: 0;    /* šířka podle textu, ne přes celý řádek */
  border: none; background: var(--choice-bg, var(--accent)); color: var(--bubble-text, #fff); font-size: 22px; font-weight: 600;
  /* TVAR NABÍDKY na jednom místě: --choice-radius (999px = pilulka, ~16px = zaoblené rohy jako
     dlaždice .cat-card v appce síně slávy). Přepnutí = změna téhle jediné proměnné; na rychlé
     porovnání slouží ladicí parametr ?choiceradius=16 (viz main.js). */
  padding: 18px 34px; border-radius: var(--choice-radius, 999px); cursor: pointer;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.30), 0 6px 20px rgba(0,0,0,.25);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.2;
}
/* (b) bez bluru (starší prohlížeč / vypnutá kompozice) → plnější alfa, ať je text pořád čitelný */
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  #choices button { background: color-mix(in srgb, var(--choice-bg, var(--accent)) 88%, transparent); }
}
/* (c) sklo. VÝKON: blur se počítá jen nad plochou tlačítek (pár pilulek), nikdy nad fullscreen
   overlayem — nad WebGL plátnem je to jediná ekonomicky únosná varianta. */
@supports (((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)))
           and (background: color-mix(in srgb, red 50%, transparent))) {
  #choices button {
    background: color-mix(in srgb, var(--choice-bg, var(--accent)) 62%, transparent);
    backdrop-filter: blur(10px) saturate(1.4);
    -webkit-backdrop-filter: blur(10px) saturate(1.4);
  }
}
#choices button:active { transform: scale(.97); }
/* DESKTOP (Sebastian 2026-08-26): tlačítka byla v jedné řadě malá → mřížka 2×2.
   Telefon zůstává sloupec (media níž).
   POZICE BLOKU (oprava 2026-08-27): stál NAD bezpodmínečnými #choices button / #choices-title
   se STEJNOU specificitou, takže z něj platila jen geometrie (tu základní pravidla nenastavují)
   a všechny stupně písma v něm byly MRTVÉ — 25px tlačítek, 24px nadpisu i hokejových 27px
   přebíjela základní pravidla níž. Blok je proto přesunutý POD ně; odteď se tu změna projeví.
   Mrtvé hodnoty se neoživují: schválený vzhled Puka i xlab-avatara je ten, který se dosud
   reálně vykresloval (tlačítka 22px, hokej 23px, nadpis 20px / hokej 30px) a nemá se hnout.
   Stupeň nadpisu si nad tlačítka zvedá tenant ve své sekci níž (hokej 30px, Škoda 34px). */
@media (min-width: 601px) {
  /* Mezera mřížky je v proměnné, aby si ji mohlo započítat pravidlo pro osamocenou poslední
     položku (sekce tenanta Škody níž). Hodnota zůstává 16px — computed styl se nemění. */
  #choices-row { display: grid; grid-template-columns: repeat(2, minmax(260px, 340px)); gap: var(--choice-grid-gap, 16px); justify-content: center; }
  #choices button { width: 100%; }
}
.hidden { display: none !important; }

/* DENNÍ LIMIT (klient): overlay „pro dnešek vyčerpáno, zkus to zítra" — navy plate přes střed,
   scéna zůstává vidět; disclaimer nezakrývá (overlay je vycentrovaný, lišta dole zůstává). */
#daily-limit {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  /* fallback pro prohlížeč bez color-mix; živou hodnotu dává pravidlo pod ním */
  background: rgba(0, 10, 35, .55); pointer-events: auto;
}
/* ZÁVOJ se dopočítává ze ŽIVÉ barvy, ne z konstanty (stejný princip jako --start-glass): je to
   barva bubliny avatara ztmavená k černé a puštěná na 55 %. Že je recept správný, ukazuje
   kontrola na hokeji — #001D60 × 36 % + černá = rgb(0, 10, 35), tedy přesně ta rgba() nad tím. */
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  #daily-limit {
    --dl-scrim: color-mix(in srgb, var(--bubble-bg, #001D60) 36%, #000);
    background: color-mix(in srgb, var(--dl-scrim) 55%, transparent);
  }
}
/* PLOTNA hlášky „pro dnešek vyčerpáno" mluví za avatara → bere jeho barvy (bubbles.avatarBg /
   avatarText), ne natvrdo navy. U hokeje z toho vyjde totéž #001D60, co tu stálo do 28. 8. */
#daily-limit .dl-box {
  max-width: 84vw; padding: 26px 30px; border-radius: 22px; background: var(--bubble-bg, #001D60); color: var(--bubble-text, #fff);
  font-size: 20px; line-height: 1.45; text-align: center; font-weight: 600;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.25), 0 14px 44px rgba(0,0,0,.5);
}
[data-tenant="hokej-avatar"] #daily-limit .dl-box { font-family: "Druk Text", Inter, system-ui, sans-serif; }

/* Pozadí historky: fixní vrstva NAD CSS pozadím body, POD canvasem (vloženo v DOMu před #stage).
   Prolnutí tam/zpět řeší opacity; cover + center = na výšku prostřední pruh (obrázky jsou 9:16). */
#story-bg {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-position: center center; background-size: cover; background-repeat: no-repeat;
  opacity: 0; transition: opacity 1.6s ease-in-out;   /* plynulé prolnutí jako u Laurina, žádný střih */
}
#story-bg.on { opacity: 1; }

/* ---- Talk tlačítko — VRSTVENÁ kompozice 1:1 dle UE kiosku (Laurin) --------------------------------
   Zdroj pravdy = KioskInteractionButtonComponent.cpp + KioskTheme.h. Všechny dodané PNG leží na
   JEDNOM plátně 1440×1417 a jsou v něm už zaregistrované na svém místě, takže se kreslí na STEJNÉ
   bounds — žádné škálování, žádné offsety jednotlivých vrstev. Poměr stran tlačítka = 1440:1417.
   Vrstvy odspodu: (0) podklad (jen desktop) → (1) koule → (2) prstenec (FIXNÍ) → (3) ikona / tečky.
   Barvení: PNG jsou bílé s alfou → maska (mask-image) + background-color, NE CSS filter.
   Zpětná vazba = ZMĚNA STAVU (barva koule + ikona). Prstenec nikdy nebliká ani nepulzuje. */
#talk-wrap {
  position: absolute;
  /* default = telefon na výšku → dole uprostřed (nad disclaimerem) */
  left: 50%; bottom: 12%; transform: translateX(-50%);
  z-index: 30;   /* VŽDY nad disclaimerem (ať jde kliknout i když ho disclaimer překrývá) */
  /* stavové barvy koule (XLabKioskTheme::TalkWaiting/TalkListening/TalkMuted).
     Koule je BÍLÉ PNG použité jako maska, obarvené touhle CSS proměnnou — žádná barva není
     zapečená v assetu, takže per-tenant přebarvení = jen přepsat proměnnou (viz sekce tenantů). */
  /* KLIDOVÁ BARVA KOULE = barva bubliny avatara (Sebastian 2026-08-28: přebarvitelné z nastavení).
     Do 28. 8. tu stála UE modrá #1C54D6 natvrdo a hokej si ji ve svém bloku přepisoval na navy —
     což je přesně ta ruční práce v kódu, která se má nahradit polem v dashboardu. Klidový stav je
     BRANDING (proto si ho hokej přebarvoval); zelená poslechu a červená mute jsou naproti tomu
     univerzální stavové signály a zůstávají natvrdo (viz dva řádky pod blokem). */
  --talk-idle-color: var(--bubble-bg, #1C54D6);
  --talk-face-color: var(--talk-idle-color);   /* idle — mikrofon */
  --talk-ring-color: #EFEADE;   /* prstenec + podklad = slonovina (TalkRing), NE čistá bílá */
}
#talk-wrap[data-state="listening"] { --talk-face-color: #0C805C; }   /* poslouchám */
#talk-wrap[data-state="speaking"]  { --talk-face-color: #D32F2F; }   /* avatar mluví (mute) */
@media (orientation: portrait) and (min-width: 600px) {  /* tablet na výšku → vpravo uprostřed */
  #talk-wrap { left: auto; right: 4%; bottom: auto; top: 50%; transform: translateY(-50%); }
}
@media (orientation: landscape) {  /* PC / tablet na šířku → vpravo uprostřed (jako kiosek) */
  #talk-wrap { left: auto; right: 4%; bottom: auto; top: 50%; transform: translateY(-50%); }
}

#talk-btn {
  position: relative; width: var(--talk-size);
  height: calc(var(--talk-size) * 1417 / 1440);   /* poměr dodaného plátna */
  background: none; border: none; padding: 0; cursor: pointer; display: block;
  -webkit-tap-highlight-color: transparent;
  /* tečky poslechu — zlomky ŠÍŘKY plátna (UE FaceDotFrac / FaceDotGapFrac) */
  --dot-w: calc(var(--talk-size) * 0.090);
  --dot-gap: calc(var(--talk-size) * 0.0376);
}
/* jedna vrstva kompozice = maska přes celé plátno, obarvená pozadím elementu */
.talk-layer {
  position: absolute; inset: 0; display: block; pointer-events: none;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
}
/* (0) PODKLAD pod koulí — JEN desktop/kiosk. Kryje průhlednou spáru, když se koule při stisku
   zmenší (prstenec se nehýbe). Na telefonu je plný kulatý prstenec → podklad nemá co krýt. */
.talk-backing {
  background-color: var(--talk-ring-color);
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_outline_mask_filled.png");
          mask-image: url("../assets/ui/talk/talk_btn_outline_mask_filled.png");
}
#talk-wrap.phone .talk-backing { display: none; }
/* KOULE + její ikona/tečky = jediná skupina, kterou zmenšuje stisk (UE ZT-STISK, pivot střed) */
.talk-ball {
  position: absolute; inset: 0; display: block; transform-origin: 50% 50%;
  transition: transform .1s ease;
}
#talk-btn:active .talk-ball { transform: scale(.95); }
/* (1) koule — dodaný bílý disk tónovaný stavovou barvou */
.talk-circle {
  background-color: var(--talk-face-color);
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_circle_mask.png");
          mask-image: url("../assets/ui/talk/talk_btn_circle_mask.png");
}
/* (3) bílé ikony — obě jsou VŽDY v DOMu (přepíná se opacita), aby se masky načetly dopředu
   a přepnutí stavu bylo okamžité, bez probliknutí */
.talk-icon { background-color: #ffffff; opacity: 0; }
.talk-icon-mic {
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_icon_mic.png");
          mask-image: url("../assets/ui/talk/talk_btn_icon_mic.png");
}
.talk-icon-mute {
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_icon_mute.png");
          mask-image: url("../assets/ui/talk/talk_btn_icon_mute.png");
}
#talk-wrap[data-state="idle"] .talk-icon-mic { opacity: 1; }
#talk-wrap[data-state="speaking"] .talk-icon-mute { opacity: 1; }
/* (2) PRSTENEC — vlastní dodaná vrstva, FIXNÍ: nikdy se neškáluje ani nehýbe.
   Desktop = oříznutý na pravé hraně plátna (lícuje s hranou obrazovky), telefon = plný kulatý. */
.talk-ring {
  background-color: var(--talk-ring-color);
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_outline_mask.png");
          mask-image: url("../assets/ui/talk/talk_btn_outline_mask.png");
}
#talk-wrap.phone .talk-ring {
  -webkit-mask-image: url("../assets/ui/talk/talk_btn_outline_mask_full.png");
          mask-image: url("../assets/ui/talk/talk_btn_outline_mask_full.png");
}

/* 3 tečky reagující na hlas — jen ve stavu „poslouchám", vycentrované na kouli (dodané masky jsou
   centrované → žádné posuny). Klid = kruh, s hlasem roste do kapsle (rádius = polovina šířky). */
.talk-dots {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: none; align-items: center; justify-content: center; gap: var(--dot-gap);
  pointer-events: none;
}
#talk-wrap[data-state="listening"] .talk-dots { display: flex; }
.talk-dots i {
  /* ŠÍŘKA je pro všechny tři STEJNÁ (--dot-w) — žádná výjimka pro prostřední (Sebastian 2026-08-25:
     „prostřední je užší" = bug). Mění se JEN výška. */
  flex: 0 0 auto; width: var(--dot-w); min-width: var(--dot-w); max-width: var(--dot-w);
  background: #fff;
  border-radius: calc(var(--dot-w) / 2);
  /* height = základ + růst * level. ZÁKLAD (klid, level = 0) je pro VŠECHNY TŘI STEJNÝ = --dot-w →
     v klidu jsou to tři shodné bílé kuličky (Sebastian 2026-08-25: „prostřední je vyšší i v klidu" = bug).
     PROSTŘEDNÍ VEDE JEN S HLASEM: má větší růstový koeficient (4,2 vs 2,8) a navíc silnější signál
     (krajní --lvl = 0,7 × --lvl-mid). Při level = 0 se oba vzorce rovnají --dot-w. */
  height: calc(var(--dot-w) + var(--dot-w) * 2.8 * var(--lvl, 0));
  transition: height .05s linear;
}
.talk-dots i:nth-child(2) {
  width: var(--dot-w);   /* explicitně: stejná tloušťka jako krajní */
  height: calc(var(--dot-w) + var(--dot-w) * 4.2 * var(--lvl-mid, 0));
}

/* ruka touch-hint (kresba talk_hand.png, 1285×1285 = čtverec) — pulz „tap me".
   Sebastian 2026-08-25: velikost zůstává 2× (92 % šířky tlačítka), ale ruka NESMÍ ležet na bílé ikoně
   mikrofonu (splývala do bílé změti). Tělo ruky je proto MIMO kouli — vlevo dole pod tlačítkem —
   a na kouli zasahuje jen špička prstu s „tap“ vlnkou, která míří do středu.
   Geometrie (změřeno z dodaných PNG masek):
     • koule: střed (50 %, 50 %) tlačítka, poloměr 44,1 % ŠÍŘKY plátna
     • ikona mikrofonu: x 35–65 %, y 28,9–71,1 % → sem ruka nesmí ani při pulzu
     • špička ukazováku v kresbě = (70 %, 30 %) plátna, osa prstu míří vzhůru vpravo pod ~49°
   Špička patří na spodní levou hranu koule = bod pod úhlem 49° od středu směrem dolů vlevo:
     tipX = 50 % − 44,1 % × cos 49°             ≈ 21,1 % ŠÍŘKY
     tipY = 50 % + 44,1 % × sin 49° × (š/v)      ≈ 83,9 % VÝŠKY
   a z toho (výška ruky = 92 % ŠÍŘKY wrapu = 93,5 % jeho výšky):
     left   = 21,1 % − 70 % × 92 %              ≈ −43,3 %
     bottom = 100 % − 83,9 % − 70 % × 93,5 %   ≈ −49,4 %
   Když se změní šířka, přepočítej podle stejných vzorců oba offsety — jinak prst přestane mířit na
   hranu koule a při posunu nahoru začne ležet na mikrofonu.
   HOKEJ má jiné zadání (prst na STŘED) — viz tenantový override v sekci síně slávy níž. */
#talk-hand {
  position: absolute; width: 92%; left: -43.3%; bottom: -49.4%; opacity: 0;
  pointer-events: none; user-select: none; -webkit-user-drag: none;
  /* pulz škáluje kolem špičky prstu → ta zůstává přilepená na svém cíli a zbytek ruky roste
     SMĚREM VEN (dolů vlevo), nikdy přes ikonu */
  transform-origin: 70% 30%;
}
#talk-wrap.hint #talk-hand { animation: handpulse 1.5s ease-in-out infinite; }
@keyframes handpulse {
  0%, 100% { opacity: .95; transform: scale(1); }
  50% { opacity: 1; transform: scale(1.18); }
}

/* ---- Vlaječky jazyků (jako na kiosku: na opačné straně než tlačítko interakce) ---- */
#lang-flags {
  /* velikost jde z nastavení přes --flag-size na <html> (config.js) — tady se NEsmí přepsat,
     jinak by lokální deklarace přebila hodnotu z configu */
  position: absolute; display: flex; flex-direction: column; gap: 12px; z-index: 29;
}
#lang-flags.row { flex-direction: row; }
#lang-flags button {
  width: var(--flag-size, 76px); height: var(--flag-size, 76px); padding: 0; border-radius: 50%;
  border: 2px solid transparent; background: none; cursor: pointer; overflow: hidden;
  opacity: .5; transition: opacity .15s, box-shadow .15s; -webkit-tap-highlight-color: transparent;
}
#lang-flags button.active { opacity: 1; border-color: #fff; box-shadow: 0 0 0 4px rgba(255,255,255,.16), 0 0 20px rgba(255,255,255,.22); }
#lang-flags button:active { transform: scale(.95); }
#lang-flags img { width: 100%; height: 100%; object-fit: cover; display: block; user-select: none; -webkit-user-drag: none; }

/* ---- Disclaimer (barevný pruh roztažený přes celou spodní část, jako v kiosku) ---- */
#disclaimer {
  position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 5; pointer-events: none;   /* pod talk tlačítkem; neblokuje klik (je to jen text) */
  padding: 14px 14px calc(14px + env(safe-area-inset-bottom));   /* čistý pruh — žádná zóna pro vinětu */
  /* PLNÁ barva s ROVNOU horní hranou (barva z nastavení disclaimer.bg), žádný gradient/viněta */
  /* Barvy z nastavení: --disclaimer-bg (disclaimer.bg, jinak bubbles.avatarBg) a --disclaimer-text
     (disclaimer.textColor) — obojí dosazuje config.js na <html>. Do 28. 8. tu stála černá a bílá
     natvrdo; v režimu „text" je sice přebíjel inline styl z applyUiConfig, ale v režimu „obrázek"
     se inline pozadí nenastavuje, takže pruh pod průhledným logem zůstával ČERNÝ bez ohledu na
     paletu klienta. Navíc to odstraňuje černé bliknutí, než doběhne /api/config. */
  background: var(--disclaimer-bg, #000000);
  color: var(--disclaimer-text, #ffffff); font-size: 19px; line-height: 1.3; text-align: center;
  text-transform: uppercase;   /* VELKÁ PÍSMENA (Sebastian 2026-08-25) */
  /* VĚTŠÍ + PROSTRKANÝ (Sebastian 2026-08-26): Druk Text velkými je hustý a špatně se čte.
     13 → 19 px (+46 %) a prostrkání; čitelnost má přednost před kompaktností. Font se NEMĚNÍ. */
  letter-spacing: .06em;
  /* Strop řádků = POJISTKA proti extrémně dlouhému textu z dashboardu, ne designový cíl —
     lišta si výšku bere podle potřeby. Náš text má na širokém desktopu 1 řádek, kolem 700–1160 px
     2 řádky, těsně nad hranicí telefonu 3 → strop je 3, jinak by se právní věta uřízla
     (změřeno na 601 px). Na telefonu strop PŘEPISUJE JS (fitDisclaimer v config.js) — viz níž. */
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Disclaimer = dvě věty; každá je vlastní <span class="dsc-s"> (config.js). Na desktopu tečou
   za sebou (mezeru dodá ::before), na telefonu z nich CSS udělá samostatné řádky — viz @media níž. */
.dsc-s { display: inline; }
.dsc-s + .dsc-s::before { content: " "; }

/* ---- TELEFON (úzká obrazovka): vše ~50 % menší / kompaktnější ---- */
@media (max-width: 600px) {
  /* TELEFON — NIKDY VÍC NEŽ 2 ŘÁDKY (Sebastian, opakovaně: „musí být jenom na 2 řádcích").
     Řeší se MĚŘENÍM, ne zkracováním textu: fitDisclaimer() v config.js po vysázení změří počet
     řádků a zmenšuje písmo přes --dsc-fs, dokud se text nevejde na 2 řádky (dolní mez 11 px,
     a 8 px na liště s AI štítkem — ten si ukrojí až 19 % šířky; zdůvodnění a naměřené
     hodnoty jsou u DSC_MIN_FONT_PX v config.js). Když ani na mezi 2 řádky nestačí, JS strop UVOLNÍ
     (text se NEUŘÍZNE — je to právní věta) a napíše do konzole varování s naměřenými hodnotami.
     Strop 2 řádky nastavuje AŽ JS, a jedině když si ověřil, že se text opravdu vejde — v CSS
     zůstává 3 jako dosud, aby se při nedostupném JS lišta chovala přesně jako dřív (a neuřízla
     víc než dnes). clamp() níž je jen VÝCHOZÍ velikost, od které se měří dolů.
     Padding se škáluje s šířkou displeje: na ≥ 375 px má stejné hodnoty jako dřív (11/6/10 px),
     na užších telefonech se stahuje a uvolňuje tak pár px navíc pro text. */
  #disclaimer { font-size: var(--dsc-fs, clamp(12px, 3.9vw, 15px));
    padding: clamp(8px, 2.94vw, 11px) clamp(4px, 1.6vw, 6px) calc(clamp(7px, 2.67vw, 10px) + env(safe-area-inset-bottom));
    line-height: 1.35; letter-spacing: .05em; -webkit-line-clamp: 3; }
  .dsc-s { display: block; }                    /* věta na svém řádku (rozhodnutí 2026-08-25 obnoveno) */
  .dsc-s + .dsc-s::before { content: none; }
  /* ZÁCHRANNÁ SAZBA (nasazuje ji fitDisclaimer(), když sazba věta-na-řádek 2 řádky v čitelném
     stupni neuhraje — typicky když je jedna věta výrazně delší než druhá, např. v němčině):
     věty tečou za sebou jako na desktopu, text se mezi 2 řádky rozdělí rovnoměrněji a vejde se
     větším písmem. Sám od sebe se tenhle režim nikdy nezapne — jen když by jinak přibyl řádek. */
  #disclaimer.dsc-flow .dsc-s { display: inline; }
  #disclaimer.dsc-flow .dsc-s + .dsc-s::before { content: " "; }
  #debug { font-size: 10px; max-width: 62vw; line-height: 1.35; }
  /* bublina = široký pruh přes celou šířku (delší řádky, ne 3 slova na řádek) */
  #speech-bubble { font-size: 15px; padding: 9px 16px; top: 4%; width: 94vw; max-width: 94vw; border-radius: 16px; }
  /* tlačítka voleb POD SEBOU. Sloupec je fit-content (šířka podle NEJDELŠÍHO labelu) a všechna
     tlačítka jsou stejně široká (width:100 %) — tedy NE přes celou obrazovku, ale ~55–65 %
     (min-width 58vw drží i krátké nabídky pohromadě, max-width 86vw je strop). */
  #choices { width: max-content; max-width: 86vw; min-width: 58vw; gap: 10px; }
  #choices-row { flex-direction: column; flex-wrap: nowrap; gap: 10px; align-items: stretch; }
  #choices button { flex: 0 0 auto; width: 100%; font-size: 18px; padding: 14px 26px;
    white-space: normal; text-overflow: clip; }
  #choices-title { font-size: 17px; padding: 8px 18px; }
  /* VÝKON: na telefonu je sloupec tlačítek větší plocha než pár pilulek na desktopu a GPU slabší
     → menší blur a o něco plnější barva (čitelnost zůstává, snímkování netrpí). */
  @supports (((backdrop-filter: blur(6px)) or (-webkit-backdrop-filter: blur(6px)))
             and (background: color-mix(in srgb, red 50%, transparent))) {
    #choices button {
      background: color-mix(in srgb, var(--choice-bg, var(--accent)) 70%, transparent);
      backdrop-filter: blur(6px) saturate(1.3);
      -webkit-backdrop-filter: blur(6px) saturate(1.3);
    }
  }
  #talk-hand { display: none !important; }   /* ruka „tap me" jen v kiosku, ne na telefonu */
}

/* ---- Fonty síně slávy — JEN tenant hokej-avatar ------------------------------------------------
   Druk Text (stejné řezy jako web hokejové síně slávy, F:/Vibe-apps/hokej-sin-slavy). Font se stahuje
   u KAŽDÉHO tenanta až ve chvíli, kdy ho nějaké pravidlo použije — a to je jen pod [data-tenant].
   Medium je zapsané jako weight 400, aby ho běžný text bublin dostal bez syntetického ztučnění. */
@font-face {
  font-family: "Druk Text";
  src: url("../assets/fonts/hokej/DrukText-Medium.otf") format("opentype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Druk Text";
  src: url("../assets/fonts/hokej/DrukText-Bold.otf") format("opentype");
  font-weight: 700; font-style: normal; font-display: swap;
}
/* Druk Cond Super = titulkový řez ze síně slávy — nadpisová/„tlačítková" typografie klienta.
   Je KONDENZOVANÝ a používá se VÝHRADNĚ verzálkami (text-transform: uppercase u konkrétních
   pravidel), proto má i větší stupeň písma než okolní Druk Text. */
@font-face {
  font-family: "Druk Cond Super";
  src: url("../assets/fonts/hokej/Druk-CondSuper.otf") format("opentype");
  font-weight: 400 900; font-style: normal; font-display: swap;
}
/* bubliny titulků (avatar i uživatel — jeden element, uživatel má .user), nadpis nabídky
   a spodní disclaimer */
[data-tenant="hokej-avatar"] #speech-bubble,
[data-tenant="hokej-avatar"] #speech-bubble.user,
[data-tenant="hokej-avatar"] #choices-title,
[data-tenant="hokej-avatar"] #disclaimer {
  font-family: "Druk Text", Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}
/* Barva nabídky u hokeje = brandová NAVY (Sebastian 2026-08-26). Červená #DC2300 (--accent)
   zůstává VÝHRADNĚ bublině s přepisem uživatele; všechno, co mluví za avatara — jeho bublina
   i tlačítka nabídky — je #001D60.
   ZDE UŽ NENÍ NIC K NASTAVOVÁNÍ (2026-08-28): pravidlo se přesunulo do :root jako
   --choice-bg: var(--bubble-bg) a --bubble-bg plní config.js z bubbles.avatarBg, což je
   u hokeje právě #001D60. Blok s hodnotou natvrdo by teď jen bránil přebarvení z dashboardu,
   proto je pryč — vzhled se nemění (ověřeno měřením, viz předávka). */
/* Modrá interakčního tlačítka u hokeje = brandová NAVY síně slávy #001D60 místo UE #1C54D6
   (Sebastian 2026-08-26). Koule je bílá PNG maska obarvená CSS proměnnou, takže se přepisuje jen
   barva — žádný hue-rotate (ten by rozhodil prstenec i ikonu) a žádná přebarvená kopie assetu.
   ZDE UŽ NENÍ NIC K NASTAVOVÁNÍ (2026-08-28): --talk-idle-color se v obecném pravidle bere
   z --bubble-bg (= bubbles.avatarBg), což je u hokeje právě #001D60 → stejný výsledek, ale
   přebarvitelný z dashboardu. Zelená poslechu a červená mute zůstávají natvrdo: jsou to
   univerzální stavové signály, ne branding. */
/* Ruka touch-hint u hokeje míří na STŘED tlačítka, na ikonku mikrofonu (Sebastian 2026-08-26:
   „ukazuje na okraj koule, má ukazovat na střed"). Stejné vzorce jako v obecném pravidle výš,
   jen cíl špičky = (50 %, 50 %) místo bodu na hraně koule:
     left   = 50 % − 70 % × 92 %             = −14,4 %
     bottom = 100 % − 50 % − 70 % × 93,5 %   = −15,5 %
   Ostatní tenanti (Škoda/xlab) si drží původní polohu u hrany koule — pravidlo se jich netýká. */
[data-tenant="hokej-avatar"] #talk-hand { left: -14.4%; bottom: -15.5%; }
/* Nabídka u hokeje: NORMÁLNÍ PÍSMENA v Druk Text — stejná typografie jako kvízová karta,
   která se Sebastianovi líbí (2026-08-26, 4. kolo: verzálky Cond Super byly špatně čitelné
   a s velkým prostrkáním se ztrácely mezery mezi slovy).
   Sklo-pilulky (tvar, barva, blur) se NEMĚNÍ. Ostatní tenanti pravidlo nemají → beze změny. */
[data-tenant="hokej-avatar"] #choices button,
[data-tenant="hokej-avatar"] #choices-title {
  font-family: "Druk Text", Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-weight: 600; font-size: 23px; letter-spacing: .01em;
}
[data-tenant="hokej-avatar"] #choices-title { font-size: 30px; font-weight: 700; }   /* nadpis o stupeň nad volbami (desktop větší — Sebastian) */
@media (max-width: 600px) {
  [data-tenant="hokej-avatar"] #choices button { font-size: 19px; }
  [data-tenant="hokej-avatar"] #choices-title { font-size: 21px; }
}
/* START TLAČÍTKO („Stiskem začněte") u hokeje: stejné sklo jako pilulky nabídky + Druk Cond Super
   verzálkami, KAŽDÉ SLOVO NA SVÉM ŘÁDKU (slova zabaluje do <span> main.js → tady jen display:block).
   Funkce tlačítka se nemění, jen vzhled. Ostatní tenanti si drží plnou barvu bublin. */
[data-tenant="hokej-avatar"] #start-btn {
  font-family: "Druk Cond Super", "Druk Text", Inter, system-ui, sans-serif;
  text-transform: uppercase; font-weight: 400; letter-spacing: .07em; line-height: 1.05;
  /* text má VYPLNIT kulaté tlačítko (Sebastian 2026-08-26: „příliš malý") */
  font-size: clamp(30px, 9vw, 46px);
  color: #fff;
  background: #001D60;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.30), 0 10px 44px rgba(0,0,0,.5);
}
/* #start-btn je flex (centrování textu) → slova jsou flex-items. „Slovo na řádek" se proto
   nedělá přes display:block (ten se u flex-item ignoruje), ale otočením osy na sloupec. */
[data-tenant="hokej-avatar"] #start-btn { flex-direction: column; }
/* Zdvih talk tlačítka nad disclaimer na telefonu řeší profil (talkPhoneBottom v avatar-profile.js)
   — pozici nastavuje inline styl v applyTalkLayout(), CSS pravidlo by nemělo účinek. */

/* ---- „VLNA" — interakční tlačítko z lišty (Sebastian 2026-08-26; JEN telefon + profil
   talkStyle:"vlna"). Vlna vyrůstá z horní hrany disclaimeru (jedna hmota), stavy mění jen
   barvu vlny (listening/speaking mají dole jemný gradient zpět do navy), ikona na dotek
   pruží. body.talkwave zapíná vlnu a schovává klasické kulaté tlačítko. ------------------- */
#talk-wave { display: none; }
body.talkwave #talk-btn { display: none; }
body.talkwave #talk-wrap {
  /* wrap se roztáhne na celou šířku a přisedne na disclaimer (bottom nastavuje JS měřením) */
  width: 100vw; pointer-events: none;
}
body.talkwave #talk-wave {
  display: block; width: 100%; pointer-events: none;
  /* ŽÁDNÝ tap-highlight (Sebastian 2026-08-27: „světle modrý poloprůhledný obdélník kolem
     tlačítka" = Chrome tap-highlight na dotyk) ani výběr textu */
  -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none;
}
body.talkwave #talk-wave * { -webkit-tap-highlight-color: transparent; outline: none; }

/* ── BOČNÍ VLNKA (tablet/PC — zadání Sebastiana 27. 8.): svisle u pravého okraje, tvar „C"
   (hlubší a kratší = větší plocha pro prst). Stejné stavy/ikony jako spodní vlna; gradienty
   vodorovně (hřbet → okraj). Pozici (top/right) nastavuje applyTalkLayout inline. ─────────── */
body.talkwave #talk-wave.side svg { width: 92px; height: 340px; }   /* pevná velikost — MUSÍ přebít width:100% z telefonní větve (vyšší specificita) */
#talk-wrap[data-state="listening"] #talk-wave.side .tw-shape { fill: url(#tw-gs-listening); }
#talk-wrap[data-state="speaking"]  #talk-wave.side .tw-shape { fill: url(#tw-gs-speaking); }
#talk-wave.side .tw-bar {
  height: calc(14px + 22px * min(var(--lvl, 0), 1));
  y: calc(170px - (14px + 22px * min(var(--lvl, 0), 1)) / 2);
}
#talk-wave.side .tw-bar-mid {
  height: calc(14px + 30px * min(var(--lvl-mid, 0), 1));
  y: calc(170px - (14px + 30px * min(var(--lvl-mid, 0), 1)) / 2);
}
#talk-wave.side .tw-zoomeq { transform-origin: 48px 170px; }
/* ruka „tap me" mířila na kulaté tlačítko — u boční vlnky by ukazovala vedle → schovat
   (vlastní hint pro vlnku = případný samostatný úkol) */
body.talkwave #talk-hand { display: none !important; }
body.talkwave #talk-wave svg { display: block; width: 100%; height: auto; overflow: visible; }   /* ikona se při pružení nesmí oříznout */
#talk-wave .tw-shape, #talk-wave .tw-icon, #talk-wave .tw-eq { pointer-events: auto; cursor: pointer; }
/* Základní (klidová) barva vlny a dolní konec stavových gradientů = barva lišty disclaimeru.
   Hodnotu dává NASTAVENÍ (2026-08-28): --disclaimer-bg, kterou config.js plní z disclaimer.bg
   (a když chybí, z bubbles.avatarBg). Do 28. 8. tu byl default #001D60 natvrdo a Škoda si ho ve
   svém bloku přepisovala na #0E3A2F — obojí byly přesně ty hodnoty, které stojí v dashboardu,
   takže se vzhled nemění, jen se barva přestala psát do kódu. --tw-base zůstává jako ruční
   přepínač před nastavením. Pravidlo přebíjí atribut fill/stop-color v SVG (prezentační atribut
   má nejnižší prioritu), stavová pravidla s url(#tw-g-…) mají vyšší specificitu, takže je
   tohle neovlivní. */
#talk-wave .tw-shape { fill: var(--tw-base, var(--disclaimer-bg, #001D60)); transition: fill .25s ease; }
#talk-wave .tw-stop-base { stop-color: var(--tw-base, var(--disclaimer-bg, #001D60)); }
#talk-wrap[data-state="listening"] #talk-wave .tw-shape { fill: url(#tw-g-listening); }
#talk-wrap[data-state="speaking"]  #talk-wave .tw-shape { fill: url(#tw-g-speaking); }
#talk-wave .tw-i-idle, #talk-wave .tw-i-speaking, #talk-wave .tw-eq { display: none; fill: #fff; }
#talk-wrap[data-state="idle"]      #talk-wave .tw-i-idle    { display: block; }
#talk-wrap[data-state="listening"] #talk-wave .tw-eq       { display: block; }
#talk-wrap[data-state="speaking"]  #talk-wave .tw-i-speaking { display: block; }
/* EQ sloupce reagují na hlas přes --lvl/--lvl-mid (stejný zdroj jako dosavadní tečky);
   y/height jsou SVG geometrie stylovatelná CSS (Chrome/Safari/Firefox aktuální). */
#talk-wave .tw-bar {
  height: calc(14px + 22px * min(var(--lvl, 0), 1));
  y: calc(42px - (14px + 22px * min(var(--lvl, 0), 1)) / 2);
}
#talk-wave .tw-bar-mid {
  height: calc(14px + 30px * min(var(--lvl-mid, 0), 1));
  y: calc(42px - (14px + 30px * min(var(--lvl-mid, 0), 1)) / 2);
}
/* dotek: ikona se zvětší a vrátí */
#talk-wave .tw-zoom   { transition: transform .14s ease; transform-origin: 12px 12px; }
#talk-wave .tw-zoomeq { transition: transform .14s ease; transform-origin: 195px 42px; }
#talk-wave.tw-press .tw-zoom   { transform: scale(1.18); }
#talk-wave.tw-press .tw-zoomeq { transform: scale(1.18); }
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  [data-tenant="hokej-avatar"] #start-btn { background: color-mix(in srgb, #001D60 88%, transparent); }
}
@supports (((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)))
           and (background: color-mix(in srgb, red 50%, transparent))) {
  [data-tenant="hokej-avatar"] #start-btn {
    background: color-mix(in srgb, #001D60 62%, transparent);
    backdrop-filter: blur(10px) saturate(1.4);
    -webkit-backdrop-filter: blur(10px) saturate(1.4);
  }
}

/* ---- BUDDY — JEN tenant skoda-avatar (Sebastian 2026-08-27) ------------------------------------
   Zadání: „stejný jazyk ovládacích prvků jako Puk, ale ve škodovských barvách". Mění se VÝHRADNĚ
   barva — font (systémový) i stupně písma zůstávají škodovské, Druk patří síni slávy.
   Ostatní tenanti (xlab-avatar, hokej-avatar) tahle pravidla nemají → beze změny.

   NABÍDKA: sklo-pilulky jsou obecné (#choices button výš) a barvu berou z --choice-bg. Škodě se
   --accent plní z configu hodnotou bubbles.userBg = #78FAAE (světle mintová), na které bílý text
   plaval. Tlačítka nabídky ale „mluví za avatara", takže berou TMAVĚ ZELENOU z bubbles.avatarBg
   (#0E3A2F) — tutéž, co má bublina avatara i lišta disclaimeru. Mintový akcent zůstává tam, kde
   ho config používá dnes: bublina uživatele, klávesnice, tlačítko „Otevřít stránku", spodek pozadí.
   ZDE UŽ NENÍ NIC K NASTAVOVÁNÍ (2026-08-28): hodnota stála natvrdo jako #0E3A2F a při změně
   barvy v dashboardu se nehnula. Vazba --choice-bg: var(--bubble-bg) je teď v :root pro všechny
   tenanty, takže tenhle blok jen bránil přebarvení. Vzhled Škody se nemění (ověřeno měřením). */

/* ---- SKLO TLAČÍTEK NABÍDKY: návrh 4 „LOM SVĚTLA" — JEN tenant skoda-avatar -------------------
   Sebastian 2026-08-28: „tlačítka hlavního menu nejsou vyloženě jako skleněná" → šest návrhů
   v Nahledy_UI/sklo_nabidka_varianty, vybral návrh 4. Katalog všech šesti i s naměřenými čísly
   zůstává v NAVRHY.md (dá se z něj čerpat pro další avatary).

   (1) PODMÍNKA, BEZ KTERÉ NENÍ VIDĚT ŽÁDNÉ SKLO — fill-mode nabídky
   ------------------------------------------------------------------------------------------------
   Základní pravidlo #choices má `animation: choicesIn .55s ease both`. Dopředná výplň drží
   #choices i po doběhnutí trvale ve fázi výplně animace opacity, takže ho Blink nechává ve
   vlastní kompoziční vrstvě — a ta se tlačítkům pod ní stane „backdrop rootem". Pod sklem pak
   není 3D scéna, ale prázdno, a backdrop-filter NEDĚLÁ VŮBEC NIC.
   Změřeno (_overeni_backdrop.mjs, tlačítko bez vlastního pozadí, měřen týž bod):
       fill-mode both:       brightness(0.15) → rgb 67,97,82   brightness(3) → rgb 67,97,82   (Δ 0)
       fill-mode backwards:  brightness(0.15) → rgb 10,15,12   brightness(3) → rgb 144,176,172 (Δ 134)
   `backwards` drží počáteční stav PŘED startem (fade-in tedy vypadá stejně — ověřeno po fázích,
   pixel po pixelu, viz _regrese_animace.json), ale po doběhnutí výplň pouští a s ní i tu vrstvu.

   PROČ JEN PRO TENANTA, a ne rovnou v základním pravidle: oprava v #choices by sklo zapnula
   i Pukovi a xlab-avatarovi, kterým dodneška taky nefunguje. Změřeno na čerstvých načteních
   (_regrese_tenant.mjs, výřez nabídky, práh 2 úrovně na kanál; šum dvou totožných načtení
   je 1,0–3,3 % pixelů):
       globální oprava:   hokej 43,98 % pixelů jinak, xlab 48,67 %  → viditelná změna, ne nula
       oprava jen Škody:  hokej  3,60 % pixelů jinak, xlab  2,15 %  → v pásmu šumu, sonda dál Δ 0
   Puk sklo dostane taky, ale s vlastními, na jeho světlé scéně přeměřenými hodnotami — postup
   má jeho session popsaný v sklo_nabidka_varianty/PRO_PUKA.md. Do té doby se mu nemá pod rukama
   zapnout nezměřený blur(10px) z obecného pravidla.

   :not(.leaving) NENÍ kosmetika: #choices.leaving (odchod nabídky) má stejnou specificitu jako
   [data-tenant] #choices a stojí v souboru výš, takže by mu tenantová hodnota přebila fill-mode
   a nabídka by po doběhnutí odchodové animace skočila zpátky na opacity 1 — přesně to „blikání",
   které se opravovalo. Takhle platí backwards jen v klidovém stavu a odchod si dál drží both.

   (2) VZHLED — návrh 4 „lom světla"
   ------------------------------------------------------------------------------------------------
   Jediná varianta se ZÁMĚRNĚ MALÝM rozptylem (blur 8): pod sklem má být pořád poznat, co tam je,
   jen to má vypadat jinak. Práci dělá optika — sytost 2,8, kontrast 0,5, jas 0,78. Hrana je
   nejsilnější ze všech návrhů (1,5 px), protože u čirého skla drží tvar jedině obvod.

   POŘADÍ FUNKCÍ VE FILTRU NENÍ JEDNO: contrast() přitahuje každý kanál zvlášť ke střední hodnotě,
   takže kromě kontrastu ubere i barvu a scéna pod sklem zešedne. Sytost proto patří až ZA něj —
   blur() → contrast() → brightness() → saturate(). (První měřicí kolo mělo saturate() na začátku
   a všechny varianty vyšly šedivé.)

   PROČ contrast() POD 1: tlačítka neleží nad prázdnem, ale nad avatarem — svítivost scény pod
   nimi jde od L ≈ 0,017 (stín) po L ≈ 0,55 (mintové hrany paží, bílá hlava, logo na hrudi).
   Aby bylo sklo vidět nad tmavým místem, musí být světlejší; aby na něm zůstal čitelný bílý text
   nad světlým místem, musí být tmavší. Obojí najednou splní jedině snížení kontrastu pozadí.
   Fyzikálně je to i správně — matné sklo světlo rozptyluje, tedy kontrast toho za ním snižuje.

   VÝKON: blur se počítá VÝHRADNĚ nad plochou tří pilulek, nikdy přes celé okno nad WebGL plátnem
   (pravidlo projektu). Návrh 4 má nejnižší poloměr ze všech šesti návrhů a poloměr je hlavní cena;
   změřeno v _vykon_skla.json.

   FALLBACK: prohlížeč bez backdrop-filter (nebo bez color-mix) dostane PLNOU barvu nabídky.
   Do 28. 8. tu stála rgba(14, 58, 47, .92), tedy #0E3A2F natvrdo — právě proto, že se v téhle
   větvi nesmí použít color-mix(), a jinak alfa nešla zapsat. Řeší se to obráceně: fallback je
   živá --choice-bg BEZ alfy (o těch 8 % průhlednosti přijdou jen prohlížeče bez color-mix,
   kde se stejně nekreslí žádné sklo), a průhlednost dodá až color-mix ve větvi pod tím. ------ */
[data-tenant="skoda-avatar"] #choices:not(.leaving) { animation-fill-mode: backwards; }
[data-tenant="skoda-avatar"] #choices button {
  background: var(--choice-bg, #0E3A2F);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .30), 0 6px 20px rgba(0, 0, 0, .25);
  text-shadow: 0 1px 3px rgba(0, 0, 0, .55);
}
@supports (((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)))
           and (background: color-mix(in srgb, red 50%, transparent))) {
  [data-tenant="skoda-avatar"] #choices button {
    background: color-mix(in srgb, var(--choice-bg, #0E3A2F) 18%, transparent);
    backdrop-filter: blur(8px) contrast(.5) brightness(.78) saturate(2.8);
    -webkit-backdrop-filter: blur(8px) contrast(.5) brightness(.78) saturate(2.8);
    box-shadow:
      inset 0 0 0 1.5px rgba(255, 255, 255, .48),   /* hrana = jediné, co u čirého skla drží tvar */
      0 8px 24px rgba(0, 0, 0, .34);
    text-shadow: 0 1px 2px rgba(0, 0, 0, .9), 0 2px 12px rgba(0, 0, 0, .7);
  }
}
/* NADPIS NABÍDKY („Co tě zajímá nejvíc?") byl na DESKTOPU menší než tlačítka pod ním — 20px
   proti 22px (Sebastian 2026-08-27: „v desktop verzi s novýma tlačítkama tam ten nadpis co tě
   zajímá musí být větší"). Nejdřív se zvedl na 29px (poměr hokeje 30/23 ≈ 1,3), Sebastianovi
   to pořád bylo málo („nadpis co tě zajímá nejvíc bych udělal možná trošku větší") → o stupeň
   výš na 34px, tedy 1,55× tlačítka.
   STROP: nadpis se musí vejít na JEDEN řádek i v nejužším desktopovém okně (601px, kde je blok
   nabídky široký 94vw = 565px). „Co tě zajímá nejvíc?" má při 34px 348px — rezerva 217px, tedy
   ~12 znaků navíc. Delší nadpis od mozku by se zalomil na dva řádky (text-wrap: balance je na
   to připravený), proto se výš už nejde.
   Telefon se nemění: tam nadpis řeší obecné pravidlo v @media (max-width: 600px), které má
   nižší specificitu než tohle tenantové → musí se přepsat zpět (stejný vzorec jako u hokeje). */
[data-tenant="skoda-avatar"] #choices-title { font-size: 34px; }
@media (max-width: 600px) {
  [data-tenant="skoda-avatar"] #choices-title { font-size: 17px; }
}
/* OSAMOCENÁ POSLEDNÍ POLOŽKA v sudé mřížce (Sebastian 2026-08-27: „když máš teda 3 tlačítka
   a to druhé je na druhém řádku, tak ať je vystředěné, ať to má nějakej hezkej tvar, takhle je
   to takový divný"). Desktopová mřížka má 2 sloupce, takže při LICHÉM počtu voleb zbyde poslední
   tlačítko samo na posledním řádku a auto-umístění ho zarazí doleva — pod levé tlačítko, ne pod
   střed nabídky.
   Řešení není „třetí tlačítko", ale obecně poslední lichá položka (:last-child:nth-child(odd)),
   takže sedí na 1, 3 i 5 voleb; při 2 a 4 se nespustí (poslední položka je sudá, řádek je plný).
   Tlačítko se roztáhne přes oba sloupce, vystředí se a šířku dostane přesně jednoho sloupce:
   sloupce mřížky jsou vždy stejně široké (max obou je pevných 340px, případně shodně seříznutý
   strop 94vw), takže (100 % − mezera) / 2 = jeden sloupec na pixel přesně.
   JEN Škoda: hokej má 4 volby (mřížka vychází beze zbytku) a schválený vzhled Puka ani
   xlab-avatara se nemá hnout, tak se jim pravidlo nepodsouvá. */
@media (min-width: 601px) {
  [data-tenant="skoda-avatar"] #choices-row > button:last-child:nth-child(odd) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - var(--choice-grid-gap, 16px) / 2);
  }
}
/* ---- Firemní font Škody — JEN tenant skoda-avatar ----------------------------------------------
   SKODA Next (řezy z kioskového balíku F:/AI Avatars/Skoda/01_UE_Kiosek/Laurin_UI_Assety/fonty,
   zkopírované do public/assets/fonts/skoda/). Stejný princip jako Druk u hokeje: soubor si
   prohlížeč stáhne teprve ve chvíli, kdy ho použije některé pravidlo pod [data-tenant="skoda-avatar"]
   → ostatním tenantům nepřibude ani bajt. Fallback je systémový font (system-ui) — když se TTF
   nenačte, text se jen vysází systémovým řezem, rozvržení drží dál. */
@font-face {
  font-family: "SKODA Next";
  src: url("../assets/fonts/skoda/SKODANext-Regular_UI.ttf") format("truetype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "SKODA Next";
  src: url("../assets/fonts/skoda/SKODANext-Bold_UI.ttf") format("truetype");
  font-weight: 700; font-style: normal; font-display: swap;
}
/* START TLAČÍTKO („Stiskem začněte") u Buddyho — připomínky Sebastiana 2026-08-27:
   „na počítači je moc malé, má být dvakrát větší", „text se slévá do jednoho slova, má být
   STISKEM / ZAČNĚTE pod sebou", „velkými kapitálkami", „škodovským fontem", „skleněný design",
   „ať se na něm občas objeví ta ručička".
   Základní vzhled tlačítka je v <style> uvnitř index.html (kruh, pulz, barva z configu); tohle
   pravidlo má vyšší specificitu ([data-tenant] + #id), takže ho přebije bez !important.
   DVA ŘÁDKY: #start-btn je flex, jednotlivá slova zabaluje main.js do <span> → jsou to
   flex-items. display:block by se u nich ignoroval, proto se otáčí osa na sloupec (stejné
   řešení jako u hokeje). Zároveň to je oprava toho „Stiskemzačněte": vodicí mezera uvnitř
   flex-itemu se při sazbě ořízne, takže se slova v řádku slepila dohromady. */
[data-tenant="skoda-avatar"] #start-btn {
  flex-direction: column;
  position: relative;                 /* kotva pro ruku „tap me" (::after níž) */
  font-family: "SKODA Next", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  text-transform: uppercase; font-weight: 700; letter-spacing: .06em; line-height: 1.1;
  color: #fff;
  /* VELIKOST TLAČÍTKA A PÍSMA = JEDNA HODNOTA (Sebastian 2026-08-28: „Proč je to na tom telefonu
     tak hrozně malý ten text ‚Stiskem začněte'? Vždyť by měl být poměrově stejně velký vůči tomu
     tlačítku, jako je při zobrazení na počítači.")
     Měl pravdu a nebyla to náhoda: kruh a písmo byly do té doby DVĚ NEZÁVISLÉ hodnoty
     (width: min(46vw,336px) proti font-size: min(6.1vw,44px) plus telefonní clamp v index.html).
     Každá se stropovala při jiné šířce okna, takže se poměr nutně rozešel — naměřeno
     desktop 44/336 = 13,1 %, telefon 14,04/168 = 8,4 %, tedy skoro o třetinu menší nápis.
     Media query proto od teď mění JEDINOU věc: --start-size. Písmo z ní vychází násobkem, takže
     poměr platí sám od sebe na jakémkoli displeji a doladit se nedá rozbít.
     Referencí je schválený desktop: 44 px na kruhu 336 px → 0.131. */
  --start-size: min(46vw, 168px);     /* telefon; desktopový strop přepisuje @media níž */
  --start-font-ratio: .131;
  width: var(--start-size); height: var(--start-size);
  font-size: calc(var(--start-size) * var(--start-font-ratio));
  /* BARVA SKLA JE ŽIVÁ Z NASTAVENÍ (Sebastian 2026-08-28: „Doufám, že to je teda živá ta barva
     a že když změním prostě v nastavení barvu, tak se mi to projeví do tý barvy toho skla.")
     Do 28. 8. živá NEBYLA — tenhle blok měl barvu natvrdo jako #0E3A2F a #25644B. Zajímavé je,
     že základní pravidlo v index.html živé bylo (background: var(--bubble-bg,#fff)); rozbily to
     až ty moje literály, které ho přebily.
     ZDROJ: --bubble-bg, kterou config.js plní z bubbles.avatarBg (config.js: r.setProperty(
     "--bubble-bg", cfg.bubbles.avatarBg)). Je to správný zdroj i významem — startovací tlačítko
     „mluví za avatara" stejně jako bublina avatara a tlačítka nabídky; táž úvaha je popsaná
     v tenant sekci výš u --choice-bg. A sedí i číselně: bubbles.avatarBg je dnes u Škody
     #0E3A2F a u hokeje #001D60, tedy přesně ty hodnoty, které tu do teď stály natvrdo.
     --accent (bubbles.userBg) se používá jen jako příměs pro zesvětlení, viz --start-glass níž.
     Fallbacky v var() jsou pojistka pro případ, že by config proměnné nedodal. */
  background: var(--bubble-bg, #0E3A2F);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.30), 0 10px 44px rgba(0,0,0,.5);
}
@supports (background: color-mix(in srgb, red 50%, transparent)) {
  [data-tenant="skoda-avatar"] #start-btn { background: color-mix(in srgb, var(--bubble-bg, #0E3A2F) 88%, transparent); }
}
/* SKUTEČNÉ SKLO (Sebastian 2026-08-28, po srovnání variant A/B/C — vybral C):
   „Přijde mi, že to tlačítko není zase skleněné, nemá to ten průhledný skleněný design, je to
   neprůhledné."  Měl pravdu a důvod nebyl v krytí: 62 % je sice průhledných, jenže tmavě zelená
   #0E3A2F ležela na tmavé scéně — obě strany měly skoro stejný jas, takže pod tlačítkem nebylo
   nic vidět a četlo se to jako plná plocha.
   Samotné snížení krytí by problém jen otočilo: tmavá díra v tmavé scéně. Sklo se pozná podle
   toho, že je SVĚTLEJŠÍ NEŽ OKOLÍ a má vlastní hranu. Proto čtyři věci najednou:
     1) krytí dolů na 32 % (z 62 %) → skrz je vidět avatar,
     2) brightness(1.4) v backdrop-filtru → to, co je za sklem, se prosvětlí nad okolní scénu;
        tohle je ta vlastnost, která odliší sklo od díry, ne průhlednost sama,
        blur 18 px (z 10) + saturate 1,7 → rozostření za sklem, barvy scény zůstanou živé,
     3) SVĚTLEJŠÍ ODSTÍN TÓNU (--start-glass). Nastavená barva bývá skoro černá zeleň; při 32 %
        krytí ji přes prosvětlené pozadí není poznat a sklo zešedne domodra. Tón se proto bere
        ze světlejšího místa TÉŽE palety: 78 % barvy avatara + 22 % akcentu. U Škody z toho
        vyjde #25644B (78 % #0E3A2F + 22 % #78FAAE) — přesně ta konstanta, která tu stála do
        28. 8., než se barva navázala na nastavení; teď se dopočítá pro jakoukoli barvu.
        (Při 62 % by tenhle odstín byl na tlačítko moc světlý — dává smysl jedině se sníženým
        krytím, obě čísla patří k sobě.)
        Poměr 78/22 se schválně nepočítá znovu pro každou barvu: je to receptura „posuň tón
        o krok ke světlejší barvě palety", ne dolaďování na konkrétní zeleň.
     4) hrana a přesvětlení: světlý vnitřní lem 1,5 px, vnitřní horní záře (sklo chytá světlo
        shora) a spodní vnitřní protistín, aby kruh měl objem; navrch lineární gradient
        v background-image jako odlesk na horní třetině.
   HORNÍ BÍLÝ ODLESK JE ZTLUMENÝ (Sebastian 2026-08-28: „Možná bych tam trošku jenom snížil ten
   odlesk, který je nahoře, ten bílý." — ze tří proměřených měr vybral nejsilnější ztlumení).
   Odlesk dělají DVĚ vrstvy a ztlumit se musely obě naráz, jinak se světlo jen přesune:
     (a) gradient v background-image  .20 → .07 nahoře a .06 → .02 ve 34 % výšky
     (b) horní záře v box-shadow      .75 → .26
   Naměřeno (odlesk_a_barvy.mjs — přírůstek svítivosti horního pásu kotouče, 5–22 % výšky, proti
   téže ploše na holé scéně): 0,0467 → 0,0080, tedy 17 % původní síly. Kontrast nápisu se tím
   nezhoršil, naopak: 11,66 → 12,78:1.
   CO SE ZTLUMIT NESMÍ: lem 1,5 px po obvodu. Ten není odlesk, ale HRANA skla — je to vlastnost,
   podle které se kotouč čte jako hmota, ne jako díra (změřeno při výběru varianty C). Stejně tak
   se nesahá na spodní protistín ani na vržený stín, jsou to jiné vrstvy.
   Původní hodnoty i mezistupeň zůstávají k dispozici v Nahledy_UI/start_tlacitko_varianty/
   varianta_odlesk.css (?odlesk=… na náhledovém serveru), kdyby se to chtělo znovu doladit.
   TEXT: bílé písmo na prosvětleném skle ztrácelo, dostává proto stín (těsný pro hranu písmen
   + široký měkký pro odsazení od pozadí). Barva písma zůstává #fff.
   Vše je uvnitř @supports na backdrop-filter — prohlížeč, který ho neumí, by z 32 % krytí udělal
   opravdovou díru bez rozostření; tam zůstává neprůhledná podoba z pravidel výš. */
@supports (((backdrop-filter: blur(10px)) or (-webkit-backdrop-filter: blur(10px)))
           and (background: color-mix(in srgb, red 50%, transparent))) {
  [data-tenant="skoda-avatar"] #start-btn {
    /* Mezikrok ve vlastní proměnné, ať se do background-color nemusí psát color-mix v color-mix
       na jeden řádek. Vlastní proměnné se dosazují textově, takže výsledek je stejný, jen
       čitelnější — a poměr 78/22 je na jednom místě. */
    --start-glass: color-mix(in srgb, var(--bubble-bg, #0E3A2F) 78%, var(--accent, #78FAAE));
    background-color: color-mix(in srgb, var(--start-glass) 32%, transparent);
    background-image: linear-gradient(180deg, rgba(255,255,255,.07) 0%, rgba(255,255,255,.02) 34%, rgba(255,255,255,0) 62%);
    backdrop-filter: blur(18px) saturate(1.7) brightness(1.4);
    -webkit-backdrop-filter: blur(18px) saturate(1.7) brightness(1.4);
    box-shadow:
      inset 0 0 0 1.5px rgba(255,255,255,.55),          /* světlý lem = hrana skla, NEZTLUMOVAT */
      inset 0 16px 26px -18px rgba(255,255,255,.26),    /* přesvětlení shora (ztlumeno z .75) */
      inset 0 -26px 40px -26px rgba(0,0,0,.45),         /* protistín dole → objem */
      0 10px 44px rgba(0,0,0,.45);                      /* vržený stín pod tlačítkem */
    text-shadow: 0 1px 2px rgba(0,0,0,.85), 0 3px 16px rgba(0,0,0,.65);
  }
}
/* VELIKOST: jen DESKTOP (Sebastian: „na telefonu ho nech, jak je" — telefonní kruh zůstává na
   min(46vw, 168px), tedy přesně jak byl). Na desktopu se strop zdvojnásobuje na 336px; v úzkém
   okně dál vládne 46vw, takže se tlačítko nikdy nerozleze přes obrazovku.
   Písmo se tu ÚMYSLNĚ neuvádí — vychází z --start-size pravidlem výš, takže stačí přepsat
   velikost kruhu a nápis se dopočítá. Dřív tu byla druhá, nezávislá hodnota (min(6.1vw,44px))
   a právě ta rozházela poměr mezi telefonem a počítačem.
   Naměřeno po úpravě: 320px → kruh 147,2 / písmo 19,3; 390px → 168 / 22,0; 601px → 276,5 / 36,2;
   768px a výš → 336 / 44,0. Poměr 13,1 % všude. Nejdelší slovo („ZAČNĚTE") zabere 65,2 % šířky
   kruhu, vnitřní šířka je i na 320px displeji 78 % — vejde se s rezervou.
   PADDING zůstává v pixelech (26 desktop / 16 telefon z index.html) schválně: je to optický
   odstup textu od skleněné hrany, ne nosná veličina. Že se text vejde i s ním, je změřené. */
@media (min-width: 601px) {
  [data-tenant="skoda-avatar"] #start-btn {
    --start-size: min(46vw, 336px);
    padding: 26px;
  }
}
/* RUKA „TAP ME" na startovacím tlačítku. Kresba je stejná jako u interakčního tlačítka
   (#talk-hand = assets/ui/talk/talk_hand.png), ale ta ruka leží uvnitř #talk-wrap, které je
   po dobu start obrazovky schované (body.prestart) → na startu se použít nedá. Dělá se proto
   pseudo-prvkem; JS se nikde nedotýkáme (v main.js souběžně pracuje jiná session).
   GEOMETRIE — stejné vzorce jako u #talk-hand, jen kruhem je TLAČÍTKO SAMO (poloměr 50 % jeho
   šířky, ne 44,1 % jako koule v plátně):
     špička ukazováku v kresbě = (70 %, 30 %) obrázku, ruka je 92 % šířky tlačítka (čtverec)
     tipX = 50 % − 50 % × cos 49°            ≈ 17,2 %  →  left   = 17,2 % − 70 % × 92 % ≈ −47,2 %
     tipY = 50 % + 50 % × sin 49°            ≈ 87,7 %  →  bottom = 12,3 % − 70 % × 92 % ≈ −52,1 %
   Tělo ruky tak zůstává mimo tlačítko (nepřekrývá nápis) a na kruh sahá jen špička prstu.
   „OBČAS": cyklus 9 s — ruka je přes 5 s pryč, pak se ukáže, dvakrát zapulzuje a zmizí.
   DVĚ VRSTVY: ::after je samotná ruka, ::before je tmavé podsvícení pod ní (viz níž). Geometrii
   i animaci mají SPOLEČNOU — kdyby se rozešly, halo by se od ruky odlepilo. */
[data-tenant="skoda-avatar"] #start-btn::before,
[data-tenant="skoda-avatar"] #start-btn::after {
  content: ""; position: absolute; width: 92%; height: 92%; left: -47.2%; bottom: -52.1%;
  transform-origin: 70% 30%;          /* pulz roste od špičky prstu ven, špička drží cíl */
  opacity: 0; pointer-events: none; user-select: none;
  animation: startHand 9s ease-in-out infinite;
}
[data-tenant="skoda-avatar"] #start-btn::after {
  background: url("../assets/ui/talk/talk_hand.png") center / contain no-repeat;
}
@keyframes startHand {
  0%, 60% { opacity: 0; transform: scale(1); }
  66%     { opacity: .95; transform: scale(1); }
  73%     { opacity: 1; transform: scale(1.18); }
  80%     { opacity: .95; transform: scale(1); }
  87%     { opacity: 1; transform: scale(1.18); }
  94%     { opacity: .95; transform: scale(1); }
  100%    { opacity: 0; transform: scale(1); }
}
/* ==== BARVA RUKY = BARVA UŽIVATELOVY BUBLINY (Sebastian 2026-08-28) ==============================
   „Ta ruka vlastně přebírá tu druhou barvu — což je vlastně ta bublina v pozadí uživatele."
   Není to tedy konstanta #78FAAE, ale proměnná --accent, kterou na <html> dosazuje config.js
   PŘÍMO z bubbles.userBg (config.js: r.setProperty("--accent", cfg.bubbles.userBg)). U Buddyho
   z toho vyjde #78FAAE, u Puka ze stejného pravidla červená #DC2300 — proto proměnná, ne hex.
   Touž proměnnou barví ruku i ui-addons.css u hokeje, ať to nemá každý tenant po svém.
   Záložní hodnota v var() je pojistka pro případ, že by config proměnnou nedodal.

   JAK SE RUKA BARVÍ: talk_hand.png je čistě BÍLÁ kresba s alfa kanálem (ověřeno dekódováním —
   všechny neprůhledné pixely mají RGB 250–255 v šedé). Obrázek se proto přesune z background
   do MASKY (kresba = tvar) a background nese barvu. Odstín je tím přesně ten z proměnné; CSS
   filtr (hue-rotate a spol.) by na barevném podkladu čistou barvu nedal a druhý PNG pro každou
   barvu je slepá ulička. Stejným způsobem se v projektu barví i vrstvy interakčního tlačítka.
   POZOR na zkratku `background`, ne `background-color`: pravidlo výš dává ::after bílou kresbu
   jako background-image (záloha pro prohlížeč bez masky) a obrázek se kreslí NAD barvou pozadí —
   samotné background-color by tedy ruku nechalo bílou. Zkratka background-image vynuluje.

   PROČ DVĚ VRSTVY: barevná ruka sama stojí a padá s tím, jak tmavé je pod ní pozadí. Buddyho
   start obrazovka tmavá je, ale pravidlo má fungovat i tam, kde tmavá nebude.
   Vlastní stín ::after udělat nejde — CSS pořadí je nejdřív filter, teprve pak mask, takže by
   maska drop-shadow zase odřízla (vyzkoušeno: kolem masky se neobjeví nic). Halo proto nese
   samostatná spodní vrstva ::before: tentýž obrázek jako BACKGROUND (ne maska), sražený
   brightness(0) na černo a obalený dvěma drop-shadow. Černá kresba je přesně pod barevnou,
   takže není vidět; ven čouhá jenom měkký tmavý okraj. Obě vrstvy sdílejí geometrii i animaci
   (pravidlo výš), takže se při pulzu nemůžou rozejít.
   (U hokeje má ::before v ui-addons.css odlesk skla, takže tam tudy halo nepůjde — viz předávka.)

   Vše je za @supports na mask — prohlížeč bez masky by z background:barva udělal barevný
   čtverec. Tam zůstává původní bílá ruka z pravidla výš a ::before je průhledné prázdno. */
@supports ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  [data-tenant="skoda-avatar"] #start-btn::after {
    background: var(--accent, #78FAAE);
    -webkit-mask: url("../assets/ui/talk/talk_hand.png") center / contain no-repeat;
            mask: url("../assets/ui/talk/talk_hand.png") center / contain no-repeat;
  }
  [data-tenant="skoda-avatar"] #start-btn::before {
    background: url("../assets/ui/talk/talk_hand.png") center / contain no-repeat;
    filter: brightness(0) drop-shadow(0 0 4px rgba(0,0,0,.85)) drop-shadow(0 0 12px rgba(0,0,0,.5));
  }
}
/* VLNA (telefon): tvar vyrůstá z horní hrany disclaimeru a má s ním splývat v jednu hmotu →
   klidová barva vlny i dolní konec stavových gradientů = barva lišty disclaimeru.
   ZDE UŽ NENÍ NIC K NASTAVOVÁNÍ (2026-08-28): hodnota tu stála natvrdo jako #0E3A2F, což je
   přesně disclaimer.bg Škody. Obecné pravidlo výš si ji teď bere z --disclaimer-bg, takže
   splývání s lištou platí samo od sebe pro každou barvu z dashboardu. Zelená poslechu
   a červená mute zůstávají univerzální stavové signály. */

/* ================================================================================================
   PROPORČNÍ ŠKÁLOVÁNÍ OVLÁDACÍCH PRVKŮ — JEN tenant skoda-avatar (Sebastian 2026-08-28)
   ------------------------------------------------------------------------------------------------
   ZADÁNÍ: „Mělo by se to vždycky škálovat dle velikosti obrazovky, aby to zachovávalo poměrově
   stejnou velikost na všech obrazovkách — jak tlačítka, tak i to interakční tlačítko."

   CO BYLO ŠPATNĚ (změřeno 28. 8., _mereni_PRED.json): na desktopu byla VŠECHNA velikost pevná
   v pixelech — tlačítko nabídky 22 px, nadpis 34 px, bublina 18 px, webové okno 360 px — a to
   od 820 px do 3440 px šířky stejně. Poměr tlačítka k oknu tak klesl z 3,06 % (1280×720) na
   1,53 % (2560×1440), tedy na POLOVINU: na velkém monitoru bylo ovládání opticky drobné.

   JEDNOTKA: `--ui-u` = 1vmin, tedy setina MENŠÍHO rozměru okna. Proč menší rozměr:
     · na širokoúhlém monitoru (21:9) je svazující výška — kdyby se počítalo z šířky, prvky by
       se na 3440×1440 nafoukly proti 2560×1440, ačkoli místa svisle nepřibylo (změřeno: obě
       šířky vycházejí IDENTICKY),
     · na tabletu na výšku je naopak svazující šířka a vmin ji podchytí sám.

   MEZE: každý prvek má clamp(dolní, poměr, horní). DOLNÍ MEZ je schválně rovna DNEŠNÍ hodnotě,
   takže se na malém desktopu, tabletu a v úzkém okně nic nezmenší (regrese vyloučena
   konstrukcí, doloženo měřením); horní mez brání „obludnosti" na velmi velkých plochách.

   TELEFON SE NEMĚNÍ: celý blok je uvnitř @media (min-width: 601px), takže do telefonní větve
   (@media max-width: 600px) nesahá ani jedním pravidlem.

   VÝJIMKA — webové okno: to je NA VÝŠKU 9:16 a jeho svazujícím rozměrem je tedy výška okna
   (šířka 45vh drží poměr 9:16 pod stropem 82vh, takže se okno nikdy neuřízne). 86vw zůstává
   pojistkou pro úzká okna. Ostatních tenantů se to netýká — Puk má vlastní pravidlo
   v ui-addons.css (min(720px, 47vh)), což je stejný princip i řádově stejná hodnota.
   ============================================================================================== */
@media (min-width: 601px) {
  [data-tenant="skoda-avatar"] {
    --ui-u: 1vmin;                                                        /* setina menšího rozměru okna */

    --ui-choice-fs:    clamp(22px, calc(2.40 * var(--ui-u)), 36px);       /* tlačítka nabídky */
    --ui-title-fs:     clamp(34px, calc(3.70 * var(--ui-u)), 56px);       /* nadpis nabídky (1,54× tlačítko) */
    --ui-choice-gap:   clamp(12px, calc(1.30 * var(--ui-u)), 20px);       /* mezera nadpis ↔ tlačítka */
    --choice-grid-gap: clamp(16px, calc(1.70 * var(--ui-u)), 26px);       /* mezera ve mřížce 2×2 */
    --ui-col-min:      clamp(260px, calc(28 * var(--ui-u)), 420px);       /* sloupec mřížky — min */
    --ui-col-max:      clamp(340px, calc(36 * var(--ui-u)), 560px);       /* sloupec mřížky — max */

    /* Bublina řeči: DOLNÍ mez je hodnota z nastavení (bubbles.fontSize → --bubble-font-size),
       takže slider v dashboardu dál platí; škálování jen roste nad ni, strop 1,7× nastavení. */
    --ui-bubble-fs:    clamp(var(--bubble-font-size, 18px), calc(1.95 * var(--ui-u)),
                             calc(var(--bubble-font-size, 18px) * 1.7));
    --ui-bubble-max:   min(96vw, clamp(960px, calc(104 * var(--ui-u)), 1500px));

    --ui-panel-w:      min(88vw, clamp(540px, calc(58 * var(--ui-u)), 860px));   /* obrázek */
    /* 41vh: víc už kolidovalo s bublinou řeči. Okno je 9:16 a vystředěné na 50 % výšky, takže
       jeho horní hrana (a přečnívající zavírací křížek) musí zůstat POD bublinou. Změřeno na
       1920×1080 rezerva 7 px, na 2560×1440 13 px; na oknech nižších než ~900 px se uplatní
       dolní mez 360px = dnešní hodnota, tam tedy zůstává dnešní (mírný) překryv. */
    --ui-panel-web-w:  min(86vw, clamp(360px, 41vh, 640px));                     /* web (9:16, viz výš) */
    --ui-panel-wide-w: min(96vw, clamp(780px, calc(82 * var(--ui-u)), 1180px));  /* e-mail + klávesnice */
    --ui-close:        clamp(46px, calc(4.40 * var(--ui-u)), 72px);              /* zavírací křížek */

    /* INTERAKČNÍ TLAČÍTKO (boční vlnka) — VELIKOST CELÉHO PRVKU, NIKDY NE GEOMETRIE.
       Sebastian 2026-08-28: „když ti říkám, že se má vlnka zvětšit, tak nebudeš zvyšovat její
       tvar, ale celej ten element" — tvar (viewBox a řídicí body v talkwave.js) je schválený
       z telefonu a NESMÍ se přepisovat; jediný povolený nástroj na velikost je tahle proměnná.
       Velikost vlastní talkwave.js inline stylem `min(var(--tw-side-h, 680px), 84vh)` —
       sem patří JEN hodnota proměnné, do modulu se nesahá.

       ZŮSTÁVÁ PŮVODNÍ STUPNICE 680/72/1150 — a je to ROZHODNUTÍ, ne opomenutí.
       Sebastian 28. 8. řekl „je strašlivě obrovské, mělo by být tak o třetinu menší", jenže
       koukal na DEFORMOVANOU vlnku (viewBox 150:340, hloubka:rozpětí 1:0,94). Oprava tvaru
       (commit 1bddc60 — doslovná transpozice telefonní cesty, viewBox 78:390) sama ubere na
       šířce 55 % při nezměněné výšce, takže jeho požadavek je splněný TVAREM. Kdyby se k tomu
       přidalo ještě zkrácení výšky na 2/3, sešla by se dvě zmenšení a skončili bychom na 30 %
       původku — proti jeho zadání, ne v souladu s ním. Hokej to má stejně (ui-addons.css:
       override 455px zrušen, jede na výchozích 680).
       Změřeno živě (výška × šířka, deformovaný tvar → opravený tvar při téže výšce):
         1440×900   680×300 → 680×136 (9,4 % šířky okna)
         1920×1080  778×343 → 778×156 (8,1 %)
         2560×1440 1037×457 → 1037×207 (8,1 %)
       Dolní mez 680px = původní default (tablet i 1280×720 tedy zůstávají beze změny), nad ni
       roste s vmin. Šířka jde z poměru viewBoxu (78:390 = 1:5, shodně s telefonem).
       Telefon se nemění: celý blok je uvnitř @media (min-width: 601px). */
    --tw-side-h:       clamp(680px, calc(72 * var(--ui-u)), 1150px);
  }

  /* --- nabídka ------------------------------------------------------------------------------ */
  [data-tenant="skoda-avatar"] #choices { gap: var(--ui-choice-gap); }
  /* padding v em → vnitřní okraje rostou s písmem samy; .82em/1.55em = dnešních 18px/34px při 22px */
  [data-tenant="skoda-avatar"] #choices button { font-size: var(--ui-choice-fs); padding: .82em 1.55em; }
  [data-tenant="skoda-avatar"] #choices-title  { font-size: var(--ui-title-fs); }
  [data-tenant="skoda-avatar"] #choices-row {
    grid-template-columns: repeat(2, minmax(var(--ui-col-min), var(--ui-col-max)));
    gap: var(--choice-grid-gap);
  }

  /* --- bublina řeči ------------------------------------------------------------------------- */
  [data-tenant="skoda-avatar"] #speech-bubble {
    font-size: var(--ui-bubble-fs); max-width: var(--ui-bubble-max);
    padding: .5em 1em; border-radius: 1.1em;
  }

  /* --- okno s obsahem (obrázek / web / e-mail) ----------------------------------------------- */
  [data-tenant="skoda-avatar"] #content-panel { width: var(--ui-panel-w); }
  [data-tenant="skoda-avatar"] #content-panel.panel-web { width: var(--ui-panel-web-w); }
  /* Strop výšky iframu (80vh) se ZÁMĚRNĚ nemění: šířka 41vh znamená výšku 41vh × 16/9 = 72,9vh,
     takže se do stropu vždycky vejde a okno se neořezává. Zvednutí stropu by se projevilo jedině
     na nízkých oknech, kde vládne dolní mez 360px — a tam by okno jen povyrostlo do bubliny
     (naměřeno +7 px překryvu na 1280×720). Necháváme tedy dnešní hodnotu. */
  /* !important je tu JEN proto, že ho má základní pravidlo .panel-wide (řádek s min(780px,96vw));
     bez něj by tenantová hodnota neprošla. Není to obcházení cizí session — obě pravidla jsou
     v tomhle souboru a jde o tentýž prvek. */
  [data-tenant="skoda-avatar"] #content-panel.panel-wide { width: var(--ui-panel-wide-w) !important; }
  [data-tenant="skoda-avatar"] .panel-close {
    width: var(--ui-close); height: var(--ui-close);
    top: calc(var(--ui-close) * -.35); right: calc(var(--ui-close) * -.35);
    font-size: calc(var(--ui-close) * .435);
  }
  /* BUBLINA NAD PANELEM — POJISTKA k vadě 5 („avatar mluví, ale nevidím jeho textovou bublinu").
     #content-panel je v DOMu ZA bublinou, takže ji při překryvu překresluje. Se šířkou webového
     okna 41vh k překryvu na oknech od ~880 px výšky NEDOCHÁZÍ (změřeno: rezerva 7 px na
     1920×1080, 13 px na 2560×1440) — pravidlo je tu pro případ, že si někdo v dashboardu zvětší
     okno přes web.size / image.size.
     STROP min-height: 880px je schválně: na nižších oknech se bublina s panelem protíná i dnes
     (38,8 px na 1280×720, 12,5 px na 1440×810) a tam by bublina zakryla zavírací křížek. Pod
     880 px proto zůstává DNEŠNÍ chování (panel nad bublinou) — nic se nezhorší.
     pointer-events: none — bublina je jen titulek, nikdy se do ní neklikalo; takhle případný
     klik projde skrz na ovládání pod ní. */
  @media (min-height: 880px) {
    [data-tenant="skoda-avatar"] #speech-bubble { z-index: 8; pointer-events: none; }
  }
  /* ovládání e-mailového okna — stupně písma ve stejném poměru jako dnes (20 / 22 / 20 / 18 px) */
  [data-tenant="skoda-avatar"] .email-title { font-size: clamp(20px, calc(2.10 * var(--ui-u)), 32px); }
  [data-tenant="skoda-avatar"] #email-input { font-size: clamp(22px, calc(2.35 * var(--ui-u)), 36px); }
  [data-tenant="skoda-avatar"] .email-send  { font-size: clamp(20px, calc(2.10 * var(--ui-u)), 32px); }
  [data-tenant="skoda-avatar"] .osk-key     { font-size: clamp(18px, calc(1.90 * var(--ui-u)), 28px); }
}

/* ---- Debug overlay (vlevo nahoře) ---- */
#debug{
  position:fixed;left:14px;top:12px;z-index:50;pointer-events:none;
  font-family:ui-monospace,"Cascadia Code",monospace;font-size:13px;line-height:1.5;
  text-shadow:0 1px 3px rgba(0,0,0,.9);max-width:46vw;
  /* poloprůhledné rozmazané pozadí → text čitelný i na barevném/foto pozadí */
  background:rgba(8,12,20,.42);backdrop-filter:blur(7px);-webkit-backdrop-filter:blur(7px);
  padding:10px 14px;border-radius:12px;
}
#dbg-conn{font-weight:700;letter-spacing:.5px;}
#dbg-conn.on{color:#39d353;}   /* připojeno */
#dbg-conn.off{color:#ff4d4d;}  /* odpojeno */
#dbg-action{color:#ffd166;margin-top:2px;}
#dbg-log{color:#9fb0c0;margin-top:4px;}
#dbg-log div{opacity:.5;}
#dbg-log div:last-child{opacity:1;color:#cfe0f0;}
/* (styl ladicího tlačítka „Odpojit server" odstraněn 27. 8. 2026 spolu s tlačítkem — viz index.html) */

/* ==========================================================================================
   AI ŠTÍTEK ŠKODY V DISCLAIMERU (28. 8. 2026)
   ------------------------------------------------------------------------------------------
   Odznak „AI" s facetovým řezem dodaný klientem (Škoda Brand Portal → AI-generated content,
   příloha „AI Labels.zip"). Vychází z transparenčních povinností EU AI Act účinných
   od 2. 8. 2026 — je to BRANDOVÉ PRAVIDLO ŠKODY, ne ozdoba.

   PLATÍ JEN PRO TENANTY SE ŠTÍTKEM: celé to visí na <html data-ai-label="1">, který nasazuje
   config.js podle seznamu AI_LABEL_TENANTS. Puk (hokej-avatar) ani xlab-avatar atribut
   nedostanou → ani jedno pravidlo této sekce se u nich neuplatní a jejich lišta je beze změny.

   PROVEDENÍ = 1:1 podle kiosku Laurin (zdroj pravdy; Autostadt, lišta 4320 × 288 px).
   Změřeno z nasazeného Disclaimer_{CS,EN,DE}_pruhledne.png (doklady D2–D5 v _doklady_0813):
     · varianta  White — bílá plocha, ČERNÉ „AI" (plná, NE průhledná; v pixelech odznaku jsou
                 čistě bílá 255,255,255 a čistě černá 0,0,0, žádné prosvítající pozadí)
     · pozice    vpravo, svisle na střed lišty
     · výška     184 / 288 px = 63,9 % výšky lišty
     · odstupy   51–52 px od pravé, horní i dolní hrany = 18,1 % výšky lišty na všech třech
                 stranách → odstup od pravé hrany = 28,27 % výšky kresby odznaku
   Kiosek používá tentýž vektor přes rastr AI_badge_White_130x96.png (LogKioskAiStitek).

   Soubor assets/ui/ai-stitek/White.svg je BYTE PO BYTU klientův vektor (sha256
   184e3988 68140ecd 6b63a9a6 55bcc5be 795a9733 a9d89af3 53d5a06c b7c7009c). Nepřebarvuje se,
   neotáčí, neořezává ani nepřekresluje — mění se jen jeho velikost, přesně jako v kiosku.

   GEOMETRIE VEKTORU — POZOR: viewBox je 130 × 96, ale kresba končí na 129,601 × 93,0894.
   Dole tedy zbývá 3,03 % prázdna a vpravo 0,31 %. Kdyby se box vektoru jen zarovnal na střed,
   seděl by odznak opticky nízko a moc vlevo. Proto má box poměr 130 : 96, kresbu v něm roztáhne
   background-size: contain, a posun translate() je spočítaný tak, aby na střed a do odstupu
   sedla KRESBA, ne box (procenta se počítají z vlastní velikosti boxu, takže platí v obou
   větvích min() níž):
     svisle     0,5 · (93,0894 / 96)                              = 48,48 %
     vodorovně  (0,28268 · 0,96968 − 0,00307 · 1,354167) / 1,354167 = 19,94 %

   VÝŠKA = min(65,89 %; 2,95em):
     · 65,89 % výšky lišty JE Laurinových 63,9 % kresby (65,89 · 0,96968 = 63,9) — tahle větev
       rozhoduje na normální jedno- i dvouřádkové liště, tedy odznak drží přesně jeho proporci;
     · 2,95em je táž velikost vyjádřená písmem a slouží jako STROP pro degenerovaný případ,
       kdy lištu nafoukne třetí řádek (dlouhý text v úzkém telefonu). Bez stropu by odznak
       s vyšší lištou vyrostl přes rezervovaný sloupec a vlezl by do textu.

   MÍSTO SI BERE ŠTÍTEK, NE TEXT: --ai-stitek-sloupec je rezervace v pravém paddingu lišty,
   o kterou se zmenší prostor pro sazbu — přesně ta šířka, kterou odznak i s ochranným odstupem
   zabere. Měření fitDisclaimer() v config.js kvůli tomu nepotřebuje ani řádku navíc: počítá
   řádky ze SKUTEČNĚ vysázené lišty, takže užší prostor uvidí samo a písmo si zmenší.
   Rezervace je v em, takže se zmenšuje spolu s písmem a hledání konverguje (menší písmo →
   užší sloupec → víc místa pro text), nikdy neosciluje.
   Šířka sloupce = kresba (1,34901 · box) + 2 × odstup (0,28268 · 0,96968 · box) = 1,89724 · box.
   Rezervuje se JEN VPRAVO (Sebastian: „o šířku, kterou štítek zabere, se musí zmenšit prostor
   pro text") — symetrická rezervace na obou stranách stojí dvakrát tolik a na telefonu vyhnala
   všechny tři jazyky na tři řádky (změřeno 28. 8., viz Nahledy_UI/ai_stitek_2026-08-28).
   ========================================================================================== */
[data-ai-label="1"] #disclaimer {
  --ai-stitek-box: 2.95em;                                        /* strop výšky BOXU vektoru */
  --ai-stitek-sloupec: calc(1.89724 * var(--ai-stitek-box));      /* kresba + 2 × odstup */
  /* Pravý padding = rezervace pro odznak. max() proto, že odstup odznaku od hrany se počítá
     od HRANY LIŠTY a už v sobě má i to, co dřív dělal základní padding — nesčítá se s ním.
     Základní hodnoty (14px / clamp níž) jsou opsané z pravidla #disclaimer výš; kdyby se tam
     změnily, změnit i tady. Levý padding se NEMĚNÍ. */
  padding-right: max(14px, var(--ai-stitek-sloupec));
}
[data-ai-label="1"] #disclaimer::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 0;
  height: min(65.89%, var(--ai-stitek-box));
  aspect-ratio: 130 / 96;                        /* viewBox dodaného vektoru */
  transform: translate(-19.94%, -48.48%);
  background: url("/assets/ui/ai-stitek/White.svg") center / contain no-repeat;
  pointer-events: none;
}
@media (max-width: 600px) {
  [data-ai-label="1"] #disclaimer { padding-right: max(clamp(4px, 1.6vw, 6px), var(--ai-stitek-sloupec)); }
}
