/* Shared skin for the live embeds. Every colour, radius and border comes from a
   custom property, so a host page restyles the whole thing by redefining these
   five tokens and nothing else. */
:root{
  --glz-ink:#fff;
  --glz-ink-2:rgba(255,255,255,.6);
  --glz-surface:rgba(255,255,255,.04);
  --glz-line:rgba(255,255,255,.22);
  --glz-accent:#fff;
  --glz-on-accent:#000;
}

/* ── catalogue ──────────────────────────────────────────────────── */
.glz-cat-bar{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:22px}
.glz-chip{
  font:inherit;font-size:13.5px;line-height:1;cursor:pointer;
  padding:10px 16px;border-radius:999px;
  border:1px solid var(--glz-line);background:transparent;color:var(--glz-ink-2);
  transition:color .25s,border-color .25s,background .25s;
}
.glz-chip:hover{color:var(--glz-ink);border-color:var(--glz-ink-2)}
.glz-chip.is-on{background:var(--glz-accent);border-color:var(--glz-accent);color:var(--glz-on-accent)}

.glz-cat-grid{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(178px,1fr));
  gap:clamp(10px,1.2vw,16px);
}
.glz-card{
  border:1px solid var(--glz-line);
  background:var(--glz-surface);overflow:hidden;display:flex;flex-direction:column;
  animation:glz-in .5s cubic-bezier(.16,1,.3,1) both;
  animation-delay:calc(var(--n) * 28ms);
  transition:border-color .3s,transform .5s cubic-bezier(.16,1,.3,1);
}
@keyframes glz-in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.glz-card{animation:none}}
.glz-card:hover{border-color:var(--glz-accent);transform:translateY(-3px)}
.glz-card-img{aspect-ratio:1;display:grid;place-items:center;padding:14px;
  background:radial-gradient(circle at 50% 40%,rgba(255,255,255,.07),transparent 70%)}
.glz-card-img img{width:100%;height:100%;object-fit:contain;
  transition:transform .6s cubic-bezier(.16,1,.3,1)}
.glz-card:hover .glz-card-img img{transform:scale(1.07)}
.glz-card-body{padding:0 14px 15px;display:flex;flex-direction:column;gap:5px;flex:1}
.glz-card-sku{margin:0;font-size:11px;letter-spacing:.06em;color:var(--glz-ink-2);
  font-variant-numeric:tabular-nums}
.glz-card h4{margin:0;font-size:13px;font-weight:600;line-height:1.32;color:var(--glz-ink)}
.glz-card-spec{margin:0;font-size:11.5px;color:var(--glz-ink-2);line-height:1.4;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.glz-card-price{margin:auto 0 0;padding-top:8px;font-size:14px;font-weight:700;
  color:var(--glz-accent);font-variant-numeric:tabular-nums}
.glz-cat-foot{margin:20px 0 0;font-size:13px;color:var(--glz-ink-2)}

/* ── ONE frame for every embed ────────────────────────────────────
   Before this there were two: a hairline browser window for the desktop
   demos and a moulded phone body — rounded corners, gloss, drop shadow
   and a notch — for the vertical ones. On a page built entirely from
   flat hairlines the phone was a foreign object: the only thing with a
   radius, the only thing with a highlight, the only thing pretending to
   be a physical product.

   Now both are the same construction and differ only in proportion:
   label bar and view. A vertical demo is a vertical frame, not a picture
   of a phone. Пояснение к рамке живёт в текстовой колонке кейса: под
   рамкой оно съедало две строки высоты у каждого демо на странице.

   --view is one number for the whole page, so every view down the page
   is exactly the same height and every frame is flush with the same
   right edge. --ar is the only per-frame variable. */
.glz-frame{
  --ar:1.6;
  display:flex;flex-direction:column;
  width:min(100%, calc(var(--view,440px) * var(--ar)));
  margin-left:auto;margin-right:0;
}
.glz-frame-dev{--ar:.5625}

/* Полоса непрозрачная. Она была прозрачной, и растровое поле страницы
   просвечивало прямо сквозь неё: ярлык и ссылка — 10.5 px поверх ряби —
   переставали читаться совсем. Полоса окна и не должна быть стеклянной,
   это чрома, а не содержимое. */
.glz-frame-bar{display:flex;align-items:center;gap:6px;padding:9px 13px;
  border:1px solid var(--glz-line);border-bottom:0;flex:none;background:#000}
.glz-frame-bar i{width:7px;height:7px;border:1px solid var(--glz-line);display:block;
  flex:none}
.glz-frame-bar span{margin-left:7px;font-size:12px;font-weight:500;
  letter-spacing:.04em;color:rgba(255,255,255,.72);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}

/* «открыть» справа в полосе: снимает потолок окна и заодно сообщает,
   что внутри настоящая страница, а не снимок экрана */
.glz-frame-open,.glz-frame-back{
  margin-left:auto;flex:none;font:inherit;font-size:12px;font-weight:600;
  letter-spacing:.04em;color:rgba(255,255,255,.72);white-space:nowrap;
  border:0;background:none;padding:0 0 1px;cursor:pointer;
  border-bottom:1px solid transparent;transition:color .25s,border-color .25s}
.glz-frame-open:hover,.glz-frame-back:hover{
  color:var(--glz-ink);border-bottom-color:var(--glz-ink)}
.glz-frame-open::after{content:" ↗"}
/* кнопка возврата появляется, только когда игра запущена, и тогда она
   стоит рядом со ссылкой, а не вместо неё */
.glz-frame-back{display:none;margin-left:14px}
.is-running .glz-frame-back{display:inline-block}

/* Запасной слой: лежит под встройкой и виден, только если та не
   отчиталась о готовности за четыре секунды. Пустая чёрная рамка на
   месте витрины хуже, чем её отсутствие. */
/* Слой состояния. display:none по умолчанию, а не просто «под
   встройкой»: иначе его текст лежит в дереве доступности и читается
   скринридером у каждой рабочей витрины — шесть сообщений об ошибке на
   странице, где всё загрузилось. */
.glz-frame-state{display:none;position:absolute;inset:0;z-index:0;
  flex-direction:column;align-items:center;justify-content:center;
  gap:12px;padding:24px;text-align:center;background:#000}
.glz-frame-view.is-pending > .glz-frame-state,
.glz-frame-view.is-dead > .glz-frame-state{display:flex}
.glz-frame-msg{margin:0;font-size:13px;line-height:1.5;color:var(--glz-ink-2);
  max-width:28ch}
.glz-frame-out{font-size:13px;font-weight:600;color:var(--glz-ink);
  text-decoration:none;border-bottom:1.5px solid var(--glz-ink);padding-bottom:2px}

/* Пока грузится — только сообщение, без выхода наружу: предлагать уйти
   на первой секунде нормальной загрузки незачем. И само сообщение
   появляется не сразу: у быстрой встройки «Загружается…» иначе успевает
   мигнуть и прочитаться как сбой. Секунда взята по замеру худшего
   случая — прыжка по якорю через полстраницы, когда наблюдатель
   срабатывает не мгновенно. */
.glz-frame-view.is-pending > .glz-frame-state{opacity:0;
  animation:glz-wait .3s ease-out 1s forwards}
.glz-frame-view.is-pending .glz-frame-out{display:none}
@keyframes glz-wait{to{opacity:1}}
@media(prefers-reduced-motion:reduce){
  .glz-frame-view.is-pending > .glz-frame-state{animation-duration:.01s}
}

/* Пока встройка не отчиталась, её не видно: у пустого iframe свой фон,
   и он закрыл бы сообщение собой. Мёртвую убираем совсем. */
.glz-frame-view.is-pending > iframe{visibility:hidden}
.glz-frame-view.is-dead > iframe,
.glz-frame-view.is-dead > img,
.glz-frame-view.is-dead > .glz-cover,
.glz-frame-view.is-dead > .glz-go{display:none}

.glz-frame-view{position:relative;width:100%;aspect-ratio:var(--ar);
  overflow:hidden;border:1px solid var(--glz-line);background:#000}
.glz-frame-view iframe{position:absolute;inset:0;width:100%;height:100%;
  border:0;display:block;z-index:1;background:#000}
.glz-frame-view video{position:absolute;inset:0;width:100%;height:100%;
  border:0;display:block;background:#000;object-fit:cover}
.glz-frame-view > img{position:relative;z-index:1;width:100%;display:block;
  will-change:transform}

.glz-frame-rail{height:3px;background:var(--glz-line);position:relative;
  overflow:hidden;flex:none}
.glz-frame-rail i{position:absolute;inset:0;display:block;background:var(--glz-ink);
  height:26%;will-change:transform}

/* ── the launch button over the game cover ──────────────────────── */
.glz-go{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  z-index:2;display:inline-flex;align-items:center;gap:9px;
  background:var(--glz-accent);color:var(--glz-on-accent);border:0;cursor:pointer;
  font:inherit;font-size:14px;font-weight:700;padding:13px 22px;
  white-space:nowrap;transition:transform .3s cubic-bezier(.16,1,.3,1)}
.glz-go:hover{transform:translate(-50%,-50%) scale(1.04)}
.glz-go-tri{width:0;height:0;border-left:9px solid currentColor;
  border-top:6px solid transparent;border-bottom:6px solid transparent;display:block}
.glz-cover{position:absolute;inset:0;z-index:1;width:100%;height:100%;
  object-fit:cover;display:block}

/* Рамка отзывается на курсор. Только transform и border-color: она
   поднимается, ничего не пересчитывается по раскладке. */
.glz-frame-view{transition:transform .5s cubic-bezier(.16,1,.3,1),
  border-color .5s ease-out}
.glz-frame:hover .glz-frame-view{transform:translateY(-6px);
  border-color:rgba(255,255,255,.45)}
@media(prefers-reduced-motion:reduce){
  .glz-frame-view{transition:border-color .2s}
  .glz-frame:hover .glz-frame-view{transform:none}
}

/* Вертикальная рамка узкая (222 px при окне 1024), и в её полосе не
   помещалось «ore rush · canvas 2d» вместе со ссылкой — ярлык терял
   41 px и обрывался многоточием. У ссылки остаётся стрелка: смысл
   держится на ней, слово было подпоркой. */
@media(max-width:1200px){
  .glz-frame-dev .glz-frame-open{font-size:0}
  .glz-frame-dev .glz-frame-open::after{font-size:13px}
}

/* На узком экране колонок больше нет, и потолок высоты уступает
   читаемости: вертикальная рамка берёт ширину, какую даёт экран. */
@media(max-width:900px){
  .glz-frame{width:100%;margin-inline:0}
  .glz-frame-dev{width:min(330px,72vw)}
}
