/* postcard — карточка поста: снимок, вписанный в ячейку мозайки.

   Карточка — маленькое окно: заливка и кольцо те же, что у рамки
   страницы (см. .page-window в main.css). Тени у карточки нет — тень
   на сайте одна, и мелким карточкам она не к лицу. Снимок встаёт
   внутрь кольца во всю карточку, и рамка становится рамкой
   фотографии.

   Форму карточке задаёт пропорция снимка: переменная --ratio (высота
   в единицах ширины) приходит от сервера в самой карточке, и
   aspect-ratio растягивает карточку ровно под снимок — ничего не
   обрезается. В ряду мозайки эта же пропорция служит весом при
   раздаче ширины (см. .mosaic__row в main.css), поэтому карточки
   в ряду выходят одной высоты.

   Скругление — общий калибр с сеткой профиля (--post-radius), поэтому
   карточки в ленте и в профиле одной формы.

   Снимка в шаблонной карточке нет: вместо него — фактура места,
   знак сайта вполсилы по центру, как у пустой шапки профиля. А по
   карточке ходит блик загрузки — наискось, из левого верхнего угла
   в правый нижний. Снимок непрозрачный и лежит выше штампа и блика:
   встанет — они скроются под ним, а postcard.js погасит анимацию. */

.postcard {
    /* Краски окна, записанные здесь по местным меркам: переменная
       вычисляется там, где объявлена, — см. «Кольцо» в themes.css. */
    --fill: var(--color-panel);
    --ring-color: var(--color-border);

    position: relative;
    overflow: hidden;
    border: 1px solid transparent;
    border-radius: var(--post-radius, 16px);
    background: linear-gradient(var(--fill), var(--fill)) padding-box,
                linear-gradient(var(--ring-color), var(--ring-color)) border-box;
}

/* Снимок лежит во всю карточку, внутри кольца: абсолют от паддинг-
   бокса, поэтому рамка остаётся видимой по краю. Он выше штампа и
   блика (z-index: 1): непрозрачный снимок накрывает их целиком,
   а пока его нет — сквозь прозрачный слой видны и штамп, и блик.
   Пустой адрес ничего не рисует и никуда не ходит: картинка просто
   убирается, и карточка остаётся в состоянии загрузки. */
.postcard__img {
    position: absolute;
    inset: 0;
    z-index: 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Пропорция карточки — пропорция снимка: снимок вписан целиком.
   --ratio несёт высоту в единицах ширины (0.75 у альбомного),
   а aspect-ratio ждёт наоборот — ширину на высоту, поэтому
   деление на единицу: 1 / 0.75 = 1.333 — коробка выходит альбомная.
   Пустая переменная (заглушка без снимка) даёт квадрат. */
.postcard {
    aspect-ratio: 1 / var(--ratio, 1);
}

.postcard__img[src=""] {
    display: none;
}

/* Сет — коллаж из кадров одной записи. Устроен как мозайка в
   миниатюре: кадры стоят колонками-стопками (--w — ширина колонки
   в долях карточки, --r — высота клетки в долях колонки), и сервер
   подобрал ширины так, что все колонки кончаются вровень — внутри
   карточки нет ни дыры, ни обрезки: каждый кадр заполняет свою
   ячейку целиком, вплоть до пикселя.

   Клетки стоят встык, без зазоров: прожилка между кадрами
   подсвечивала бы заливку карточки и рвала бы коллаж на лоскуты,
   а стык кадров сам по себе читается границей.

   Пропорция всей карточки (—ratio) и ширины колонок приходят от
   сервера, который считает их из пропорций кадров (см. set_layout
   в app.py): клиенту остаётся только растянуть клетки по долям. */
.postcard--set {
    display: flex;
}

/* Штамп и блик карточки коллажу не к лицу: штамп в центре коллажа
   смотрелся бы пятном поверх фотографий, а слой загрузки у коллажа
   свой — на каждой клетке. */
.postcard--set::before,
.postcard--set::after {
    content: none;
}

.postcard__setcol {
    position: relative;
    flex: var(--w) 1 0%;
    min-width: 0;
}

.postcard__cell {
    position: relative;
    height: 100%;
}

/* Слой загрузки клетки — тот же блик, что у всей карточки: полоса
   ходит наискось, пока снимок едет, и гасится классом is-loaded
   (см. postcard.js). Псевдоэлементы карточки заняты кольцом, поэтому
   блику хватает клетки. */
.postcard__cell::after {
    content: "";
    position: absolute;
    inset: -30%;
    background: linear-gradient(
        135deg,
        transparent 40%,
        var(--color-shine) 46%,
        var(--color-shine) 54%,
        transparent 60%
    );
    animation: postcard-shine 1.6s linear infinite;
    pointer-events: none;
}

.postcard__cell.is-loaded::after {
    display: none;
}

/* Счётчик кадров, не влезших в коллаж: «+N» в углу последней клетки.
   Краски — точь-в-точь капля выбора в доке: акцент на четверть
   поверх заливки панели. У капли фон прозрачный и тон проступает
   сквозь него, здесь смесь взята наглухо — плашка висит на снимке,
   и сквозь неё должно быть видно столько же, сколько сквозь каплю:
   ноль. Цвет знака — чернила, как у иконки поверх капли. */
.postcard__set-more {
    position: absolute;
    z-index: 2;
    right: 10px;
    bottom: 10px;
    padding: 3px 9px 4px;
    /* Не пилюля: любой радиус от полувысоты и больше браузер срезает
       до полувысоты, и плашка остаётся капсулой. Угол карточного
       калибра на такой высоте — 8px: прямые участки краёв видны, и
       скругление читается как у карточек, а не как у капсулы. */
    border-radius: 8px;
    background: var(--color-accent-soft);
    color: var(--color-ink);
    font-size: 12px;
    line-height: 1.4;
    pointer-events: none;
}

.postcard__set-more::before {
    content: "+";
    margin-right: 3px;
}

/* Заглушка — знак сайта по центру. Краску знак несёт свою (в файле
   он уже чернилами), а присутствие задаёт opacity — тот же рецепт,
   что у рисунка в пустой шапке. Размер фиксированный: на карточках
   любого размера это один и тот же тихий штамп, а не картинка,
   растянутая под ячейку. */
.postcard::before {
    content: "";
    position: absolute;
    inset: 0;
    background: url("/svg/logo.svg") center / 44px 44px no-repeat;
    opacity: 0.06;
    pointer-events: none;
}

/* Блик загрузки: по карточке наискось — из левого верхнего угла
   в правый нижний — идёт матовая полоса. Матовый, а не глянцевый:
   полоса широкая, с ровной вершиной и мягкими плечами, а свет в ней —
   чуть больше десятой доли чернил. Острой вершины нет, поэтому полоса
   читается разводом света, а не искрой. В тёмной теме это свет,
   в светлой — тень, и обе читаются как фактура места, а не поломка.

   Слой больше карточки на 30% с каждой стороны — запас ровно такой,
   чтобы полоса заходила в кадр и выходила из него целиком: на стыке
   циклов скачка нет, а плита под композитинг на пятую часть меньше.
   Анимация — один transform: её ведёт композитор, перерисовок нет. */
.postcard::after {
    content: "";
    position: absolute;
    inset: -30%;
    background: linear-gradient(
        135deg,
        transparent 40%,
        var(--color-shine) 46%,
        var(--color-shine) 54%,
        transparent 60%
    );
    animation: postcard-shine 1.6s linear infinite;
    pointer-events: none;
}

/* Ход — вдоль диагонали, на 48% собственной ширины слоя: с запасом
   в обе стороны, чтобы полоса уходила за кадр прежде, чем цикл
   начнётся заново. */
@keyframes postcard-shine {
    from {
        transform: translate(-48%, -48%);
    }

    to {
        transform: translate(48%, 48%);
    }
}

/* Снимок встал — блику подсвечивать нечего. */
.postcard.is-loaded::after {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    /* Без анимаций блика нет вовсе: заглушка остаётся тихим штампом. */
    .postcard::after {
        display: none;
    }

    .postcard__cell::after {
        display: none;
    }
}

.postcard__setcol {
    /* The server's widths sum to one; no flex redistribution. */
    flex: none;
    width: calc(var(--w) * 100%);
    align-self: stretch;
}
.postcard__cell {
    width: 100%;
    height: auto;
    aspect-ratio: 1 / var(--r, 1);
    overflow: hidden;
}

.postcard::after, .postcard__cell::after { animation: none; display: none; }

.postcard > .postcard__actions {
    display: none;
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 5;
    gap: 4px;
}
.postcard.is-owner > .postcard__actions { display: flex; }
