/* ==========================================================================
   ПРОЛОГЪТ — отвесният герой и разпадът на надписа
   Зарежда се СЛЕД experience.css и нарочно живее в свой файл: така работата по
   пролога не се преплита с останалата част от листа.
   ========================================================================== */

/* ── СТАТИЧНИЯТ ПЪРВИ КАДЪР ────────────────────────────────────────────────
   `hero_top.webp` е ИЗПЕЧЕН ОТ САМАТА СЦЕНА в позата, в която живото 3D застава
   при `introT = 0` (`tools/harness/herobake.mjs`). Затова преливането между
   снимка и сцена е невидимо: това не е „друга картинка", а първият кадър на
   филма, изчислен предварително — сцената под нея показва СЪЩИТЕ пиксели.
   ⚠ ЗАТОВА И НИКАКВИ ГРАДИЕНТИ ТУК. Всеки слой, който стои върху снимката, но
   не и върху живото 3D, се вижда като скок точно в мига на преливането.
   Винетката `.xp-frame` е под `.xp-hero` (z 1 срещу 5) и вече е ВПЕЧЕНА в
   кадъра; полумракът зад текста слезе при текста, където му е мястото. */
/* ⛔ `cover` БЕШЕ ГРЕШНОТО ПАСВАНЕ. Камерата има ФИКСИРАН ВЕРТИКАЛЕН ъгъл (36°):
   при по-широк изглед сцената показва ПОВЕЧЕ настрани и СЪЩОТО нагоре-надолу.
   `cover` прави точно обратното — мащабира по ширина и РЕЖЕ отгоре и отдолу.
   Затова стрехите се отрязваха на 1.82:1, а живото 3D под снимката ги показва.
   `auto 100%` заковава ВЕРТИКАЛНИЯ обхват и оставя ширината да се реже — точно
   поведението на камерата. Снимката е изпечена на 2.35:1, за да е по-широка от
   всеки практичен изглед и да няма празнина отстрани. */
.xp-hero {
  /* ⛔⛔ 08-04 · КЕШ-БУСТЪТ ТУК СЕ РАЗМИНАВАШЕ С ТОЗИ В `index.html` (1785380777
     срещу 1785379179) и браузърът сваляше СЪЩАТА снимка ДВА ПЪТИ — мерено с
     `tools/harness/_ship_audit.mjs`: 2 × 2.17 MB в 71 заявки / 42.6 MB. При това
     `preload … fetchpriority="high"` в главата зареждаше версия, която CSS-ът
     после НЕ ползваше, тоест предзареждането работеше срещу LCP вместо за него.
     Правило: кеш-бустът на един файл се пише на ЕДНО място.
     ⛔⛔ 08-06 · СЪЩИЯТ ДЕФЕКТ СЕ ВЪРНА, ТРЕТИ ПЪТ, при **webp** варианта:
     `index.html` предзареждаше `?v=1785880392`, а този ред стоеше на `1785379179`
     ⇒ мерено `performance.getEntriesByType("resource")`: ДВА записа за
     `hero_top.webp`, **747 KB всеки**, старт 11 мс (link) и 42 мс (css).
     Тоест `preload fetchpriority="high"` пак работеше СРЕЩУ LCP.
     ⇒ Правилото вече не се пази с коментар, а с ГЕЙТ: `tools/harness/cachebust.mjs`
     чете всички `?v=` в index.html · styles · lib и отказва при разминаване. */
  /* ⚑⚑ 08-08 · #297 · AVIF С РЕЗЕРВА ПРЕЗ `image-set()`.
     Мерено днес: `hero_top.webp` е 746 KB; AVIF при q60 е **370 KB (−50 %)** при
     RMS **2.11/255** спрямо WebP-а (q50 дава 229 KB при 2.72, q45 — 186 KB при 3.06).
     ⛔ ИЗБРАН Е q60, НЕ q50: тази снимка Е LCP елементът И еталонът, срещу който
     гейтът `hero` мери остротата на живото 3D (1.338×). По-мека снимка вдига това
     отношение „безплатно" — тоест гейтът би позеленял ЗАРАДИ регресия. По-малкото
     отклонение струва 141 KB и не мени присъдата.
     ⚑ `image-set()` е договорът: браузър без AVIF взима WebP-а. Safari 16+ и
     Chrome 90+ го поддържат; по-старите падат на реда `url()` отдолу. */
  background: url("../assets/hero_top.webp?v=c832eccc") center / auto 100% no-repeat;
  background-image: image-set(
    url("../assets/hero_top.avif?v=71e80416") type("image/avif"),
    url("../assets/hero_top.webp?v=c832eccc") type("image/webp"));
  background-color: #070605;   /* същият тон като дъното на `.xp-stage` */
  filter: none;   /* рендерът е тонално обработен от ACES — второ пипане го чупи */
  /* ⛔⛔ 07-30 · ТОВА БЕШЕ ПРИЧИНАТА ЗА „РАЗМАЗВАНЕТО ПРИ ПРЕХОДА".
     `experience.css` слага тук `transition: opacity .5s ease`, а `paintIntro`
     пише нова непрозрачност на ВСЕКИ кадър — второ затихване върху затихването
     на двигателя. Мерено (`smearaudit.mjs`): на 451-ата ms зададеното е 0, а
     изчисленото 0.692, и снимката гасне чак на 867-ата — 420 ms, в които тя
     стои наложена върху сцена, слязла 7.2 м. Двоен образ, не замъгляване.
     Преливането се прави от JS еднократно и В ПОКОЙ (`предайГероя`), където
     двата слоя са един и същи кадър; там преходът се задава инлайн. */
  transition: none;
}
/* Винетката минава НАД снимката (беше под нея): така един и същ CSS слой
   затъмнява и снимката, и живото 3D. Иначе тя трябваше да е ВПЕЧЕНА в кадъра,
   а тя е вързана за пропорцията на прозореца и не се пече вярно. */
.xp-frame { z-index: 6; }

/* ── ПОРТРЕТ: камерата се ДРЪПВА, снимката трябва да я последва ──────────────
   Под пропорция 1.15 `resize()` отваря ъгъла 36°→52° и дърпа камерата ×1.55
   (`rK`), тоест сцената показва много повече. Видимата височина расте с
   `rK · tan(fov/2) / tan(18°)`:
     пропорция 1.15 → ×1.00 → 100 %
     пропорция 0.80 → ×1.60 →  63 %
     пропорция 0.46 → ×2.32 →  43 %
   Без това преливането на телефон е скок в мащаба. Стълбицата е груба, но
   грешката ѝ е под 8 % — далеч под скока, който поправя. */
@media (max-aspect-ratio: 115/100) { .xp-hero { background-size: auto 63%; } }
@media (max-aspect-ratio: 80/100)  { .xp-hero { background-size: auto 43%; } }

/* ── ПОЛУМРАКЪТ ЗАД ТЕКСТА ─────────────────────────────────────────────────
   Живее при текста и си отива заедно с него, а не със снимката. */
.xp-intro::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: calc(1 - var(--dis, 0));
  background: linear-gradient(102deg,
    rgba(5, 3, 2, 0.66) 0%,
    rgba(5, 3, 2, 0.40) 24%,
    rgba(5, 3, 2, 0.10) 44%,
    transparent 58%);
}

/* Дребните надписи гаснат първи; само H1 се разпада на зърна. */
.xp-intro .hero-over,
.xp-intro .hero-rule,
.xp-intro .hero-cta { opacity: var(--sec, 1); }

/* ── РАЗПАДЪТ НА ЗАГЛАВИЕТО ────────────────────────────────────────────────
   Маската яде буквите ОТГОРЕ НАДОЛУ (изпарява се нагоре), а `hero-dust.js`
   рисува отделилите се зърна върху същото място.
   Числата са изведени, не подбрани: фронтът трябва да стигне ГОРНИЯ ръб точно
   когато полетят първите зърна (--dis ≈ 0.08) и ДОЛНИЯ при 1 →
   X(d) = 111% − 136%·d. Мекият ръб е 22 % от височината. */
.xp-intro .hero-h1 {
  transform: translateY(calc(var(--dis, 0) * -1.5rem));
  filter: blur(calc(var(--dis, 0) * var(--dis, 0) * 5px));
  -webkit-mask-image: linear-gradient(to top,
    #000 calc(111% - var(--dis, 0) * 136%),
    transparent calc(133% - var(--dis, 0) * 136%));
  mask-image: linear-gradient(to top,
    #000 calc(111% - var(--dis, 0) * 136%),
    transparent calc(133% - var(--dis, 0) * 136%));
  will-change: transform, filter;
}

/* Платното със зърната стои НАД снимката, но под навигацията.
   ⚠ `fixed`, не `absolute`: героят е закован, а страницата под него се движи. */
.hero-dust {
  position: fixed;
  z-index: var(--z-hud);
  pointer-events: none;
  display: none;
}

/* Спокоен режим: без разпад, без вдигане — само чист преход. */
@media (prefers-reduced-motion: reduce) {
  .xp-intro .hero-h1 { transform: none; filter: none; }
  .hero-dust { display: none !important; }
}

/* ══ ⏳ 08-08 · ЛЕНТАТА НА ЗАРЕЖДАНЕТО ══════════════════════════════════════
   Стои НА МЯСТОТО на призива „Скролирай и строй" и се сменя с него — един
   елемент на едно място, без наслагване и без премигване.
   Езикът е на самия сайт, нищо ново не се измисля: серифното число (Prata),
   една златна власинка и микро главни с тракинг — същата стълбица, с която е
   писан целият HUD.
   ⛔ БЕЗ `backdrop-filter` (мерено `cardglass.mjs`: −21.8 % к/с) и БЕЗ втори
   слой стъкло. Четимостта върху заетия кадър се пази с плътен радиален полумрак
   и с една сянка под власинката — и двете безплатни за композитора. */
.hero-boot {
  position: absolute;
  left: 50%;
  bottom: var(--edge-v);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s4);
  padding: var(--s6) var(--s10) var(--s4);
  pointer-events: none;
  text-align: center;
  color: var(--gold-hi);
  transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
/* полумракът: центриран елипсовиден, за да не се вижда ръб */
.hero-boot::before {
  content: "";
  position: absolute;
  inset: -10% -6%;
  background: radial-gradient(60% 70% at 50% 55%,
    rgba(5, 4, 3, 0.72), rgba(5, 4, 3, 0.32) 55%, transparent 78%);
  z-index: -1;
}
/* ЧИСЛОТО — водещото. Табличните цифри пазят блока да не подскача при 9→10→100,
   а фиксираната ширина държи знака „%" на едно и също място през цялото време. */
.hero-boot .hb-num {
  display: inline-flex;
  align-items: flex-start;
  justify-content: center;
  min-width: 4.4ch;
  gap: 0.14em;
  font-family: var(--font-display);
  font-size: clamp(2.1rem, 1.4rem + 2.2vw, 3.4rem);
  line-height: 0.92;
  letter-spacing: 0.005em;
  font-variant-numeric: tabular-nums;
  color: var(--ivory);
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.75);
}
.hero-boot .hb-num i { font-style: normal; }
.hero-boot .hb-num small {
  font-family: var(--font-text);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--tr-micro);
  color: var(--gold-55);
  transform: translateY(0.35em);
}
/* ВЛАСИНКАТА — същият жест като `--rule` в HUD-а, но с измерим пълнеж.
   Сянката отдолу я държи четима и когато под нея мине светло дърво. */
.hero-boot .hb-rail {
  position: relative;
  width: clamp(150px, 21vw, 280px);
  height: 1px;
  background: rgba(201, 169, 106, 0.22);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.55);
  overflow: hidden;
}
.hero-boot .hb-rail i {
  position: absolute;
  inset: 0;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--gold-lo), var(--gold-hi));
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}
/* ⛔⛔ 08-08 · ЧИСЛОТО ЗАМРЪЗВА, ЗАЩОТО НИШКАТА Е БЛОКИРАНА — не защото лентата
   е мързелива. Мерено (`tools/harness/bootbar.mjs`, 1920×1038 dpr 2): смените
   вървят 0→27 % гладко, после стоят **1 120 мс** (27→43), **1 036 мс** (43→50) и
   **1 660 мс** (50→67) — точно трите синхронни парчета на `create()`. През тях
   НИКАКЪВ JS и НИКАКВО пребоядисване не могат да станат.
   ⇒ Живият знак се дава от КОМПОЗИТОРА, не от главната нишка: една-единствена
   анимация на `transform`, която върви и когато JS-ът е блокиран.
   ⚖️ ЦЕНАТА, КАЗАНА ЧЕСТНО: законът от 08-03 („безкрайните анимации будят
   композитора завинаги", мерено 2.8 % → 1.7 % от едно ядро) важи — затова тази
   тук НЕ Е безкрайна по живот: селекторът е `body.xp-booting`, тоест тя
   престава да съществува в мига на отключването и никога не се връща. */
body.xp-booting .hero-boot .hb-rail::after {
  content: "";
  position: absolute;
  inset: 0;
  width: 34%;
  background: linear-gradient(90deg, transparent, rgba(233, 214, 175, 0.55), transparent);
  animation: hbSweep 1.8s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  will-change: transform;
}
@keyframes hbSweep {
  0%   { transform: translateX(-110%); }
  100% { transform: translateX(400%); }
}
@media (prefers-reduced-motion: reduce) {
  body.xp-booting .hero-boot .hb-rail::after { animation: none; opacity: 0.3; }
  .hero-boot .hb-rail i { transition: none; }
}
.hero-boot .hb-txt {
  font-family: var(--font-text);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--tr-micro);
  text-transform: uppercase;
  color: var(--txt-55);
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.7);
}

/* ⚑ КОЙ СЕ ВИЖДА КОГА — по ЕДИН клас на `body`, не по два флага в JS.
   Докато трае буутът: лентата се вижда, призивът го няма (и не може да се
   натисне). След отключването: точно обратното. */
body.xp-booting .hero-cta { opacity: 0 !important; pointer-events: none; }
body:not(.xp-booting) .hero-boot { opacity: 0; visibility: hidden; }
/* ⛔ при `.xp-nogl` (без WebGL) лентата няма какво да брои — маха се веднага */
body.xp-nogl .hero-boot { display: none; }
