/* =====================================================================
   Плитки LofAC — 3D-поле, общее для hero, бенефитов, процесса и волонтёров.
   Движок перенесён из прототипа ~/projects/tile-flip.

   Словарь:
     ровное поле        — поток контента, всё одинаковое
     вспышка + кольца   — проверка людьми (0.6 / 0.4 / 0.2, как в макете)
     подъём, толщина, тень — вес настоящей вещи
     цветная изнанка    — за работой человек; перевёрнутая = печать получена
   ===================================================================== */

/* Яркость плитки — зарегистрированное число, чтобы её можно было плавно
   анимировать. Прозрачность нельзя: opacity схлопывает preserve-3d,
   поэтому яркость делаем цветом (color-mix с фоном). */
@property --fade{
  syntax:'<number>';
  inherits:true;
  initial-value:.1;
}
/* Во сколько раз выросла плитка (Visibility). От него же считаем радиус
   углов, чтобы при росте они не раздувались. */
@property --grow{
  syntax:'<number>';
  inherits:true;
  initial-value:1;
}

/* Вся сетка — одна 3D-сцена: браузер сортирует гнёзда, тени и плитки всех
   ячеек по реальной глубине, а не по порядку в DOM. Иначе две плитки
   в воздухе из соседних рядов перекрываются неправильно. */
.tiles{
  --size:90px;
  --gap:8px;
  --radius:8px;
  --thick:12px;
  --lift:56px;
  --persp:1100px;

  /* яркость лежащих плиток; у процесса в макете 0.6, у остальных 0.1 */
  --base:.1;

  --bg:#ffffff;
  --tile:#FAF9F6;
  --lit:#FAF9F6;
  --stroke:#F6F4EF;          /* обводка поднятой плитки в макете, 1px внутрь */
  --socket:#EFEDE6;
  --edge-hi:#F2EFE7;
  --edge-lo:#D6D2C4;

  /* В покое лицо плитки вровень с поверхностью, брусок утоплен в гнездо.
     +0.5px — чтобы лицо не делило плоскость с гнездом. */
  --rest-z:calc(var(--thick) / -2 + .5px);
  --shade-z:1.5px;

  --t-lift:200ms;
  --t-flip:620ms;
  --t-drop:460ms;
  --t-grow:900ms;
  --e-lift:cubic-bezier(.2,.9,.3,1);
  --e-flip:cubic-bezier(.45,.02,.2,1);
  --e-grow:cubic-bezier(.65,0,.25,1);

  position:relative;
  display:grid;
  grid-auto-rows:var(--size);
  grid-template-columns:repeat(var(--cols),var(--size));
  gap:var(--gap);
  perspective:var(--persp);
  perspective-origin:50% 50%;
  transform-style:preserve-3d;
}
/* Пол: сплошная плоскость цвета фона на уровне поверхности (Z=0), под гнёздами.
   Бруски в покое утоплены ниже, и без пола их торцы просвечивали бы в зазорах
   между плитками — у дальних от центра плиток перспектива выводит торец ровно
   в зазор. На яркости 0.1 это не видно, на 0.6 (процесс) — серые полоски. */
.tiles::before{
  content:'';
  position:absolute;inset:0;
  background:var(--bg);
  z-index:-1;
  pointer-events:none;
}

/* Ячейка — только группа в DOM, коробки у неё нет. Гнездо, тень и плитка —
   прямые grid-элементы одной клетки и прямые участники общей сцены.
   z-index решает порядок в одной плоскости и страхует, если сцену сплющит. */
.tiles .cell{
  display:contents;
  --lvl:0;
  --glow-dur:200ms;
  --glow-dly:0ms;
  --face:var(--tile);
}
.tiles .cell.lit,
.tiles .cell.hov{--face:var(--lit)}

.tiles .cell > *{
  grid-row:var(--r);
  grid-column:var(--c);
  position:relative;
  /* яркость = база или подсветка от вспышки/волны, что больше */
  --fade:max(var(--base), var(--lvl));
  --glow:--fade var(--glow-dur) ease var(--glow-dly);
}
.tiles .socket{z-index:0}
.tiles .tile{z-index:1}
.tiles .shade{z-index:2}
.tiles .cell.raised .tile{z-index:3}

.tiles[data-hover] .cell > *{cursor:pointer}

/* углубление */
.tiles .socket{
  border-radius:var(--radius);
  background:color-mix(in srgb, var(--socket) calc(var(--fade)*100%), var(--bg));
  box-shadow:
    inset 0 3px 4px rgba(72,63,46,calc(.20 * var(--fade))),
    inset 0 8px 10px -6px rgba(72,63,46,calc(.16 * var(--fade))),
    inset 0 -1px 0 rgba(255,255,255,calc(.9 * var(--fade)));
  transition:box-shadow var(--t-flip) linear, var(--glow);
}
.tiles .cell.up .socket,
.tiles .cell.lift .socket{
  box-shadow:
    inset 0 5px 6px rgba(72,63,46,calc(.34 * var(--fade))),
    inset 0 14px 16px -8px rgba(72,63,46,calc(.26 * var(--fade))),
    inset 0 -1px 0 rgba(255,255,255,calc(.9 * var(--fade)));
}

/* Падающая тень — отдельный плоский элемент (box-shadow крутился бы вместе
   с плиткой). Параметры из макета: drop shadow Y16, blur 16, spread −8,
   #CAC7BF 20%. Сдвиг и масштаб под перспективу досчитывает JS (--sh-*). */
.tiles .shade{
  pointer-events:none;
  margin:8px;
  border-radius:2px;
  background:#CAC7BF;
  filter:blur(8px);
  opacity:0;
  transform:translate3d(0,0,var(--shade-z)) scale(.94);
  transition:
    opacity calc(var(--t-drop) * .7) ease-in calc(var(--t-flip) * .5),
    transform calc(var(--t-drop) * .7) ease-in calc(var(--t-flip) * .5),
    var(--glow);
  will-change:transform,opacity;
}
.tiles .cell.up .shade{
  opacity:calc(.2 * var(--fade));
  transform:translate3d(var(--sh-x,0px), var(--sh-y,16px), var(--shade-z)) scale(var(--sh-s,1));
  transition:
    opacity var(--t-lift) var(--e-lift),
    transform var(--t-lift) var(--e-lift),
    var(--glow);
}

/* ---------- плитка: цикл hero (up / landing) ---------- */
/* translate и rotate — отдельные свойства, поэтому подъём и переворот
   разводятся по времени */
.tiles .tile{
  transform-style:preserve-3d;
  translate:0 0 var(--rest-z);
  rotate:y 0deg;
  transition:
    rotate var(--t-flip) var(--e-flip) 0ms,
    var(--glow);
}
.tiles .cell.up .tile{
  translate:0 0 var(--lift);
  rotate:y 180deg;
  transition:
    translate var(--t-lift) var(--e-lift) 0ms,
    rotate var(--t-flip) var(--e-flip) calc(var(--t-lift) * .55),
    var(--glow);
}
.tiles .cell.ax-x .tile{rotate:x 0deg}
.tiles .cell.ax-x.up .tile{rotate:x 180deg}
.tiles .cell.ccw.up .tile{rotate:y -180deg}
/* подъём без переворота (волонтёры: смотрят, но не сертифицируют) */
.tiles .cell.up.noturn .tile{rotate:0deg}

/* Посадка отдельной анимацией: падение с ускорением, касание и маленький
   отскок ВВЕРХ — overshoot в cubic-bezier проваливал плитку под гнездо. */
.tiles .cell.landing .tile{
  animation:tile-land var(--t-drop) linear calc(var(--t-flip) * .5) both;
}
.tiles .cell.landing.noturn .tile{animation-delay:0ms}
@keyframes tile-land{
  0%  {translate:0 0 var(--lift);                             animation-timing-function:cubic-bezier(.55,0,.9,.4)}
  70% {translate:0 0 var(--rest-z);                           animation-timing-function:cubic-bezier(.2,.6,.4,1)}
  85% {translate:0 0 calc(var(--rest-z) + var(--lift) * .05); animation-timing-function:cubic-bezier(.6,0,.8,1)}
  100%{translate:0 0 var(--rest-z)}
}

/* ---------- грани бруска ---------- */
.tiles .f{position:absolute;backface-visibility:hidden}

.tiles .front,
.tiles .back{inset:0;border-radius:var(--radius)}
.tiles .front{
  background:color-mix(in srgb, var(--face) calc(var(--fade)*100%), var(--bg));
  box-shadow:inset 0 0 0 1px color-mix(in srgb, var(--stroke) calc(var(--fade)*100%), transparent);
  transform:translateZ(calc(var(--thick) / 2));
}
.tiles .back{
  background:var(--accent);
  transform:rotateY(180deg) translateZ(calc(var(--thick) / 2));
}
.tiles .cell.ax-x .back{transform:rotateX(180deg) translateZ(calc(var(--thick) / 2))}
/* в макете у поднятых цветных плиток та же обводка #F6F4EF, у лежащих — нет */
.tiles .cell.up .back,
.tiles .cell.lift .back{box-shadow:inset 0 0 0 1px var(--stroke)}

/* торцы; инсет на радиус, чтобы скругления не давали щелей */
.tiles .eL,.tiles .eR{
  top:var(--radius);bottom:var(--radius);
  left:calc(50% - var(--thick) / 2);width:var(--thick);
  background:linear-gradient(
    to bottom,
    color-mix(in srgb, var(--edge-hi) calc(var(--fade)*100%), var(--bg)),
    color-mix(in srgb, var(--edge-lo) calc(var(--fade)*100%), var(--bg))
  );
}
.tiles .eR{transform:rotateY(90deg)  translateZ(calc(var(--size) / 2))}
.tiles .eL{transform:rotateY(-90deg) translateZ(calc(var(--size) / 2))}
.tiles .eT,.tiles .eB{
  left:var(--radius);right:var(--radius);
  top:calc(50% - var(--thick) / 2);height:var(--thick);
}
.tiles .eT{
  background:color-mix(in srgb, var(--edge-hi) calc(var(--fade)*100%), var(--bg));
  transform:rotateX(90deg)  translateZ(calc(var(--size) / 2));
}
.tiles .eB{
  background:color-mix(in srgb, var(--edge-lo) calc(var(--fade)*100%), var(--bg));
  transform:rotateX(-90deg) translateZ(calc(var(--size) / 2));
}

/* =====================================================================
   Состояния с результатом (бенефиты, процесс): подъём и переворот —
   независимые классы lift / flipped / nod, порядок ведёт JS (reconcile).
   ===================================================================== */
.tiles.g-states .tile{
  --grow:var(--grow-t, 1);
  scale:var(--grow);
  transition:
    translate var(--t-drop) cubic-bezier(.5,0,.75,1),
    rotate var(--t-flip) var(--e-flip),
    --grow var(--t-grow) var(--e-grow),
    var(--glow);
}
.tiles.g-states .cell.lift .tile{
  /* --nudge-* — компенсация перспективы у выросшей плитки (setGrow) */
  translate:var(--nudge-x,0px) var(--nudge-y,0px) var(--lift);
  transition:
    translate var(--t-lift) var(--e-lift),
    rotate var(--t-flip) var(--e-flip),
    --grow var(--t-grow) var(--e-grow),
    var(--glow);
}
/* «кивок» — короткий подскок в ответ на сообщение (Community) */
.tiles.g-states .cell.nod .tile{
  translate:0 0 calc(var(--lift) * .4);
  transition:
    translate 180ms var(--e-lift),
    rotate var(--t-flip) var(--e-flip),
    --grow var(--t-grow) var(--e-grow),
    var(--glow);
}
.tiles.g-states .cell.flipped .tile{rotate:y 180deg}

/* радиус и отступы торцов делим на --grow: scale раздул бы углы */
.tiles.g-states .front,.tiles.g-states .back{border-radius:calc(var(--radius) / var(--grow))}
.tiles.g-states .eL,.tiles.g-states .eR{top:calc(var(--radius) / var(--grow));bottom:calc(var(--radius) / var(--grow))}
.tiles.g-states .eT,.tiles.g-states .eB{left:calc(var(--radius) / var(--grow));right:calc(var(--radius) / var(--grow))}

.tiles.g-states .shade{
  transition:
    opacity calc(var(--t-drop) * .8) ease-in,
    transform calc(var(--t-drop) * .8) ease-in,
    var(--glow);
}
.tiles.g-states .cell.lift .shade{
  opacity:calc(.2 * var(--fade));
  transform:translate3d(var(--sh-x,0px), var(--sh-y,16px), var(--shade-z)) scale(var(--sh-s,1));
  transition:
    opacity var(--t-lift) var(--e-lift),
    transform var(--t-shade, var(--t-lift)) var(--e-lift),
    var(--glow);
}
.tiles.g-states .cell.nod .shade{
  opacity:calc(.12 * var(--fade));
  transform:translate3d(var(--sh-x,0px), var(--sh-y,16px), var(--shade-z)) scale(var(--sh-s,1));
  transition:opacity 180ms var(--e-lift), transform 180ms var(--e-lift), var(--glow);
}

/* =====================================================================
   Доказательства (процесс, шаг Apply) — тонкие пластины из-под плитки:
   этапы одной работы — эскиз → тона → цвет. Толщина становится буквальной:
   у человеческой работы есть слои процесса.
   ===================================================================== */
.tiles .plate{
  pointer-events:none;
  margin:calc(var(--size) * .055);   /* 5 px при плитке 90, 2 px на телефоне */
  border-radius:calc(var(--radius) * .75);
  opacity:0;
  transform:translate3d(0,0,calc(var(--lift) - var(--thick)));
  transition:
    transform 640ms var(--e-grow) var(--pd,0ms),
    opacity 200ms ease calc(var(--pd,0ms) + 460ms);
  box-shadow:inset 0 -2px 0 rgba(20,17,15,.07), 0 16px 16px -8px rgba(202,199,191,.45);
}
.tiles .cell.evidence .plate{
  opacity:1;
  transform:translate3d(calc(var(--i) * (var(--size) + var(--gap))), 0, calc(var(--lift) * .6));
  transition:
    transform 640ms var(--e-grow) var(--pd,0ms),
    opacity 160ms ease var(--pd,0ms);
}
.tiles .cell.evidence .plate.look{
  transform:translate3d(calc(var(--i) * (var(--size) + var(--gap))), 0, calc(var(--lift) * .6 + 18px));
  transition:transform 260ms var(--e-lift);
}
/* этапы одной работы — иллюстрации из assets/: эскиз → тона → цвет */
.tiles .plate{background:#F4F2EC center / cover no-repeat}
.tiles .plate.p0{background-image:url('assets/Step1.png')}
.tiles .plate.p1{background-image:url('assets/Step2.png')}
.tiles .plate.p2{background-image:url('assets/Step3.png')}

@media (prefers-reduced-motion:reduce){
  .tiles .tile,.tiles .shade,.tiles .socket,.tiles .plate{transition:none !important;animation:none !important}
}
