/* =====================================================================
   KONTAKT FÖYÜ — sonsuz tuval
   Sayfa kaymaz; kamera hareket eder. Fare ittiği yönün tersine kayar,
   tekerlek yakınlaştırır. Aynı projeye ait kareler birlikte ışığa gelir.
   ===================================================================== */

.canvas {
  position: fixed;
  inset: 0;
  overflow: hidden;
  z-index: var(--z-canvas);
  background: var(--ink);
  touch-action: none;
  cursor: none;                 /* imleci loupe devralır */
}
.canvas.is-dragging { cursor: none; }

/* JS yoksa tuval yok — düz ızgaraya düşer */
html:not(.js) .canvas { display: none; }

/* Kamera düzlemi. transform JS'ten gelir; transition YOK (her kare RAF). */
.canvas__plane {
  position: absolute;
  top: 0; left: 0;
  transform-origin: 0 0;
  will-change: transform;
}

/* Blok ölçüleri. --rows PHP'den gelir (mozaik paketleyicisi hesaplar). */
.canvas {
  --cell: 300px;
  --row:  92px;
  --cols: 7;
  --rows: 20;
  --cgap: 18px;
  --bw: calc(var(--cols) * var(--cell) + (var(--cols) - 1) * var(--cgap));
}

/* Tekrarlanan blok — sabit satırlı ızgara.
   ÖNEMLİ: blok dikdörtgen ve BOŞLUKSUZ olmalı. Kolon dengelemesi (CSS
   `columns`) kolonların altını tırtıklı bırakıyordu; tekrarlar arasında
   o tırtıklar birleşip ekranı kaplayan siyah bantlara dönüşüyordu.
   Yerleşim artık PHP'de elle paketleniyor (ka_mosaic), her hücre dolu. */
.canvas__block {
  position: absolute;
  top: 0; left: 0;
  width: var(--bw);
  display: grid;
  grid-template-columns: repeat(var(--cols), var(--cell));
  grid-template-rows: repeat(var(--rows), var(--row));
  gap: var(--cgap);

  /* Sağ ve alta bir oluk kadar dolgu: blok ölçüsü bir oluk büyür, kopyalar
     da o aralıkla dizilir. Böylece dikişteki boşluk blok içindekiyle aynı —
     tekrar noktası gözle ayırt edilemez. */
  box-sizing: content-box;
  padding: 0 var(--cgap) var(--cgap) 0;
}

/* Mozaik hücresi — konum ve ölçü PHP'den (--gc/--gr/--gw/--gh) */
.canvas .tile {
  grid-column: var(--gc, auto) / span var(--gw, 1);
  grid-row:    var(--gr, auto) / span var(--gh, 3);
  margin: 0;
  min-width: 0;
  min-height: 0;
}
.canvas .tile__frame {
  height: 100%;
  aspect-ratio: auto;   /* ölçüyü ızgara belirler, oran değil */
}

/* ---------------------------------------------------------------------
   KARE (tile)
   --------------------------------------------------------------------- */
.tile {
  display: block;
  break-inside: avoid;
  margin-bottom: var(--cgap);
  color: var(--paper);
  -webkit-tap-highlight-color: transparent;
}

.tile__frame {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: var(--ratio, 0.8);
  overflow: hidden;
  background: var(--ink-raise);
  transition: transform var(--d-slow) var(--ease);
}
.tile__frame img,
.tile__frame picture {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.tile__frame img {
  opacity: 0;
  transform: scale(1.06);
  transition: opacity var(--d-slow) var(--ease),
              transform var(--d-film) var(--ease),
              filter var(--d-base) var(--ease);
}
.tile__frame.is-loaded img,
.tile.is-loaded .tile__frame img { opacity: 1; transform: scale(1); }

.tile__blank {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(
    45deg, transparent, transparent 10px,
    rgba(242,239,234,0.025) 10px, rgba(242,239,234,0.025) 20px);
}

/* ---------------------------------------------------------------------
   ÖNİZLEME VİDEOSU
   Kapak karesinin ÜZERİNE oturur; kare altta poster olarak kalır, böylece
   video gelene kadar boşluk ya da sıçrama olmaz. Tek bir öğe dolaşıyor,
   hangi karonun içindeyse orada.
   --------------------------------------------------------------------- */
.tile__preview {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;                 /* kare üstünde, künye ve rozetin altında */
  opacity: 0;
  transition: opacity var(--d-base) var(--ease);
  pointer-events: none;
  background: var(--ink-raise);
}
.is-previewing .tile__preview { opacity: 1; }

/* Önizleme oynarken film rozeti susar — iki işaret birden gerekmiyor */
.is-previewing .tile__film { opacity: 0; }

/* Film rozeti — köşede minik safelight noktası */
.tile__film {
  position: absolute;
  top: 10px; right: 10px;
  display: grid;
  place-items: center;
  width: 24px; height: 24px;
  border-radius: 50%;
  background: rgba(10,10,11,0.55);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: var(--paper);
  opacity: 0.9;
}
.tile__film svg { margin-left: 1px; }

/* --- Künye --- */
.tile__meta {
  display: flex;
  gap: 0.7rem;
  margin-top: 0.7rem;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--d-base) var(--ease), transform var(--d-base) var(--ease);
}

/* Tuvalde künye karenin ÜSTÜNE biner — ızgara hücresi tam dolu kalsın diye.
   Altına yazılsaydı hücre taşar, mozaik dikişi açılırdı. */
.canvas .tile { position: relative; }
.canvas .tile__meta {
  position: absolute;
  left: 12px; right: 12px; bottom: 10px;
  margin: 0;
  z-index: 2;
  pointer-events: none;
}
.canvas .tile__frame::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 52%;
  background: linear-gradient(to top, rgba(10, 10, 11, 0.86), rgba(10, 10, 11, 0));
  opacity: 0;
  transition: opacity var(--d-base) var(--ease);
  pointer-events: none;
}
.canvas[data-zoom="mid"] .tile__frame::after,
.canvas[data-zoom="near"] .tile__frame::after { opacity: 1; }
.tile__no { color: var(--paper-ghost); flex-shrink: 0; }
.tile__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tile__title {
  font-family: var(--font-ui);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tile__sub { color: var(--paper-faint); }

/* Künye yalnız orta/yakın kademede görünür.
   Uzakta (kontakt föyü) sadece görüntü var — arşiv hissi. */
.canvas[data-zoom="mid"] .tile__meta,
.canvas[data-zoom="near"] .tile__meta { opacity: 1; transform: none; }

/* --- Sessiz kareler ---------------------------------------------------
   Projenin ikincil kareleri. Başlık altı kez tekrarlanmasın diye sessiz
   dururlar; üstlerine gelindiğinde adlarını söylerler. Böylece hiçbir kare
   isimsiz kalmaz ama ızgara da tekrarla dolmaz. */
.canvas .tile--mute .tile__meta,
.canvas[data-zoom="mid"] .tile--mute .tile__meta,
.canvas[data-zoom="near"] .tile--mute .tile__meta { opacity: 0; }
.canvas .tile--mute .tile__frame::after,
.canvas[data-zoom="mid"] .tile--mute .tile__frame::after,
.canvas[data-zoom="near"] .tile--mute .tile__frame::after { opacity: 0; }

/* Üstüne gelinen sessiz kare adını açar */
.canvas.is-focusing .tile--mute.is-hot .tile__meta,
.canvas.is-focusing .tile--mute.is-hot .tile__frame::after { opacity: 1; }

/* ---------------------------------------------------------------------
   ODAK — biri ışığa gelirse diğerleri kısılır.
   Aynı projeye ait kareler ("kin") birlikte aydınlanır.
   --------------------------------------------------------------------- */
.canvas.is-focusing .tile__frame img { filter: brightness(0.42) saturate(0.72); }
.canvas.is-focusing .tile.is-kin .tile__frame img { filter: none; }
.canvas.is-focusing .tile.is-kin .tile__frame { transform: scale(1.02); }
.canvas.is-focusing .tile.is-kin .tile__meta { opacity: 1; transform: none; }

/* Üstüne gelinen kare öne çıkar. z-index şart: ızgara kardeşleri sonradan
   boyandığı için büyüyen kare onların ALTINDA kalıp kırpılıyordu. */
.canvas.is-focusing .tile.is-hot { z-index: 4; }
.canvas.is-focusing .tile.is-hot .tile__frame {
  transform: scale(1.06);
  box-shadow: 0 26px 70px rgba(0, 0, 0, 0.55);
}

/* Sürüklerken odak yok — el hareketi öncelikli */
.canvas.is-dragging .tile__frame { transform: none !important; }
.canvas.is-dragging .tile__frame img { filter: none !important; }

/* ---------------------------------------------------------------------
   LOUPE — büyüteç imleci
   İnce halka. Kareye gelince açılır ve "aç" yazısını taşır.
   --------------------------------------------------------------------- */
.loupe {
  position: fixed;
  top: 0; left: 0;
  z-index: var(--z-cursor);
  width: 44px; height: 44px;
  margin: -22px 0 0 -22px;
  border: 1px solid var(--paper-ghost);
  border-radius: 50%;
  pointer-events: none;
  display: grid;
  place-items: center;
  mix-blend-mode: difference;
  transition: width var(--d-base) var(--ease),
              height var(--d-base) var(--ease),
              margin var(--d-base) var(--ease),
              border-color var(--d-base) var(--ease),
              opacity var(--d-fast) var(--ease);
}
html:not(.has-pointer) .loupe { display: none; }

.loupe__dot {
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--paper);
  transition: opacity var(--d-fast) var(--ease);
}
/* Etiket halkanın İÇİNDE kalmalı.
   Önceden white-space:nowrap ile tek satırdı: "VIEW PROJECT" 10px punto ve
   0.18em aralıkla ~94px sürüyordu, halka ise 68px — yazı iki yandan taşıp
   hata gibi görünüyordu. Artık sarıyor ("VIEW / PROJECT"), punto ve harf
   aralığı da halkaya göre kısıldı. */
.loupe__label {
  position: absolute;
  max-width: calc(100% - 14px);
  font-family: var(--font-mono);
  font-size: 8.5px;
  line-height: 1.3;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  color: var(--paper);
  opacity: 0;
  transition: opacity var(--d-fast) var(--ease);
  white-space: normal;
  overflow-wrap: anywhere;
}

/* 92px halka fotoğrafın üstünde fazla baskındı — imleç, kadrajın önüne
   geçmemeli. 68px etiketi hâlâ rahat alıyor ("VIEW PROJECT" tek satır)
   ama karenin kompozisyonunu örtmüyor. */
.loupe.is-over {
  width: 68px; height: 68px;
  margin: -34px 0 0 -34px;
  border-color: var(--paper-faint);
}
.loupe.is-over .loupe__dot   { opacity: 0; }
.loupe.is-over .loupe__label { opacity: 1; }

.loupe.is-grab { width: 30px; height: 30px; margin: -15px 0 0 -15px; }
.loupe.is-hidden { opacity: 0; }

/* ---------------------------------------------------------------------
   HUD — tuvalin alt şeridi. Zoom kademesi, görünüm anahtarı, ipucu.
   --------------------------------------------------------------------- */
.hud {
  position: fixed;
  inset: auto 0 0 0;
  z-index: var(--z-hud);
  padding: 0 var(--rail) clamp(1.1rem, 2.4vw, 2rem);
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--gut);
  pointer-events: none;
  background: linear-gradient(to top, rgba(10,10,11,0.72), rgba(10,10,11,0) 90%);
  padding-top: 5rem;
}
.hud > * { pointer-events: auto; }

.hud__hint {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--paper-ghost);
  transition: opacity var(--d-slow) var(--ease);
}
.hud.is-quiet .hud__hint { opacity: 0; }

/* Zoom kademesi göstergesi — üç çentikli minik cetvel */
.hud__zoom { display: flex; align-items: center; gap: 0.85rem; }
.hud__ticks { display: flex; align-items: center; gap: 5px; }
.hud__tick {
  width: 14px; height: 1px;
  background: var(--paper-ghost);
  transition: background var(--d-base) var(--ease), width var(--d-base) var(--ease);
}
.hud__tick.is-on { background: var(--paper); width: 22px; }
.hud__zoomlabel {
  font-family: var(--font-mono);
  font-size: var(--t-micro);
  letter-spacing: var(--track-wide);
  text-transform: uppercase;
  color: var(--paper-dim);
  min-width: 9ch;
}

/* Görünüm anahtarı — Tuval / Izgara */
.hud__views { display: flex; gap: 2px; }
.viewbtn {
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  color: var(--paper-ghost);
  border: 1px solid transparent;
  border-radius: 3px;
  transition: color var(--d-fast) var(--ease), border-color var(--d-fast) var(--ease);
}
.viewbtn:hover { color: var(--paper-dim); }
.viewbtn[aria-pressed="true"] { color: var(--paper); border-color: var(--line); }

/* Mobilde HUD yok — tuval zaten yok, gezinme alt sekmelerde,
   yoğunluk sıkıştırma jestinde. Ekranı kare doldursun. */
@media (max-width: 900px) {
  .hud { display: none; }
}

/* ---------------------------------------------------------------------
   SAHNE — tuval ile ızgara aynı sahnenin iki hâli
   --------------------------------------------------------------------- */
.stage[data-view="grid"] .canvas { display: none; }
.stage[data-view="canvas"] .stack { display: none; }

/* Mobilde tuval yok — yığın her iki görünümde de açık kalır.
   `!important` gerekli: yukarıdaki .stage[data-view="canvas"] .stack kuralı
   yığını gizliyor. Yoğunluk 5 dışında düzen masonry (block + column-count);
   kontakt föyü kademesinde eşit kareler için grid'e geçer. */
@media (max-width: 900px) {
  .stage .canvas { display: none !important; }
  .stage .stack  { display: block !important; }
  .stage .stack[data-dens="5"] { display: grid !important; }
}

/* ---------------------------------------------------------------------
   YIĞIN (stack) — tuvalin sakin kardeşi.
   Masaüstünde editoryal ızgara; mobilde sıkıştırmalı uygulama ızgarası.
   --------------------------------------------------------------------- */
/* Masaüstü: MASONRY. Kareler doğal oranlarını korur ve kolonlara sıkışarak
   akar — satırlar hizalanmadığı için altlarda boşluk kalmaz. Izgara (grid)
   hizalaması kısa hücrelerin altında kocaman boşluklar bırakıyordu.
   Okuma sırası kolon kolon olur; bir portfolyo dizini için doğru davranış. */
.stack {
  columns: var(--dens, 4);
  column-gap: var(--gut);
  padding: calc(var(--nav-h) + 2.5rem) var(--rail) 8rem;
}
.stack .tile {
  display: block;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  margin: 0 0 var(--gut);
}
.stack .tile { position: relative; }
.stack .tile__meta { opacity: 1; transform: none; }
.stack .tile { transition: z-index 0s; }

/* Hover süslemeleri yalnız gerçekten hover edebilen cihazlarda.
   Dokunmatikte :hover parmak değince tetiklenip kalkınca düşüyor; kare
   bir anlığına büyüyüp gölgeleniyor ve geri iniyordu — dokunuşun kendisi
   bir titremeye dönüşüyordu. */
@media (hover: hover) and (pointer: fine) {
  .stack .tile:hover { z-index: 4; }
  .stack .tile:hover .tile__frame {
    transform: scale(1.03);
    box-shadow: 0 26px 70px rgba(0, 0, 0, 0.5);
  }
}

/* Yığında da aynı kural: ikincil karelerin künyesi akışta yer kaplamaz,
   karenin üstüne biner ve yalnız hover'da belirir. Akışta dursaydı
   masonry kolonlarında düzensiz boşluklar açardı. */
.stack .tile--mute .tile__meta {
  position: absolute;
  left: 12px; right: 12px; bottom: 10px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
  z-index: 2;
}
.stack .tile--mute .tile__frame::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 52%;
  background: linear-gradient(to top, rgba(10, 10, 11, 0.86), rgba(10, 10, 11, 0));
  opacity: 0;
  transition: opacity var(--d-base) var(--ease);
  pointer-events: none;
}
@media (hover: hover) and (pointer: fine) {
  .stack .tile--mute:hover .tile__meta,
  .stack .tile--mute:hover .tile__frame::after { opacity: 1; }
}

@media (max-width: 1400px) { .stack { --dens: 3; } }
@media (max-width: 1100px) { .stack { --dens: 2; } }

/* ---------------------------------------------------------------------
   MOBİL — birinci öncelik.

   Eskiden mobil, eşit 1:1 karelerden oluşan bir uygulama ızgarasıydı.
   İçerikle uyuşmuyordu: bu arşivde kare formatlı tek bir görsel yok,
   karelerin %59'u dikey ve oran ortancası 0.67 (2:3). Her kare 1:1'e
   kırpılınca kadrajın yaklaşık yarısı gidiyor — moda fotoğrafında
   kompozisyonun kendisi yok oluyordu. Üstelik künye gizliydi; kullanıcı
   dokunmadan hiçbir işin adını göremiyordu.

   Şimdi: masaüstündeki gibi masonry. Kareler kendi oranında durur,
   ritim de buradan doğar — dikey ve yatay kareler sütunlarda kaydıkça
   düzen kendiliğinden hareketlenir. Künye kapak karelerinin altında
   her zaman okunur.
   --------------------------------------------------------------------- */
@media (max-width: 900px) {
  .stack {
    --dens: 2;
    display: block;
    column-count: var(--dens, 2);
    column-gap: 10px;
    transition: column-gap var(--d-base) var(--ease);
    padding: calc(56px + var(--safe-t) + 12px) 10px
             calc(var(--tabbar-h) + var(--safe-b) + 3rem);
  }
  .stack .tile { margin: 0 0 1.6rem; }
  .stack .tile__frame { aspect-ratio: var(--ratio, 0.8); transition: none; }

  /* Açılışta tam genişlik bir kare denendi, kaldırıldı: ilk işin kapağı
     dikey olduğunda ekranın tamamını kaplıyor ve altında portfolyo olduğuna
     dair hiçbir iz kalmıyordu — sayfa dizin değil açılış perdesi gibi
     okunuyordu. Kaldı ki oran, hangi işin ilk sırada olduğuna bağlıydı;
     sıra değişince görüntü de değişecekti. Belirli kapaklarda çalışan bir
     düzen düzen değil. Artık bütün kareler aynı masonry'de, kendi oranında:
     ilk ekranda birkaç iş birden görünüyor ve hiçbir yerde kırpma yok. */

  /* --- Künye karenin ÜZERİNDE --------------------------------------
     Akışta dururken üç satırlık metin blokları (numara + başlık + kategori)
     kolonları birbirinden itiyor, masonry'nin ritmini bozuyordu. Üste
     alınca ızgara saf görüntüye dönüyor, künye onun üzerinde yüzüyor.

     Tek satıra indirilmedi, tek BİLGİye indirildi: numara ve kategori·yıl
     mobilde düşürüldü, yalnız başlık kaldı. Ölçüm: 28 başlığın ortancası
     27 karakter, en uzunu 43; 170px kolonda tek satıra ~20 karakter sığıyor.
     Zorla tek satır olsaydı 18 başlık kesilecekti. İki satır serbest —
     üste bindiği için akışı zaten etkilemiyor. */
  .stack .tile { position: relative; }
  .stack .tile__meta {
    display: block;
    position: absolute;
    left: 12px; right: 12px; bottom: 11px;
    margin: 0;
    opacity: 1;
    transform: none;
    z-index: 2;
    pointer-events: none;
  }
  /* Numara ve kategori·yıl mobilde yok — ikisi de detay sayfasında ve
     arşivde duruyor. Burada tek iş var: hangi işe baktığını söylemek. */
  .stack .tile__no,
  .stack .tile__sub { display: none; }

  .stack .tile__title {
    white-space: normal;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-size: 0.8rem;
    line-height: 1.32;
    letter-spacing: 0.005em;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55), 0 2px 14px rgba(0, 0, 0, 0.45);
  }

  /* Okunurluk perdesi.
     İlk deneme (%42 yükseklik, altta 0.68) koyu karelerde yetiyordu ama
     açık tonlularda — beyaz stüdyo fonu, gökyüzü, aydınlık iç mekân —
     başlık kayboluyordu. Metnin durduğu ilk ~%30'luk şerit belirgin
     koyu, üstü hızla siliniyor: fotoğrafın gövdesi açıkta kalıyor,
     yalnız yazının arkası kapanıyor. */
  .stack .tile:not(.tile--mute) .tile__frame::after {
    content: '';
    position: absolute;
    inset: auto 0 0 0;
    height: 52%;
    background: linear-gradient(to top,
                rgba(10, 10, 11, 0.88) 0%,
                rgba(10, 10, 11, 0.66) 28%,
                rgba(10, 10, 11, 0.30) 58%,
                rgba(10, 10, 11, 0) 100%);
    opacity: 1;
    pointer-events: none;
  }

  /* Tek kolonda kare büyük — başlık da nefes alsın */
  .stack[data-dens="1"] .tile__meta { left: 16px; right: 16px; bottom: 14px; }
  .stack[data-dens="1"] .tile__title { font-size: 1rem; -webkit-line-clamp: 3; line-clamp: 3; }
  /* Masaüstünde ikincil kareler sessiz durur, üstlerine gelince adlarını
     söyler. Mobilde hover yok — orada sessiz kalsalar hiçbir zaman
     konuşamazlar. Bu yüzden varsayılan görünümde yalnız kapak kareleri var:
     her kare bir iş, her işin adı yazılı, 66 yerine 28 görsel. Telefonda
     hem daha okunur hem çok daha hafif.

     Tüm kareler kaybolmuyor — sıkıştırınca (yoğunluk 3 ve 5) arşiv açılıyor.
     Gizli kareler lazy yüklendiği için indirilmezler de. */
  .stack .tile--mute { display: none; }

  /* Sıkıştırma merdiveni: açtıkça büyür ve konuşur, kapattıkça
     arşive döner. Künye önce gider, sonra oran — en uçta kontakt föyü. */

  /* 1 — hikâye: tek kolon, tam kare */
  .stack[data-dens="1"] { column-gap: 0; padding-left: 12px; padding-right: 12px; }
  .stack[data-dens="1"] .tile { margin-bottom: 2.6rem; }

  /* 3 — sıkı masonry: oranlar durur, künye susar */
  .stack[data-dens="3"] { column-gap: 5px; padding-left: 5px; padding-right: 5px; }
  .stack[data-dens="3"] .tile { margin-bottom: 5px; }
  .stack[data-dens="3"] .tile--mute { display: block; }   /* arşiv açılır */
  .stack[data-dens="3"] .tile__meta { display: none; }
  .stack[data-dens="3"] .tile__frame::after { display: none; }   /* künye yok, perde de yok */

  /* 5 — kontakt föyü: kareler eşitlenir, arşiv hissi */
  .stack[data-dens="5"] {
    display: grid;
    column-count: auto;
    grid-template-columns: repeat(5, 1fr);
    gap: 2px;
    padding-left: 0; padding-right: 0;
  }
  .stack[data-dens="5"] .tile { margin: 0; }
  .stack[data-dens="5"] .tile--mute { display: block; }   /* tam kontakt föyü */
  .stack[data-dens="5"] .tile__frame { aspect-ratio: 1; }
  .stack[data-dens="5"] .tile__meta { display: none; }
  .stack[data-dens="5"] .tile__frame::after { display: none; }

  .stack.is-pinching { transition: none; }
}

.densmeter {
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: var(--z-overlay);
  padding: 0.7rem 1.1rem;
  border-radius: 999px;
  background: rgba(12,12,14,0.78);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  font-family: var(--font-mono);
  font-size: var(--t-meta);
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  color: var(--paper);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--d-fast) var(--ease);
}
.densmeter.is-on { opacity: 1; }

/* ---------------------------------------------------------------------
   AÇILIŞ — kareler banyodan çıkar gibi belirir
   --------------------------------------------------------------------- */
@keyframes ka-develop {
  from { opacity: 0; transform: translateY(14px) scale(0.985); filter: blur(6px); }
  to   { opacity: 1; transform: none; filter: none; }
}

/* Yalnız opaklık — transform'a DOKUNMAZ.
   ⚠ Tuvalin düzlemi ve blokları konumlarını satır-içi `transform` ile alır.
   CSS animasyonları satır-içi stili ezdiği için burada transform animasyonu
   kullanmak bütün blok kopyalarını üst üste yığar: ekranın çoğu boş kalır,
   tek blok gezinir. Bu dosyada .canvas__plane / .canvas__block üzerinde
   asla transform animasyonu tanımlama. */
@keyframes ka-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.canvas.is-ready .canvas__plane { animation: ka-fade-in var(--d-film) var(--ease) both; }
.stack.is-ready { animation: ka-develop var(--d-film) var(--ease) both; }

/* ---------------------------------------------------------------------
   HAREKET AZALTMA
   --------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .canvas { position: static; overflow: visible; height: auto; cursor: auto; }
  .canvas__plane { position: static; transform: none !important; }
  .canvas__block { position: static; }
  .canvas__block ~ .canvas__block { display: none; }
  .loupe, .hud__zoom { display: none; }
  .tile__meta { opacity: 1 !important; transform: none !important; }
  .canvas.is-focusing .tile__frame img { filter: none; }
}
