/* ==========================================================================
   EnderGate v2 — ShulDi Network

   Концепция:
     ПУСТОТА. Не «космос с фиолетовым градиентом», а Энд — чёрная бездна,
     в которой висят блоки. Фиолетовый здесь не фон, а свет, который
     портал роняет на камень. Золото появляется ровно там, где нужно
     нажать.

   Сигнатурный момент: сборка чанка на скролле.

   Разделы:
     1. Токены
     2. База и типографика
     3. Пустота (атмосфера)
     4. Воксели — 3D-система Minecraft
     5. Ядро статуса сервера
     6. Навигация
     7. Герой
     8. Секции, бегущая строка, карточки
     9. Мост к Bootstrap и плагинам
    10. Моторика
    11. Адаптив и доступность
   ========================================================================== */

/* ==========================================================================
   1. Токены
   ========================================================================== */
:root {
    /* --- Цвет ---
       Ни чистого чёрного, ни чистого белого. Фиолетовый — акцент, а не фон:
       большая площадь отдана пустоте, поэтому свет портала читается. */
    --void:            #08070a;   /* базовая пустота, тёплый сдвиг */
    --void-2:          #0d0b11;
    --surface:         #12101a;
    --surface-2:       #191527;

    --ink:             #f2eef8;   /* основной текст */
    --ink-60:          rgba(242, 238, 248, 0.62);
    --ink-40:          rgba(242, 238, 248, 0.40);
    --ink-20:          rgba(242, 238, 248, 0.20);
    --line:            rgba(242, 238, 248, 0.10);

    --ender:           #7B2FBE;   /* фирменный фиолетовый */
    --ender-lit:       #a855f7;   /* тот же, но «под светом» */
    --ender-deep:      #3d1560;
    --gold:            #FFD700;   /* только CTA и цифры */
    --portal:          #00D4FF;   /* только свечение ядра */

    --ok:              #4ade80;
    --down:            #ff4d5e;

    /* --- Типографика ---
       Display : Syne — характерный, с необычными пропорциями.
       UI/body : Space Grotesk — геометрический, техничный.
       Pixel   : Press Start 2P — ТОЛЬКО цифры и микрометки. Пиксельный
                 шрифт в заголовке нечитаем, поэтому он здесь голос
                 «системного показания», а не заголовков. */
    --font-display: 'Syne', 'Space Grotesk', system-ui, sans-serif;
    --font-body:    'Space Grotesk', system-ui, -apple-system, sans-serif;
    --font-pixel:   'Press Start 2P', 'Courier New', monospace;

    /* Контраст display:body ≈ 6:1. Больше ставить нельзя: текстовая
       колонка занимает ~45% ширины, и на 9vw заголовок ломался на четыре
       строки и выдавливал за экран всё остальное, включая статус сервера. */
    --t-hero:    clamp(2.5rem, 1rem + 4.4vw, 6.25rem);
    --t-display: clamp(2.5rem, 1.2rem + 5.4vw, 6.5rem);
    --t-h2:      clamp(1.9rem, 1.2rem + 2.6vw, 3.4rem);
    --t-h3:      clamp(1.15rem, 1rem + 0.7vw, 1.5rem);
    --t-body:    clamp(1rem, 0.96rem + 0.2vw, 1.0625rem);
    --t-small:   0.8125rem;
    --t-micro:   0.625rem;

    /* --- Моторика --- */
    --e-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);
    --e-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
    --e-out-quint: cubic-bezier(0.22, 1, 0.36, 1);
    --e-in-out:    cubic-bezier(0.87, 0, 0.13, 1);
    --e-back:      cubic-bezier(0.34, 1.56, 0.64, 1);

    --d-fast: 180ms;
    --d-norm: 320ms;
    --d-slow: 560ms;
    --d-rev:  900ms;

    --radius: 4px;   /* мир кубический — скругления почти нет */
    --gutter: clamp(1.25rem, 4vw, 4rem);

    /* --- Мост к Bootstrap --- */
    --bs-primary: #7B2FBE;
    --bs-primary-rgb: 123, 47, 190;
    --bs-body-bg: #08070a;
    --bs-body-color: #f2eef8;
    --bs-link-color: #FFD700;
    --bs-link-hover-color: #ffe98a;
    --bs-border-color: rgba(242, 238, 248, 0.10);
    --bs-border-radius: 4px;
    --bs-font-sans-serif: 'Space Grotesk', system-ui, sans-serif;
}

/* ==========================================================================
   2. База и типографика
   ========================================================================== */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    /* Lenis управляет прокруткой; нативный smooth с ним конфликтует */
    scroll-behavior: auto;
}

html.lenis,
html.lenis body {
    height: auto;
}

.lenis.lenis-smooth {
    scroll-behavior: auto !important;
}

body {
    background: var(--void);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: var(--t-body);
    line-height: 1.6;
    letter-spacing: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/*
 * Своего слоя у #app быть не должно.
 *
 * С z-index: 2 он создавал слой, внутри которого запиралось модальное
 * окно. Подложку окна Bootstrap вешает на body с z-index 1050 — выше
 * всего #app, — и окно оказывалось под собственной подложкой: клики
 * по кнопкам в магазине забирала она. Фоновые слои теперь уведены
 * назад отрицательным z-index, поэтому поднимать содержимое не нужно.
 */
#app {
    flex: 1 0 auto;
    position: relative;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    font-weight: 800;
    color: #fff;
    text-wrap: balance;
}

h1 { font-size: var(--t-display); line-height: 0.92; letter-spacing: -0.035em; }
h2 { font-size: var(--t-h2);      line-height: 1.0;  letter-spacing: -0.03em; }
h3 { font-size: var(--t-h3);      line-height: 1.15; letter-spacing: -0.02em; }

p { max-width: 68ch; }

a {
    color: var(--gold);
    text-decoration: none;
    transition: color var(--d-fast) var(--e-out-quart);
}

a:hover { color: #fff; }

/* Фирменное выделение */
::selection {
    background: var(--ender-lit);
    color: #fff;
}

/* Микрометка — «системное показание» */
.eg-micro {
    font-family: var(--font-pixel);
    font-size: var(--t-micro);
    line-height: 1.8;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-40);
}

.eg-micro--portal { color: var(--portal); }
.eg-micro--gold   { color: var(--gold); }

::-webkit-scrollbar { width: 8px; }
::-webkit-scrollbar-track { background: var(--void); }
::-webkit-scrollbar-thumb { background: var(--ender-deep); }
::-webkit-scrollbar-thumb:hover { background: var(--ender); }

/* ==========================================================================
   3. Пустота
   Один слой света вместо полноэкранного градиента: портал «подсвечивает»
   сцену снизу, всё остальное остаётся чёрным.
   ========================================================================== */
.eg-void {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(60% 45% at 50% 78%, rgba(123, 47, 190, 0.22), transparent 70%),
        radial-gradient(38% 28% at 50% 74%, rgba(0, 212, 255, 0.10), transparent 72%);
}

/* Тонкая кубическая сетка — намёк на воксель, а не «сетка ради сетки» */
.eg-mesh {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0.5;
    background-image:
        linear-gradient(rgba(242, 238, 248, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(242, 238, 248, 0.035) 1px, transparent 1px);
    background-size: 64px 64px;
    mask-image: radial-gradient(120% 90% at 50% 50%, #000 20%, transparent 78%);
    -webkit-mask-image: radial-gradient(120% 90% at 50% 50%, #000 20%, transparent 78%);
}

.eg-dust {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
}

/* ==========================================================================
   4. Воксели — 3D-система Minecraft

   Один компонент .mc-voxel на CSS 3D. Никакого WebGL: 6 граней,
   preserve-3d, пиксельная текстура шахматкой и жёсткое посветление
   верхней грани — так куб читается объёмным без единого шейдера.
   ========================================================================== */
.mc-scene {
    position: relative;
    perspective: 1200px;
    perspective-origin: 50% 45%;
    width: 100%;
    aspect-ratio: 1 / 1;
    max-height: 78vh;
}

/* Камеру крутит скролл и мышь: JS пишет --cam-x/--cam-y/--cam-z */
.mc-camera {
    position: absolute;
    inset: 0;
    transform-style: preserve-3d;
    contain: layout style;
    transform:
        rotateX(calc(var(--cam-x, -18) * 1deg))
        rotateY(calc(var(--cam-y, 24) * 1deg))
        translateZ(calc(var(--cam-z, 0) * 1px));
    transition: transform 120ms linear;
    will-change: transform;
}

.mc-voxel {
    --s: 64px;              /* ребро */
    --h: calc(var(--s) / 2);
    position: absolute;
    top: 50%;
    left: 50%;
    width: var(--s);
    height: var(--s);
    margin: calc(var(--s) / -2);
    transform-style: preserve-3d;
    /* Стартовая позиция «разлёта» и целевая — между ними интерполирует JS */
    transform:
        translate3d(
            calc(var(--x, 0) * 1px),
            calc(var(--y, 0) * 1px),
            calc(var(--z, 0) * 1px)
        )
        rotateX(calc(var(--rx, 0) * 1deg))
        rotateY(calc(var(--ry, 0) * 1deg));
    will-change: transform;
}

.mc-face {
    position: absolute;
    inset: 0;
    /* Оригинальные текстуры Minecraft 1.21.1, 16x16.
       pixelated обязателен: без него браузер размоет пиксель-арт в кашу. */
    background-image: var(--tex);
    background-size: 100% 100%;
    background-repeat: no-repeat;
    image-rendering: pixelated;
    image-rendering: crisp-edges;
    outline: 1px solid rgba(0, 0, 0, 0.5);
    outline-offset: -1px;
}

/* Грани. Жёсткое различие яркости = объём. */
.mc-face.f  { transform: translateZ(var(--h)); background-image: linear-gradient(rgba(0, 0, 0, 0.264), rgba(0, 0, 0, 0.264)), var(--tex); }
.mc-face.bk { transform: rotateY(180deg) translateZ(var(--h)); background-image: linear-gradient(rgba(0, 0, 0, 0.472), rgba(0, 0, 0, 0.472)), var(--tex); }
.mc-face.r  { transform: rotateY(90deg)  translateZ(var(--h)); background-image: linear-gradient(rgba(0, 0, 0, 0.376), rgba(0, 0, 0, 0.376)), var(--tex); }
.mc-face.l  { transform: rotateY(-90deg) translateZ(var(--h)); background-image: linear-gradient(rgba(0, 0, 0, 0.376), rgba(0, 0, 0, 0.376)), var(--tex); }
.mc-face.t  { transform: rotateX(90deg)  translateZ(var(--h));  }
.mc-face.bt { transform: rotateX(-90deg) translateZ(var(--h)); background-image: linear-gradient(rgba(0, 0, 0, 0.64), rgba(0, 0, 0, 0.64)), var(--tex); }

/* Породы. Палитра держится на приглушённом камне и пурпуре Энда —
   яркое (алмаз, золото, аметист) появляется редко, иначе кластер
   читается как детские кубики, а не как мир. */
.mc-voxel[data-block="end_stone"]        { --tex: url('../img/blocks/end_stone.png'); }
.mc-voxel[data-block="end_stone_bricks"] { --tex: url('../img/blocks/end_stone_bricks.png'); }
.mc-voxel[data-block="purpur_block"]     { --tex: url('../img/blocks/purpur_block.png'); }
.mc-voxel[data-block="purpur_pillar"]    { --tex: url('../img/blocks/purpur_pillar.png'); }
.mc-voxel[data-block="obsidian"]         { --tex: url('../img/blocks/obsidian.png'); }
.mc-voxel[data-block="crying_obsidian"]  { --tex: url('../img/blocks/crying_obsidian.png'); }
.mc-voxel[data-block="stone"]            { --tex: url('../img/blocks/stone.png'); }
.mc-voxel[data-block="cobblestone"]      { --tex: url('../img/blocks/cobblestone.png'); }
.mc-voxel[data-block="deepslate"]        { --tex: url('../img/blocks/deepslate.png'); }
.mc-voxel[data-block="dirt"]             { --tex: url('../img/blocks/dirt.png'); }
.mc-voxel[data-block="amethyst_block"]   { --tex: url('../img/blocks/amethyst_block.png'); }
.mc-voxel[data-block="chiseled"]         { --tex: url('../img/blocks/chiseled_stone_bricks.png'); }
.mc-voxel[data-block="diamond_ore"]      { --tex: url('../img/blocks/diamond_ore.png'); }
.mc-voxel[data-block="gold_ore"]         { --tex: url('../img/blocks/gold_ore.png'); }

/* Трава — единственный блок с разными гранями, как в игре */
.mc-voxel[data-block="grass"]        { --tex: url('../img/blocks/grass_block_side.png'); }
.mc-voxel[data-block="grass"] .t     { --tex: url('../img/blocks/grass_block_top.png'); }
.mc-voxel[data-block="grass"] .bt    { --tex: url('../img/blocks/dirt.png'); }

/* Свечение руд вешаем на ГРАНИ, а не на сам воксель.
   filter на элементе с preserve-3d принудительно схлопывает его в flat —
   именно поэтому руды раньше выглядели плоскими квадратами. box-shadow
   такого эффекта не даёт. */
.mc-voxel[data-block="diamond_ore"] .mc-face    { box-shadow: 0 0 14px rgba(92, 214, 208, 0.40); }
.mc-voxel[data-block="gold_ore"] .mc-face       { box-shadow: 0 0 14px rgba(214, 164, 62, 0.34); }
.mc-voxel[data-block="crying_obsidian"] .mc-face { box-shadow: 0 0 16px rgba(123, 47, 190, 0.48); }

/* Медленный дрейф — у каждого вокселя своя фаза, задаётся инлайн */
.mc-voxel[data-float] {
    animation: mcFloat var(--float-dur, 7s) var(--e-in-out) calc(var(--float-delay, 0) * 1s) infinite;
}

@keyframes mcFloat {
    0%, 100% { margin-top: calc(var(--s) / -2); }
    50%      { margin-top: calc(var(--s) / -2 - 10px); }
}

/* Огонь на вершине обелиска. Плоский квад в 3D-пространстве — для пятна
   света этого достаточно, а геометрию не утяжеляет. */
.mc-torch {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 76px;
    height: 76px;
    margin: -38px 0 0 -38px;
    pointer-events: none;
    background: radial-gradient(circle,
        rgba(255, 244, 214, 0.98) 0%,
        rgba(255, 200, 90, 0.75) 18%,
        rgba(255, 146, 28, 0.42) 38%,
        rgba(255, 96, 12, 0.16) 58%,
        transparent 74%);
    /* Позицию держим в translate, пульсацию — в scale.
       Если и то и другое писать в transform, keyframes затирают
       инлайновую позицию и все огни схлопываются в центр сцены. */
    translate: var(--fx, 0) var(--fy, 0) var(--fz, 0);
    animation: mcFlame var(--flame-dur, 1.6s) steps(3, end) var(--flame-delay, 0s) infinite;
    will-change: opacity, scale;
}

@keyframes mcFlame {
    0%, 100% { opacity: 0.8;  scale: 1; }
    33%      { opacity: 1;    scale: 1.18; }
    66%      { opacity: 0.62; scale: 0.9; }
}

/* ==========================================================================
   5. Ядро статуса сервера
   Тот самый вращающийся куб, теперь — сердце портала.
   ========================================================================== */
.eg-core {
    position: absolute;
    top: 50%;
    left: 50%;
    perspective: 900px;
    /* Поднято над чанком: внутри кучи блоков каркас терялся,
       а это индикатор статуса сервера — он обязан читаться сразу. */
    transform: translate(-50%, -50%) translateY(var(--core-lift, -104px));
    transform-style: preserve-3d;
    z-index: 5;

    --core: var(--ender-lit);
    --core-glow: rgba(168, 85, 247, 0.45);
}

.eg-core[data-status="online"]  { --core: var(--ok);   --core-glow: rgba(74, 222, 128, 0.5); }
.eg-core[data-status="offline"] { --core: var(--down); --core-glow: rgba(255, 77, 94, 0.45); }

.eg-core-cube {
    --s: 118px;
    --h: 59px;
    width: var(--s);
    height: var(--s);
    position: relative;
    transform-style: preserve-3d;
    animation: egCoreSpin 16s linear infinite;
}

@keyframes egCoreSpin {
    from { transform: rotateX(-24deg) rotateY(0deg); }
    to   { transform: rotateX(-24deg) rotateY(360deg); }
}

.eg-core-face {
    position: absolute;
    width: var(--s);
    height: var(--s);
    border: 2px solid var(--core);
    background:
        linear-gradient(135deg, color-mix(in srgb, var(--core) 20%, transparent), transparent 62%),
        rgba(8, 7, 10, 0.5);
    box-shadow:
        inset 0 0 56px color-mix(in srgb, var(--core) 26%, transparent),
        0 0 22px color-mix(in srgb, var(--core) 34%, transparent);
    transition: border-color var(--d-slow) var(--e-out-quart);
}

.eg-core-face::before {
    content: '';
    position: absolute;
    inset: 10px;
    border: 1px solid color-mix(in srgb, var(--core) 26%, transparent);
}

.eg-core-face.f  { transform: translateZ(var(--h)); }
.eg-core-face.bk { transform: rotateY(180deg) translateZ(var(--h)); }
.eg-core-face.r  { transform: rotateY(90deg)  translateZ(var(--h)); }
.eg-core-face.l  { transform: rotateY(-90deg) translateZ(var(--h)); }
.eg-core-face.t  { transform: rotateX(90deg)  translateZ(var(--h)); }
.eg-core-face.bt { transform: rotateX(-90deg) translateZ(var(--h)); }

/* Свет портала под ядром */
.eg-core::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 380px;
    height: 380px;
    transform: translate(-50%, -50%) translateZ(-90px);
    /* Мягкость даёт сам градиент: filter: blur() пришлось бы пересчитывать
       каждый кадр по всей площади пятна. */
    background: radial-gradient(circle,
        var(--core-glow) 0%,
        color-mix(in srgb, var(--core-glow) 45%, transparent) 32%,
        transparent 68%);
    animation: egCoreBreath 5s var(--e-in-out) infinite;
    pointer-events: none;
}

@keyframes egCoreBreath {
    0%, 100% { opacity: 0.55; }
    50%      { opacity: 1; }
}

/* Показание статуса — не карточка, а «приборная строка» */
.eg-readout {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    align-items: flex-start;
}

.eg-readout-status {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-family: var(--font-pixel);
    font-size: var(--t-micro);
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.eg-readout[data-status="online"]  .eg-readout-status { color: var(--ok); }
.eg-readout[data-status="offline"] .eg-readout-status { color: var(--down); }
.eg-readout[data-status="unknown"] .eg-readout-status { color: var(--ink-40); }

.eg-readout-status::before {
    content: '';
    width: 6px;
    height: 6px;
    background: currentColor;
    box-shadow: 0 0 10px currentColor;
}

.eg-readout[data-status="online"] .eg-readout-status::before {
    animation: egBlip 2s var(--e-in-out) infinite;
}

@keyframes egBlip {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.25; }
}

/* Счётчик — единственное место с пиксельным шрифтом крупно */
.eg-count {
    font-family: var(--font-pixel);
    font-size: clamp(1.6rem, 1rem + 2.2vw, 2.75rem);
    line-height: 1;
    color: var(--gold);
    font-variant-numeric: tabular-nums;
}

.eg-count small {
    font-size: 0.36em;
    color: var(--ink-40);
}

/* Адрес сервера */
.eg-addr {
    display: inline-flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.55rem 0.55rem 0.55rem 0.9rem;
    border: 1px solid var(--line);
    background: rgba(18, 16, 26, 0.7);
    font-family: var(--font-body);
    font-size: var(--t-small);
}

.eg-addr code {
    color: var(--portal);
    background: none;
    padding: 0;
    font-size: inherit;
    letter-spacing: 0.02em;
}

.eg-copy {
    border: 1px solid var(--line);
    background: transparent;
    color: var(--ink-60);
    font-family: var(--font-body);
    font-size: var(--t-small);
    font-weight: 600;
    padding: 0.25rem 0.7rem;
    cursor: pointer;
    transition: all var(--d-fast) var(--e-out-quart);
}

.eg-copy:hover {
    background: var(--gold);
    border-color: var(--gold);
    color: #1a1400;
}

.eg-copy.is-copied {
    background: var(--ok);
    border-color: var(--ok);
    color: #04220f;
}

/* ==========================================================================
   6. Навигация
   ========================================================================== */
.eg-nav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1030;
    padding: 1.25rem 0;
    transition: padding var(--d-norm) var(--e-out-quart),
                background var(--d-norm) var(--e-out-quart),
                border-color var(--d-norm) var(--e-out-quart);
    border-bottom: 1px solid transparent;
}

.eg-nav.is-stuck {
    padding: 0.7rem 0;
    background: rgba(8, 7, 10, 0.86);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom-color: var(--line);
}

.eg-nav .container {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.eg-brand {
    display: inline-flex;
    align-items: center;
    gap: 0.7rem;
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.05rem;
    letter-spacing: -0.02em;
    color: #fff;
    text-transform: uppercase;
}

.eg-brand:hover { color: var(--gold); }

.eg-brand-mark {
    width: 26px;
    height: 26px;
    flex: none;
    background: var(--gold);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6) inset;
    clip-path: polygon(0 26%, 50% 0, 100% 26%, 100% 74%, 50% 100%, 0 74%);
}

/*
 * Пульсирующее свечение знака.
 *
 * Раньше здесь анимировался filter: drop-shadow. Фильтр пересчитывается
 * каждый кадр, вместе с ним перерисовывается шапка, а под шапкой лежит
 * воксельная сцена из 242 граней — её браузер собирает заново тоже.
 * На слабой машине главная теряла на одном этом половину частоты:
 * 17 кадров против 37.
 *
 * Теперь свечение — отдельный слой позади знака, и мигает у него только
 * прозрачность. Её меняет композитор, перерисовки не требуется.
 */
.eg-brand {
    position: relative;
    z-index: 0;
}

.eg-brand::before {
    content: '';
    position: absolute;
    z-index: -1;
    left: -6px;
    top: 50%;
    width: 38px;
    height: 38px;
    margin-top: -19px;
    border-radius: 50%;
    background: radial-gradient(circle,
                rgba(255, 215, 0, 0.55), rgba(255, 215, 0, 0) 68%);
    pointer-events: none;
    opacity: 0.6;
    animation: egMarkGlow 4s var(--e-in-out) infinite;
}

@keyframes egMarkGlow {
    0%, 100% { transform: scale(0.72); }
    50%      { transform: scale(1.18); }
}

.eg-nav .nav-link {
    color: var(--ink-60);
    font-size: var(--t-small);
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    padding: 0.4rem 0;
    margin: 0 0.9rem;
    position: relative;
    transition: color var(--d-fast) var(--e-out-quart);
}

.eg-nav .nav-link::after {
    content: '';
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 1px;
    background: var(--gold);
    transform: scaleX(0);
    transform-origin: right;
    transition: transform var(--d-norm) var(--e-out-expo);
}

.eg-nav .nav-link:hover,
.eg-nav .nav-link.active { color: #fff; }

.eg-nav .nav-link:hover::after,
.eg-nav .nav-link.active::after {
    transform: scaleX(1);
    transform-origin: left;
}

.eg-nav .dropdown-menu {
    background: rgba(13, 11, 17, 0.98);
    backdrop-filter: blur(16px);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.35rem;
}

.eg-nav .dropdown-item {
    color: var(--ink-60);
    font-size: var(--t-small);
    border-radius: 2px;
    transition: all var(--d-fast) var(--e-out-quart);
}

.eg-nav .dropdown-item:hover {
    background: var(--ender-deep);
    color: #fff;
}

.eg-nav .navbar-toggler {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 0.35rem 0.55rem;
}

.eg-nav .navbar-toggler-icon {
    background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23FFD700' stroke-linecap='square' stroke-width='2' d='M4 8h22M4 15h22M4 22h22'/%3e%3c/svg%3e");
}

/* Онлайн в шапке */
.eg-nav-live {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    font-family: var(--font-pixel);
    font-size: var(--t-micro);
    letter-spacing: 0.1em;
    color: var(--ink-60);
    white-space: nowrap;
}

.eg-nav-live::before {
    content: '';
    width: 5px;
    height: 5px;
    background: var(--ok);
    box-shadow: 0 0 8px var(--ok);
    animation: egBlip 2s var(--e-in-out) infinite;
}

.eg-nav-live[data-status="offline"]::before {
    background: var(--down);
    box-shadow: 0 0 8px var(--down);
    animation: none;
}

/* ==========================================================================
   7. Герой
   Асимметрия: текст смещён от центра, сцена вылезает за контейнер.
   ========================================================================== */
.eg-hero {
    position: relative;
    min-height: 100svh;
    display: flex;
    align-items: center;
    /* Компактнее сверху и снизу: первый экран обязан вместить заголовок,
       слоган, кнопки И статус сервера — иначе он бесполезен. */
    padding: 6.5rem 0 3rem;
}

/* Фон героя из админки. Держим его приглушённым и гасим к низу, иначе
   картинка перебивает пустоту и весь замысел рассыпается. */
.eg-hero-bg {
    position: absolute;
    inset: 0;
    z-index: -1;
    background-size: cover;
    background-position: center;
    opacity: 0.22;
    mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
    -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 45%, transparent 92%);
    pointer-events: none;
}

.eg-hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
    gap: clamp(1rem, 4vw, 4rem);
    align-items: center;
    width: 100%;
}

/* Сцена выходит за правый край — приём «bleeding element» */
.eg-hero-scene {
    margin-right: calc(var(--gutter) * -1);
    margin-left: -6%;
}

.eg-hero-title {
    font-family: var(--font-display);
    font-size: var(--t-hero);
    font-weight: 800;
    line-height: 0.9;
    letter-spacing: -0.04em;
    color: #fff;
    margin: 0 0 1.1rem;
    max-width: 14ch;
}

/* Слово подъезжает снизу из-под маски.
   nowrap обязателен: без него браузер рвёт строку по дефису внутри слова,
   и «Эндер-мир» превращается в «Эндер-» / «мир». */
.eg-word {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    white-space: nowrap;
}

.eg-word > span {
    display: inline-block;
    transform: translateY(105%);
    animation: egWordUp 1s var(--e-out-expo) forwards;
    animation-delay: calc(0.2s + var(--i, 0) * 0.075s);
}

@keyframes egWordUp {
    to { transform: translateY(0); }
}

.eg-hero-title em {
    font-style: normal;
    color: var(--ender-lit);
}

.eg-slogan {
    font-size: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
    font-weight: 500;
    color: var(--gold);
    max-width: 38ch;
    margin: 0 0 0.75rem;
    opacity: 0;
    animation: egFadeUp 0.9s var(--e-out-expo) 0.6s forwards;
}

.eg-hero-text {
    color: var(--ink-60);
    max-width: 44ch;
    margin: 0 0 1.5rem;
    opacity: 0;
    animation: egFadeUp 0.9s var(--e-out-expo) 0.75s forwards;
}

.eg-hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    opacity: 0;
    animation: egFadeUp 0.9s var(--e-out-expo) 0.9s forwards;
}

.eg-hero-eyebrow {
    opacity: 0;
    animation: egFadeUp 0.7s var(--e-out-expo) 0.1s forwards;
    margin-bottom: 1rem;
    display: block;
}

@keyframes egFadeUp {
    from { opacity: 0; transform: translateY(24px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Индикатор прокрутки */
.eg-scroll-cue {
    position: absolute;
    left: var(--gutter);
    bottom: 2rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    opacity: 0;
    animation: egFadeUp 0.8s var(--e-out-expo) 1.3s forwards;
}

.eg-scroll-cue-line {
    width: 56px;
    height: 1px;
    background: linear-gradient(90deg, var(--ink-40), transparent);
    position: relative;
    overflow: hidden;
}

.eg-scroll-cue-line::after {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--gold);
    transform: translateX(-100%);
    animation: egCue 2.4s var(--e-in-out) infinite;
}

@keyframes egCue {
    0%   { transform: translateX(-100%); }
    60%  { transform: translateX(100%); }
    100% { transform: translateX(100%); }
}

/* ==========================================================================
   8. Секции, бегущая строка, карточки
   ========================================================================== */
.eg-section {
    position: relative;
    padding: clamp(4rem, 12vh, 9rem) 0;
}

.eg-section--tight { padding-block: clamp(2.5rem, 7vh, 5rem); }

.eg-head {
    display: grid;
    gap: 0.9rem;
    margin-bottom: clamp(2rem, 5vw, 3.5rem);
    max-width: 52ch;
}

/* Смещение от центра: заголовок начинается с колонки 2 */
.eg-head--offset { margin-left: 8.33%; }

.eg-rule {
    height: 1px;
    background: var(--line);
    border: 0;
    margin: 0;
}

/* Бегущая строка — ритм между секциями */
.eg-marquee {
    overflow: hidden;
    border-block: 1px solid var(--line);
    padding: 1.1rem 0;
    user-select: none;
}

.eg-marquee-track {
    display: flex;
    gap: 3rem;
    width: max-content;
    animation: egMarquee 38s linear infinite;
}

.eg-marquee span {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 3vw, 2.6rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    color: transparent;
    -webkit-text-stroke: 1px var(--ink-20);
    white-space: nowrap;
}

.eg-marquee span:nth-child(even) {
    color: var(--ender-lit);
    -webkit-text-stroke: 0;
    opacity: 0.5;
}

@keyframes egMarquee {
    to { transform: translateX(-50%); }
}

/* Карточка — плоская плита, а не «стекляшка» */
.eg-card {
    position: relative;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.75rem;
    height: 100%;
    overflow: hidden;
    transition: transform var(--d-norm) var(--e-out-quart),
                border-color var(--d-norm) var(--e-out-quart),
                background var(--d-norm) var(--e-out-quart);
}

.eg-card::after {
    content: '';
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 1px;
    background: linear-gradient(90deg, var(--ender-lit), transparent 70%);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--d-slow) var(--e-out-expo);
}

.eg-card:hover {
    transform: translateY(-3px);
    border-color: rgba(168, 85, 247, 0.4);
    background: var(--surface-2);
}

.eg-card:hover::after { transform: scaleX(1); }

.eg-card-index {
    font-family: var(--font-pixel);
    font-size: var(--t-micro);
    color: var(--ink-20);
    display: block;
    margin-bottom: 1.5rem;
}

.eg-card h3 { margin-bottom: 0.5rem; }

.eg-card p {
    color: var(--ink-60);
    font-size: 0.95rem;
    margin: 0;
}

/* Новости */
.eg-post {
    display: block;
    border-top: 1px solid var(--line);
    padding: 1.5rem 0;
    transition: background var(--d-norm) var(--e-out-quart);
}

.eg-post:hover { background: rgba(168, 85, 247, 0.05); }

.eg-post-row {
    display: grid;
    grid-template-columns: 6rem 1fr auto;
    gap: 1.5rem;
    align-items: baseline;
}

.eg-post-date {
    font-family: var(--font-pixel);
    font-size: var(--t-micro);
    color: var(--ink-40);
}

.eg-post-title {
    font-family: var(--font-display);
    font-size: clamp(1.15rem, 1rem + 1vw, 1.9rem);
    font-weight: 700;
    letter-spacing: -0.025em;
    color: #fff;
    line-height: 1.1;
    transition: color var(--d-fast) var(--e-out-quart), transform var(--d-norm) var(--e-out-quart);
}

.eg-post:hover .eg-post-title {
    color: var(--gold);
    transform: translateX(8px);
}

.eg-post-arrow {
    color: var(--ink-20);
    transition: color var(--d-fast) var(--e-out-quart), transform var(--d-norm) var(--e-out-quart);
}

.eg-post:hover .eg-post-arrow {
    color: var(--gold);
    transform: translateX(6px);
}

/* Кнопки */
.btn,
.eg-btn {
    --btn-bg: transparent;
    --btn-fg: var(--ink);
    --btn-bd: var(--line);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.85rem 1.6rem;
    border: 1px solid var(--btn-bd);
    border-radius: var(--radius);
    background: var(--btn-bg);
    color: var(--btn-fg);
    font-family: var(--font-body);
    font-size: var(--t-small);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    cursor: pointer;
    transition: transform var(--d-fast) var(--e-out-quart),
                background var(--d-fast) var(--e-out-quart),
                color var(--d-fast) var(--e-out-quart),
                border-color var(--d-fast) var(--e-out-quart);
    will-change: transform;
}

.btn-primary,
.eg-btn--gold {
    --btn-bg: var(--gold);
    --btn-fg: #1a1400;
    --btn-bd: var(--gold);
}

.btn-primary:hover,
.eg-btn--gold:hover {
    --btn-bg: #fff;
    --btn-bd: #fff;
    --btn-fg: #0b0910;
    color: #0b0910;
}

.btn-outline-primary:hover,
.eg-btn:hover {
    --btn-bd: var(--ender-lit);
    --btn-bg: rgba(168, 85, 247, 0.12);
    color: #fff;
}

/* Магнитная кнопка — смещение пишет JS */
[data-magnetic] {
    transform: translate3d(calc(var(--mx, 0) * 1px), calc(var(--my, 0) * 1px), 0);
}


/* ==========================================================================
   9. Мост к Bootstrap и плагинам
   Страницы магазина и форума приходят из плагинов — приводим их к системе.
   ========================================================================== */
.container { padding-inline: var(--gutter); max-width: 1360px; }

main.container.content { padding-top: 8rem; padding-bottom: 6rem; }

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: var(--ink);
}

.card-header, .card-footer {
    background: rgba(168, 85, 247, 0.06);
    border-color: var(--line);
}

.form-control, .form-select, .input-group-text {
    background: var(--void-2);
    border: 1px solid var(--line);
    color: var(--ink);
    border-radius: var(--radius);
    font-family: var(--font-body);
}

.form-control:focus, .form-select:focus {
    background: var(--void-2);
    border-color: var(--ender-lit);
    color: var(--ink);
    box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.22);
}

.form-control::placeholder { color: var(--ink-40); }

.table {
    --bs-table-color: var(--ink);
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--line);
    --bs-table-hover-color: #fff;
    --bs-table-hover-bg: rgba(168, 85, 247, 0.08);
}

.modal-content {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.modal-header, .modal-footer { border-color: var(--line); }
.btn-close { filter: invert(1) grayscale(1) brightness(1.7); }

.alert {
    border-radius: var(--radius);
    border: 1px solid var(--line);
    background: var(--surface);
    color: var(--ink);
}

.alert-success { border-color: rgba(74, 222, 128, 0.45); }
.alert-danger  { border-color: rgba(255, 77, 94, 0.45); }
.alert-warning { border-color: rgba(255, 215, 0, 0.45); }
.alert-info    { border-color: rgba(0, 212, 255, 0.45); }

.badge { border-radius: 2px; font-weight: 700; letter-spacing: 0.04em; }
.bg-primary { background: var(--ender) !important; }

.page-link {
    background: var(--surface);
    border-color: var(--line);
    color: var(--ink-60);
    border-radius: var(--radius);
}

.page-item.active .page-link {
    background: var(--ender);
    border-color: var(--ender-lit);
    color: #fff;
}

.progress {
    background: var(--void-2);
    border: 1px solid var(--line);
    border-radius: 2px;
    height: 4px;
}

.progress-bar { background: var(--ender-lit); }

.nav-tabs { border-bottom-color: var(--line); }

.nav-tabs .nav-link {
    color: var(--ink-40);
    border: 0;
    border-bottom: 1px solid transparent;
    font-size: var(--t-small);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.nav-tabs .nav-link.active {
    background: none;
    color: var(--gold);
    border-bottom-color: var(--gold);
}

.dropdown-menu {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
}

.dropdown-item { color: var(--ink-60); }
.dropdown-item:hover { background: var(--ender-deep); color: #fff; }

hr { border-color: var(--line); opacity: 1; }

code, pre {
    color: var(--portal);
    background: rgba(0, 212, 255, 0.06);
    border-radius: 2px;
    font-family: 'Space Grotesk', monospace;
}

blockquote {
    border-left: 2px solid var(--ender-lit);
    padding-left: 1rem;
    color: var(--ink-60);
}

/* Подвал */
.eg-footer {
    position: relative;
    z-index: 2;
    margin-top: auto;
    border-top: 1px solid var(--line);
    padding: clamp(3rem, 8vh, 5rem) 0 2rem;
    background: var(--void);
}

.eg-footer a { color: var(--ink-60); font-size: var(--t-small); }
.eg-footer a:hover { color: var(--gold); }

.eg-social {
    display: inline-grid;
    place-items: center;
    width: 40px;
    height: 40px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    color: var(--ink-60);
    transition: all var(--d-fast) var(--e-out-quart);
}

.eg-social:hover {
    border-color: var(--gold);
    color: var(--gold);
    transform: translateY(-2px);
}

/* ==========================================================================
   9б. Курсор
   Квадрат вместо стрелки — мир кубический. Ставится только при точном
   указателе; на тач-устройствах и при «уменьшить движение» JS его не
   создаёт, и родной курсор остаётся на месте.
   ========================================================================== */
/*
 * Системный курсор больше не прячем.
 *
 * Собственный курсор обновлялся по событиям мыши, а они идут через
 * основной поток: на загруженной странице точка отставала от настоящего
 * положения мыши. Системного курсора при этом не было, и отставание
 * читалось как подвисание мыши.
 *
 * Теперь курсор на месте и всегда точен, а кольцо ходит за ним ореолом.
 * Точка не нужна — её роль играет сам курсор.
 */
.eg-cursor-dot { display: none; }

/* На слабой машине убираем и кольцо */
.eg-lite .eg-cursor { display: none; }

.eg-cursor,
.eg-cursor-dot {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;
    pointer-events: none;
    margin-left: -0.5px;
    margin-top: -0.5px;
    transition: opacity var(--d-fast) var(--e-out-quart);
    will-change: transform;
}

/* Точка — ровно под пальцем, без задержки */
.eg-cursor-dot {
    width: 4px;
    height: 4px;
    margin: -2px 0 0 -2px;
    background: var(--gold);
}

/* Кольцо догоняет — отсюда ощущение веса */
.eg-cursor {
    width: 26px;
    height: 26px;
    margin: -13px 0 0 -13px;
    border: 1px solid var(--ink-40);
    transition: width var(--d-norm) var(--e-out-expo),
                height var(--d-norm) var(--e-out-expo),
                margin var(--d-norm) var(--e-out-expo),
                border-color var(--d-norm) var(--e-out-quart),
                background var(--d-norm) var(--e-out-quart),
                opacity var(--d-fast) var(--e-out-quart);
}

.eg-cursor.is-hot {
    width: 44px;
    height: 44px;
    margin: -22px 0 0 -22px;
    border-color: var(--gold);
    background: rgba(255, 215, 0, 0.10);
}

.eg-cursor.is-down {
    width: 18px;
    height: 18px;
    margin: -9px 0 0 -9px;
    border-color: var(--gold);
}

/* Сенсорные экраны: никакого кастомного курсора */
@media (hover: none), (pointer: coarse) {
    .eg-cursor,
    .eg-cursor-dot { display: none; }

    .eg-has-cursor,
    .eg-has-cursor * { cursor: auto; }
}

/* ==========================================================================
   10. Моторика
   ========================================================================== */
[data-reveal] {
    opacity: 0;
    transform: translateY(48px);
    transition: opacity var(--d-rev) var(--e-out-expo),
                transform var(--d-rev) var(--e-out-expo);
}

[data-reveal].is-in {
    opacity: 1;
    transform: none;
}

[data-reveal-stagger] > * {
    opacity: 0;
    transform: translateY(36px);
    transition: opacity var(--d-slow) var(--e-out-expo),
                transform var(--d-slow) var(--e-out-expo);
}

[data-reveal-stagger].is-in > * {
    opacity: 1;
    transform: none;
}

[data-reveal-stagger].is-in > *:nth-child(1) { transition-delay: 0.05s; }
[data-reveal-stagger].is-in > *:nth-child(2) { transition-delay: 0.12s; }
[data-reveal-stagger].is-in > *:nth-child(3) { transition-delay: 0.19s; }
[data-reveal-stagger].is-in > *:nth-child(4) { transition-delay: 0.26s; }
[data-reveal-stagger].is-in > *:nth-child(5) { transition-delay: 0.33s; }
[data-reveal-stagger].is-in > *:nth-child(6) { transition-delay: 0.40s; }

/* ==========================================================================
   11. Адаптив и доступность
   ========================================================================== */
@media (max-width: 991.98px) {
    .eg-hero-grid { grid-template-columns: 1fr; }

    .eg-hero-scene {
        margin: 0 auto 1rem;
        order: -1;
        max-width: 340px;
        width: 100%;
    }

    /* Ядро поднято меньше: на узкой сцене оно иначе уходит за верхний край */
    .eg-core { transform: translate(-50%, -50%) translateY(var(--core-lift, -72px)); }

    .eg-head--offset { margin-left: 0; }

    .eg-nav .navbar-collapse {
        background: rgba(13, 11, 17, 0.98);
        border: 1px solid var(--line);
        border-radius: var(--radius);
        margin-top: 0.75rem;
        padding: 0.85rem;
    }

    .eg-nav .nav-link { margin: 0; }
}

@media (max-width: 767.98px) {
    .eg-post-row { grid-template-columns: 1fr; gap: 0.5rem; }
    .eg-scroll-cue { display: none; }
    .eg-core-cube { --s: 84px; --h: 42px; }
    .eg-core { transform: translate(-50%, -50%) translateY(var(--core-lift, -58px)); }
    .eg-hero { padding-top: 5.5rem; }
    .eg-hero-scene { max-width: 280px; }
}

/* Клавиатурный фокус — заметный и в стиле */
:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 3px;
}

/* Уважаем «уменьшить движение»: гасим дрейф, вращение и параллакс,
   но оставляем весь контент на месте и видимым. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
    }

    .eg-core-cube { transform: rotateX(-24deg) rotateY(-34deg); }
    .mc-camera { transform: rotateX(-18deg) rotateY(24deg); }

    [data-reveal],
    [data-reveal-stagger] > * { opacity: 1; transform: none; }

    .eg-word > span { transform: none; }
    .eg-slogan, .eg-hero-text, .eg-hero-actions, .eg-hero-eyebrow, .eg-scroll-cue { opacity: 1; }
    .eg-dust { display: none; }
}

@media print {
    .eg-void, .eg-mesh, .eg-dust, .mc-scene, .eg-nav { display: none !important; }
    body { background: #fff; color: #000; }
}


/* --- Диалоги и поля выбора ------------------------------------------------
   Заголовок диалога размечен как h2, а заголовкам тема даёт витринный
   размер: в окне подтверждения покупки он занимал две строки и выдавливал
   содержимое вниз.                                                         */
.modal-title {
    font-size: var(--t-h3);
    line-height: 1.15;
    letter-spacing: -0.02em;
}

/* Bootstrap рисует галочки светлыми на светлом. На тёмном фоне темы
   обязательное согласие в корзине было почти не видно, и кнопка
   «Оплатить» молча не срабатывала.                                         */
.form-check-input {
    width: 1.15em;
    height: 1.15em;
    margin-top: 0.16em;
    background-color: var(--void-2);
    border: 1px solid var(--ink-40);
}

.form-check-input:hover { border-color: var(--ink-60); }

.form-check-input:checked {
    background-color: var(--ender-lit);
    border-color: var(--ender-lit);
}

.form-check-input:focus {
    border-color: var(--ender-lit);
    box-shadow: 0 0 0 3px rgba(168, 85, 247, 0.22);
}

.form-check-input:focus-visible {
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}

.form-check-label { cursor: pointer; }

/* Подвал диалога — flex. Длинный текст согласия прижимал кнопки к краю,
   поэтому отдаём ему отдельную строку.                                     */
.modal-footer .form-check {
    flex: 1 1 100%;
    margin-bottom: 0.6rem;
}


/* --- Лёгкий режим ---------------------------------------------------------
   Включается сам, когда замер частоты после загрузки показывает слабую
   машину. Гасим всё, что движется постоянно: пока идёт хоть одна такая
   анимация, браузер каждый кадр пересобирает воксельную сцену шапки.
   Сама сцена, текстуры и свечения остаются.                               */
.eg-lite .eg-brand::before,
.eg-lite .eg-nav-live,
.eg-lite .eg-scroll-cue-line,
.eg-lite .mc-torch,
.eg-lite .mc-flame,
.eg-lite .eg-core,
.eg-lite .eg-core-cube,
.eg-lite .eg-core-shell,
.eg-lite .eg-marquee-track,
.eg-lite .pd-spin,
.eg-lite .pd-flame {
    animation: none !important;
}

/* Пыль рисуется на канвасе каждый кадр — на слабой машине убираем */
.eg-lite .eg-dust { display: none; }

/* Свечение знака без пульса всё равно должно читаться */
.eg-lite .eg-brand::before { opacity: 0.65; }
