/**
 * Miqno — Kart CSS (TF-103 v2: TEK KANONİK KAYNAK).
 *
 * Bu dosya artık kart geometrisinin (boyut/konum/renk) TEK tanımıdır — index.html VE admin.html
 * BUNU DOĞRUDAN YÜKLER (kendi kopyalarını TUTMAZLAR). Canlı önizleme (index.html), sepet küçük
 * resmi (buildCardHtml -> .cdx-cardwrap) ve admin üretim render'ı (buildCardElement + html-to-image)
 * AYNI bu dosyadaki sınıfları, AYNI değerlerle kullanır. "Senkron nöbetçisi" testi artık gerekmez —
 * yerini "TEK dosya" nöbetçisi aldı (bkz. tests/tf103-canonical-css.test.js): index.html'de BU
 * sınıfların KENDİ TANIMI varsa test kırılır.
 *
 * index.html'e YALNIZ etkileşim-amaçlı (hover tilt vb., geometriyi ETKİLEMEYEN) küçük bir ek blok
 * kalabilir — o da açıkça "ETKİLEŞİM-SADECE, GEOMETRİ YOK" diye işaretlenmiştir.
 */

.tf-custom-card {
  position: relative;
  width: clamp(270px, 84vw, 340px);
  aspect-ratio: 560 / 800;
  container-type: inline-size;
  filter: drop-shadow(0 24px 44px rgba(0, 0, 0, 0.6));
  --tfc-text: #ffffff;
  --tfc-cloud: rgba(0, 0, 0, 0.82);
  /* TF-103 v2 — Oswald 700 "7" rakamının GERÇEK render genişliği ÷ font-size. Canvas measureText ile
     ölçüldü (50/100/200/302px boyutlarda test edildi, oran SABİT): 43.9/100 = 0.439. Oswald rakamları
     TABULAR DEĞİL (width("7") ≈ width("0") × 0.798) -> 1ch ("0" genişliği) KULLANILAMAZ, ~%20 fazla
     kaydırma yapardı. Font değişirse bu TEK değer yeniden ölçülüp burada güncellenir (başka yerde YOK).
     TEK BASAMAK grubu ("7" gibi) için doğrudur; çok basamaklı OVR'nin GÖRSEL merkezi grubun kendi
     shrink-to-fit genişliğine göre zaten .tfc-meta'nın align-items:center'ı ile otomatik ortalanır. */
  --tfc-digit7-ratio: 0.439;
  /* TF-103 v2 — ONAYLI: OVR+POZİSYON grubu TEK "knob" ile %20 büyütülür (12cqw × 1.20 = 14.4cqw). */
  --tfc-ovr-size: 14.4cqw;
  background: transparent;
}

.tfc-bg {
  /* VARSAYILAN ZEMİN (Kerem, 2026-08-22): kartın İÇİ default koyu olmalı.
     Eskiden koyu görünmesinin sebebi zeminin PLACEHOLDER GÖRSELİNE gömülü
     olmasıydı; placeholder saydam PNG'ye çevrilince kart bembeyaz kaldı.
     Zemin artık katmanın kendisinde: seçilen arka plan görseli/rengi bunun
     ÜSTÜNE biner, seçim yoksa kart yine de doğru görünür.
     Önizleme ve baskı AYNI dosyayı okuduğu için parite kendiliğinden korunur. */
  background-color: #23191F;
  position: absolute; inset: 0; z-index: 0;
  background-size: auto 100%; background-position: center; background-repeat: no-repeat;
  clip-path: polygon(50.0% 6.1%,60.0% 8.1%,70.5% 10.1%,75.9% 12.1%,86.2% 14.1%,89.5% 16.1%,89.6% 18.1%,89.6% 20.1%,89.6% 22.1%,89.6% 24.1%,89.6% 26.1%,89.6% 28.1%,89.6% 30.1%,89.6% 32.1%,89.6% 34.1%,89.6% 36.1%,89.6% 38.1%,89.6% 40.1%,89.6% 42.1%,89.6% 44.1%,89.6% 46.1%,89.6% 48.1%,89.6% 50.1%,89.6% 52.1%,89.6% 54.1%,89.6% 56.1%,89.6% 58.1%,89.6% 60.1%,89.6% 62.1%,89.6% 64.1%,89.5% 66.1%,89.6% 68.1%,89.5% 70.1%,89.5% 72.1%,89.5% 74.1%,88.6% 76.1%,85.2% 78.1%,81.1% 80.1%,70.2% 82.1%,60.0% 84.1%,51.8% 86.1%,50.0% 86.6%,49.8% 86.6%,47.9% 86.1%,39.8% 84.1%,29.6% 82.1%,18.6% 80.1%,14.5% 78.1%,11.1% 76.1%,10.0% 74.1%,10.0% 72.1%,10.0% 70.1%,10.0% 68.1%,10.0% 66.1%,10.0% 64.1%,10.0% 62.1%,10.0% 60.1%,10.0% 58.1%,10.0% 56.1%,10.0% 54.1%,10.0% 52.1%,10.0% 50.1%,10.0% 48.1%,10.0% 46.1%,10.0% 44.1%,10.0% 42.1%,10.0% 40.1%,10.0% 38.1%,10.0% 36.1%,10.0% 34.1%,10.0% 32.1%,10.0% 30.1%,10.0% 28.1%,10.0% 26.1%,10.0% 24.1%,10.0% 22.1%,10.0% 20.1%,10.0% 18.1%,10.0% 16.1%,14.1% 14.1%,23.9% 12.1%,29.6% 10.1%,41.4% 8.1%,49.6% 6.1%);
}

/* Temalar */
.tf-custom-card.theme-gold .tfc-bg { background: radial-gradient(circle at 50% 35%, rgba(212,175,55,0.25), transparent 70%), repeating-linear-gradient(45deg, rgba(20,20,20,0.9) 0px, rgba(20,20,20,0.9) 2px, rgba(10,10,10,0.95) 2px, rgba(10,10,10,0.95) 4px); }
.tf-custom-card.theme-neon .tfc-bg { background: radial-gradient(circle at 50% 35%, rgba(0,168,255,0.25), transparent 70%), radial-gradient(circle at 80% 80%, rgba(255,0,120,0.15), transparent 50%), linear-gradient(135deg, #051923 0%, #000c14 100%); background-size: cover; }
.tf-custom-card.theme-stadium .tfc-bg { background: radial-gradient(circle at 50% 20%, rgba(46,204,113,0.2), transparent 60%), linear-gradient(180deg, #0a2f1d 0%, #03140c 100%); }
.tf-custom-card.theme-carbon .tfc-bg { background: repeating-linear-gradient(135deg, rgba(30,30,30,0.8) 0px, rgba(30,30,30,0.8) 3px, rgba(15,15,15,0.9) 3px, rgba(15,15,15,0.9) 6px); }
.tf-custom-card.theme-cyber .tfc-bg { background: radial-gradient(circle at 50% 35%, rgba(224,86,253,0.25), transparent 70%), linear-gradient(135deg, #2c003e 0%, #12001a 100%); }

.tfc-frame-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; z-index: 5; pointer-events: none; }
.tf-custom-card.frame-silver .tfc-frame-img { filter: grayscale(1) brightness(1.75) contrast(0.95); }
.tf-custom-card.frame-copper .tfc-frame-img { filter: sepia(0.7) saturate(1.7) hue-rotate(-14deg) brightness(1.05); }
/* ÇERÇEVE ÖZEL RENGİ (frame-rainbow) — Kerem: eski sepia+hue-rotate filtresi saf/canlı renk (özellikle
   KIRMIZI) veremiyordu (turuncuya/soluk düşüyordu). Yeni yol: altın çerçevenin ÜZERİNE, çerçeve şekline
   MASKELİ renk katmanı + mix-blend-mode:color -> metalik PARLAKLIK (luminance) korunur, TON+DOYGUNLUK
   seçilen renge döner (doğru & canlı). Baskı paritesi: html-to-image maske-url + blend'i doğru basar
   (yerelde test edildi). frame-rainbow'da img'e artık FİLTRE YOK; renklendirmeyi tint katmanı yapar. */
.tf-custom-card.frame-rainbow .tfc-frame-img { filter: none; }
.tfc-frame-tint { display: none; }
.tf-custom-card.frame-rainbow .tfc-frame-tint {
  display: block; position: absolute; inset: 0; z-index: 5; pointer-events: none;
  background: var(--frame-color, #ff3d9a); mix-blend-mode: color;
  -webkit-mask-image: url(../web/custom-frame.png?v=2be83f99); mask-image: url(../web/custom-frame.png?v=2be83f99);
  /* HIZ: ayni pikseller KAYIPSIZ WebP'de %21 daha kucuk (scripts/frame-webp.py dogrular).
     PNG satiri USTTE kalir -> image-set desteklemeyen tarayici onu kullanir (fallback). */
  -webkit-mask-image: image-set(url(../web/custom-frame.webp?v=9ee0808a) type("image/webp"), url(../web/custom-frame.png?v=2be83f99) type("image/png"));
  mask-image: image-set(url(../web/custom-frame.webp?v=9ee0808a) type("image/webp"), url(../web/custom-frame.png?v=2be83f99) type("image/png"));
  -webkit-mask-size: contain; mask-size: contain;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
.tfc-cloud { position: absolute; left: 7%; right: 7%; top: 50%; height: 22%; z-index: 2; pointer-events: none; background: radial-gradient(ellipse 82% 62% at 50% 50%, var(--tfc-cloud), transparent 70%); }

/* TF-103 — foto sınırı ARTIK ARKA PLANLA (.tfc-bg) BİREBİR AYNI: eskiden sabit, dar bir kutuydu
   (top:13%; left:10%; width:80%; height:60%) -- çerçevenin gerçek iç (kalkan biçimli) penceresinden
   HER ZAMAN küçüktü, foto o kutuya SIĞDIRILIYOR, kutunun kendisi çerçevenin izin verdiği alanı
   KULLANMIYORDU (kullanıcı "resim hâlâ belli bir karede düşüyor" diye bildirdi -- foto BASE FIT'i
   zaten iyileştirilmişti ama SIĞACAĞI KUTU baştan beri gereğinden küçüktü). Artık .tfc-bg ile AYNI
   inset:0 + AYNI clip-path (kalkan poligonu) kullanır -- foto artık çerçevenin İZİN VERDİĞİ TÜM iç
   alana göre konumlanır/ölçeklenir (computeBaseScale/applyPhotoFitNow container.clientWidth/Height'ı
   OKUR, sabit bir yüzde DEĞİL -- bu nedenle JS tarafında değişiklik GEREKMEDİ, kutu büyüyünce foto
   otomatik olarak daha büyük/doğru alana sığar). TEK kanonik dosya: önizleme/sepet/admin AYNI
   sınırı kullanır (tf103-canonical-css.test.js kilitler).
   Alt maske de bu YENİ (tam kart yüksekliğine göre) koordinat sistemine göre YENİDEN ölçeklendi:
   isim satırı kart-Y ~56%-63%'te, statlar ~66%'da başlar -- maske artık BU MUTLAK kart-Y
   yüzdelerinde başlar/biter (konteyner artık kartın TAMAMI olduğu için container-göreli = kart-göreli).
   İkinci geçiş (Kerem, canlı geri bildirim: "biraz daha aşağıdan başlatalım") -- başlangıç %63'ten
   %67'ye, biti̇ş %70'ten %74'e ÇEKİLDİ (bant genişliği ~aynı, yalnız AŞAĞI kaydı): %67'ye kadar TAM
   opak (isim + gövdenin DAHA FAZLASI + stat etiket satırının ÇOĞU korunur), %74'te tam saydam
   (yalnız stat DEĞER satırını korumaya YETECEK KADAR, hâlâ dar bant). */
.tfc-photo-container { position: absolute; inset: 0; z-index: 3; overflow: hidden;
  clip-path: polygon(50.0% 6.1%,60.0% 8.1%,70.5% 10.1%,75.9% 12.1%,86.2% 14.1%,89.5% 16.1%,89.6% 18.1%,89.6% 20.1%,89.6% 22.1%,89.6% 24.1%,89.6% 26.1%,89.6% 28.1%,89.6% 30.1%,89.6% 32.1%,89.6% 34.1%,89.6% 36.1%,89.6% 38.1%,89.6% 40.1%,89.6% 42.1%,89.6% 44.1%,89.6% 46.1%,89.6% 48.1%,89.6% 50.1%,89.6% 52.1%,89.6% 54.1%,89.6% 56.1%,89.6% 58.1%,89.6% 60.1%,89.6% 62.1%,89.6% 64.1%,89.5% 66.1%,89.6% 68.1%,89.5% 70.1%,89.5% 72.1%,89.5% 74.1%,88.6% 76.1%,85.2% 78.1%,81.1% 80.1%,70.2% 82.1%,60.0% 84.1%,51.8% 86.1%,50.0% 86.6%,49.8% 86.6%,47.9% 86.1%,39.8% 84.1%,29.6% 82.1%,18.6% 80.1%,14.5% 78.1%,11.1% 76.1%,10.0% 74.1%,10.0% 72.1%,10.0% 70.1%,10.0% 68.1%,10.0% 66.1%,10.0% 64.1%,10.0% 62.1%,10.0% 60.1%,10.0% 58.1%,10.0% 56.1%,10.0% 54.1%,10.0% 52.1%,10.0% 50.1%,10.0% 48.1%,10.0% 46.1%,10.0% 44.1%,10.0% 42.1%,10.0% 40.1%,10.0% 38.1%,10.0% 36.1%,10.0% 34.1%,10.0% 32.1%,10.0% 30.1%,10.0% 28.1%,10.0% 26.1%,10.0% 24.1%,10.0% 22.1%,10.0% 20.1%,10.0% 18.1%,10.0% 16.1%,14.1% 14.1%,23.9% 12.1%,29.6% 10.1%,41.4% 8.1%,49.6% 6.1%);
  /* ALT DEGRADE MASKESI KALDIRILDI (Kerem, 2026-08-22: "Futbolcu kart temasinda
     preview'da fotograf alttan kesiliyor"). Foto konteyneri kartin %67'sinde
     solmaya baslayip %74'te BITIYORDU; cerceve ailelerinde bu %71 -> %78.5 idi.
     Yumusak bir gecis olmasi amaclanmisti ama gecis yalnizca ~%7 boyunda oldugu
     icin ekranda YUMUSAMA degil KESIK okunuyordu: kartin alt ucte biri fotografsiz
     kaliyor, altta kartin koyu zemini gorunuyordu (olculdu: 486px kartta foto
     ~382px'de bitiyor).
     Artik foto, cercevenin kendi clip-path penceresini TAMAMEN dolduruyor --
     Forge XI kartinin zaten yaptigi sey (o varyantlar mask-image:none). Alt
     bolgedeki yazilarin okunurlugu yazi halesiyle ve ISTEGE BAGLI alt golgeyle
     saglanir (bkz. tf-foto-isik.js -- gölge artik varsayilan KAPALI). */ }
.tfc-photo-container img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

/* FOTOGRAF PARLAKLIGI + ALT GOLGE (Kerem, 2026-08-20: "studio kismindaki fotograf
   parlakligi ve golge verebilme ozelligini ekleyelim siteye").

   NEDEN BU DOSYADA: onizleme ile BASKI kompoziti ayni stil dosyasini okur. Sadece
   index.html'e yazsaydik musterinin gordugu kart ile basilan kart farkli olurdu.

   NEDEN FOTO KONTEYNERININ ICINDE: golge katmani .tfc-photo-container'in COCUGU;
   boylece o konteynerin clip-path'ini ve maskesini KENDILIGINDEN paylasir. Her
   cerceve ailesinin kendi kirpmasi var (metalik/tahta/yeni temalar); golgeyi
   disarida ayri bir katman yapsaydik her aile icin kirpmayi TEKRAR yazmak
   gerekirdi ve biri unutulurdu.

   Varsayilanlar ETKISIZ: parlaklik 1, golge gucu 0. Degisken yazilmamis eski
   tasarimlar birebir eskisi gibi cikar (regresyon yok). */
.tfc-photo-container img { filter: brightness(var(--tfc-foto-parlak, 1)); }

/* === FOTOĞRAF STİLLERİ (lansman seti, 27 Ağustos 2026) ====================
   BURASI TEK TANIM YERİ. Canlı önizleme (tf-sayfa.js) ve baskı üreticisi
   (tf-card-render.js) fotoğraf KABINA aynı `data-foto-stil` niteliğini yazar;
   filtre dizgisi spec'te TAŞINMAZ. İki tarafın sessizce ayrılması ancak bu
   dosya değişirse mümkün, o da ikisini birden değiştirir. Kimlikler ve
   gerekçeleri: assets/js/tf-foto-stil.js.

   ÇÖZÜNÜRLÜKTEN BAĞIMSIZ: `filter` vektörel uygulanır -> 7x10 cm baskıda kart
   3-4x büyük çizilse de stil birebir aynı çıkar, ayrı bir raster üretilmez.

   PARLAKLIK KORUNUR: müşterinin kendi ayarladığı `--tfc-foto-parlak`
   (photoLight) her zincirin BAŞINDA duruyor. Stil onu EZMEZ, üstüne biner --
   aksi halde stil seçen müşterinin parlaklık ayarı sessizce kaybolurdu.
   `orijinal` için ayrı kural YOK: taban kural zaten o. */
.tfc-photo-container[data-foto-stil="canli"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) brightness(1.06) saturate(1.35) contrast(1.12); }
.tfc-photo-container[data-foto-stil="sicak"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) brightness(1.04) saturate(1.18) sepia(.22) hue-rotate(-8deg) contrast(1.04); }
.tfc-photo-container[data-foto-stil="vintage"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) brightness(1.06) sepia(.32) saturate(1.1) contrast(.92); }
.tfc-photo-container[data-foto-stil="nostaljik"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) brightness(1.08) saturate(.72) sepia(.12) contrast(.88); }
.tfc-photo-container[data-foto-stil="sinematik"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) brightness(.98) saturate(1.12) contrast(1.28); }
/* Rec.709 kanal ağırlıklı (0.2126/0.7152/0.0722) -- düz desature DEĞİL. */
.tfc-photo-container[data-foto-stil="sb"] img {
  filter: brightness(var(--tfc-foto-parlak, 1)) grayscale(1) brightness(1.04) contrast(1.18); }

/* ---- FX KATMANI: fade · vinyet · grain ----------------------------------
   Filtre zinciriyle yapılamayan üç iş. Kap fotoğrafın İÇİNDE ve onun
   kırpmasını paylaşıyor (aynı gerekçe .tfc-photo-shadow'da yazılı: dışarıda
   ayrı katman olsaydı her çerçeve ailesi için kırpmayı tekrar yazmak
   gerekirdi). Fotoğraf yokken de zararsız: kap boşsa hiçbir şey boyamaz. */
.tfc-foto-fx { position: absolute; inset: 0; pointer-events: none; z-index: 3; }
/* FADE = siyahları kaldırma. Vintage'ın "eski baskı" hissi bundan gelir:
   kontrastı düşürmek yerine tabana ince bir sıcak perde koyulur. */
.tfc-photo-container[data-foto-stil="vintage"] .tfc-foto-fx {
  background: linear-gradient(rgba(255,226,178,.13), rgba(255,226,178,.13)); }
.tfc-photo-container[data-foto-stil="nostaljik"] .tfc-foto-fx {
  background: linear-gradient(rgba(214,224,232,.16), rgba(214,224,232,.16)); }
/* SİNEMATİK = vinyet + ÇOK İNCE grain.
   Grain bir DOSYA değil, satır içi SVG feTurbulence: baskı ortamının taşıması
   gereken ek bir varlık olmasın ve iki tarafta aynı dokuyu üretsin.
   `baseFrequency` yüksek + opacity düşük -> "kirli" değil "film" hissi. */
.tfc-photo-container[data-foto-stil="sinematik"] .tfc-foto-fx {
  background-image:
    radial-gradient(ellipse at 50% 45%, rgba(0,0,0,0) 42%, rgba(0,0,0,.34) 100%),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.86' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='120' height='120' filter='url(%23n)' opacity='.19'/></svg>");
  background-size: 100% 100%, 120px 120px;
  background-repeat: no-repeat, repeat;
  mix-blend-mode: multiply; }
/* ---- TEMA KARTI (Gezi/Bebek/Gamer/Taraftar) ----
   Cerceve ve maskeler SPEC'ten inline degisken olarak gelir (--tfc-tint-maske,
   --tfc-bg-maske): her cercevenin kendi ic penceresi var, sinif tabanli kural
   yazsaydik cerceve basina CSS uretip baski ortamina tasimak gerekirdi.
   Uretimdeki clip-path futbolcu kalkanina gore cizilmis -- tema kartinda
   KAPATILIR, yerini cercevenin kendi maskesi alir. */
.tf-custom-card.tfc-tema .tfc-bg,
.tf-custom-card.tfc-tema .tfc-photo-container {
  clip-path: none;
  -webkit-mask-image: var(--tfc-bg-maske); mask-image: var(--tfc-bg-maske);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; }
/* Tema tint'i de SITENIN kendi kapisindan gecer: .tfc-frame-tint varsayilan
   display:none, yalniz .frame-rainbow (renk secilmis) ile acilir. Onceden tema
   dali tint'i KOSULSUZ ciziyordu -- musteri renk secmese bile baskida varsayilan
   altin tint vurabilirdi (olculdu: onizlemede katman olu, baskida canli). */
.tf-custom-card.tfc-tema.frame-rainbow .tfc-frame-tint {
  -webkit-mask-image: var(--tfc-tint-maske); mask-image: var(--tfc-tint-maske);
  -webkit-mask-size: 100% 100%; mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; }
/* Musterinin ekledigi yazilar.

   PUNTO KARTIN KENDI GENISLIGINE BAGLI (cqw). Onceden onizlemede JS'in yazdigi
   --tfyt-w kullaniliyordu; BASKIDA O DEGISKEN YOKTU ve punto 340px varsayimina
   dusuyordu -- yani ekranda dogru, baskida yanlis. Container sorgusu ikisini TEK
   kurala baglar: kart hangi olcekte cizilirse cizilsin yazi ayni orani tutar.

   container-type YALNIZ tema kartinda acilir; futbolcu kartinin 3B egilme/golge
   duzenine dokunulmaz. */
.tf-custom-card.tfc-tema { container-type: inline-size; }
.tf-custom-card.tfc-tema .tfyt-yazilar { position: absolute; inset: 0; z-index: 6; pointer-events: none; }
.tf-custom-card.tfc-tema .tfyt-yazi { position: absolute; display: block; text-align: center;
  white-space: nowrap; line-height: 1.05; font-weight: 800; color: #fff;
  font-size: calc(var(--tfyt-punto, .05) * 100cqw);
  text-shadow: 0 0 2px rgba(0,0,0,.7), 0 0 4px rgba(0,0,0,.48), 0 1px 2px rgba(0,0,0,.85), 0 2px 6px rgba(0,0,0,.45); }

/* === YAZI OKUNURLUK STİLİ (MOBİL FAZ 7) ===================================
   Kerem: "Fotoğraf üstünde okunurluk için; seçilen stil baskıya birebir
   yansır." Dört stil: Düz · Gölge · Kontur · Zemin.

   BURASI TEK TANIM YERİ. Canlı önizleme (tf-yeni-temalar.js yaziKatmani) ve
   baskı HTML'i (tf-card-render.js temaYazilariHtml) AYNI `tfyt-stil-*`
   sınıfını yazar; görünüm satır içi stille taşınmaz. İki tarafın sessizce
   ayrılması ancak bu dosya değişirse mümkün, o da ikisini birden değiştirir.

   ÖLÇÜ BİRİMİ `em`: gölge/kontur kalınlığı puntoyla ORANTILI büyür. `px`
   olsaydı 7×10 cm baskı çözünürlüğünde (kart ~3-4× büyük çiziliyor) kontur
   saç teli inceliğinde kalır, önizlemeyle baskı ayrılırdı.

   VARSAYILAN = GÖLGE: yukarıdaki taban kural zaten koşulsuz gölge yazıyordu.
   `stil` alanı taşımayan ESKİ tasarımlar okuyucuda 'golge'ye düşer -> görünüm
   bayt-aynı korunur. */
.tf-custom-card.tfc-tema .tfyt-yazi.tfyt-stil-duz { text-shadow: none; }
/* Gölge = tabandaki görünümün ADI. Kural yeniden yazılmaz (tek tanım), yalnız
   sınıf adı var olsun diye burada anılır: .tfyt-stil-golge tabanı devralır. */
.tf-custom-card.tfc-tema .tfyt-yazi.tfyt-stil-kontur {
  text-shadow:
    .055em 0 0 rgba(0,0,0,.92), -.055em 0 0 rgba(0,0,0,.92),
    0 .055em 0 rgba(0,0,0,.92), 0 -.055em 0 rgba(0,0,0,.92),
    .04em .04em 0 rgba(0,0,0,.92), -.04em .04em 0 rgba(0,0,0,.92),
    .04em -.04em 0 rgba(0,0,0,.92), -.04em -.04em 0 rgba(0,0,0,.92); }
/* ZEMİN: yazının arkasına koyu bir şerit. `-webkit-text-stroke` ya da
   `paint-order` KULLANILMIYOR -- html-to-image foreignObject çekiminde
   tarayıcıdan tarayıcıya değişiyor; padding + background her yerde aynı. */
.tf-custom-card.tfc-tema .tfyt-yazi.tfyt-stil-zemin {
  text-shadow: none; background: rgba(0,0,0,.55);
  padding: .08em .3em; border-radius: .16em; }

.tfc-photo-shadow { position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background: linear-gradient(to top,
    rgba(0,0,0,var(--tfc-golge-guc, 0)) 0%,
    rgba(0,0,0,0) var(--tfc-golge-yuk, 14%)); }
/* TF — Forge XI custom kart: foto ÇERÇEVENİN TAMAMINI kaplar ("sadece foto" kartı). İki değişiklik:
   (1) Alt degrade yumuşatma YOK (mask-image:none) -> ful görsel.
   (2) clip-path, çerçeve PNG'sinin GERÇEK dış kalkan silüeti — custom-frame.png alfasından YOĞUN
       örnekleme (her 4px bir satır, 800px boyda ~200 satır, alfa eşiği 200/255 -- KATI çerçeve
       sınırı, geçiş profili yalnız ~1px'de 0'dan 255'e sıçrıyor) ile türetildi, ardından düz
       (kolineer) noktalar sadeleştirildi (93 nokta). İLK deneme yalnız 44 satır + alfa>40 eşiği
       kullanmıştı -- düşük eşik çerçevenin YARI SAYDAM kenar tüyünü (antialiasing) yakalıyordu VE
       düz-çizgi enterpolasyonu keskin köşelerde/facetlerde ÇERÇEVENİN GERÇEK sınırının biraz DIŞINA
       taşıyordu (Kerem, canlı ekran görüntüsü — yeşil test fotoğrafıyla doğrulandı). Bu daha yoğun
       türetme hem BOŞLUK (üst denemenin fifa-clip'i, ~86.6%'da bitip alt uca inmiyordu) hem TAŞMA
       (ilk forgexi-clip denemesi) sorununu ÇÖZER — alt UÇ ~91.5%. TEK kanonik yer: önizleme+sepet+baskı. */
.forgexi-card .tfc-photo-container {
  -webkit-mask-image: none; mask-image: none;
  clip-path: polygon(48.75% 3%,46.79% 3.5%,44.64% 4%,42.32% 4.5%,39.29% 5%,34.29% 5.5%,28.93% 6%,27.86% 6.5%,25.36% 7.5%,22.5% 8.5%,21.25% 9%,19.64% 9.5%,16.07% 10.5%,13.93% 11%,11.43% 11.5%,8.39% 12%,5.54% 12.5%,5.54% 66.5%,3.75% 67.5%,3.39% 68%,3.57% 68.5%,3.57% 78.5%,4.29% 79%,5.18% 79.5%,6.61% 80.5%,7.5% 81%,8.21% 81.5%,9.11% 82%,9.82% 82.5%,10.71% 83%,11.43% 83.5%,12.32% 84%,15.36% 84.5%,20% 85%,23.75% 85.5%,29.82% 86.5%,32.32% 87%,34.64% 87.5%,36.79% 88%,38.75% 88.5%,44.11% 90%,45.54% 90.5%,47.14% 91%,48.57% 91.5%,51.43% 91.5%,55.71% 90%,57.5% 89.5%,59.11% 89%,65% 87.5%,70% 86.5%,72.86% 86%,75.89% 85.5%,79.64% 85%,84.29% 84.5%,88.04% 84%,88.93% 83.5%,89.64% 83%,90.54% 82.5%,91.25% 82%,92.14% 81.5%,93.57% 80.5%,94.46% 80%,96.61% 78.5%,96.61% 77%,96.79% 76.5%,96.79% 76%,96.61% 75.5%,96.79% 75%,96.79% 70%,96.61% 69.5%,96.79% 69%,96.79% 68%,96.25% 67.5%,94.46% 66.5%,94.46% 12.5%,91.25% 12%,88.21% 11.5%,85.54% 11%,83.21% 10.5%,81.25% 10%,79.46% 9.5%,77.86% 9%,76.43% 8.5%,73.93% 7.5%,72.86% 7%,71.61% 6.5%,70.71% 6%,65.71% 5.5%,60.54% 5%,57.32% 4.5%,55% 4%,53.04% 3.5%,51.25% 3%);
}
/* TF-103 direkt foto konumlandırma — metin/rozet katmanları (foto ÜSTÜNDE, z-index 6) sürükle/pinch
   olayını YUTMAMALI (kullanıcı isim/stat üzerinden tutup fotoğrafı sürükleyebilmeli) ve masaüstünde
   metin seçimi/imleç değişimi ile karışmamalı. Kanonik (Preview/Cart/Admin hepsinde zararsız/doğru). */
.tfc-meta, .tfc-name, .tfc-stats, .tfc-flag, .forgexi-card .fx-ov { pointer-events: none; user-select: none; -webkit-user-select: none; }

/* TF-103 v2 — TEK bayrak katmanı. Eski .tfc-nation (.tfc-meta içine gömülü, sol-üst) buildCardHtml'in
   ARTIK KULLANMADIĞI bir fosildi — canlı önizleme HER ZAMAN bu bağımsız, alt-orta .tfc-flag'ı
   kullanıyordu (bkz. "YETENEKLER altında, tam ortada"). Kart tipinden BAĞIMSIZ görünür konum. */
.tfc-flag { position: absolute; top: 77%; left: 50%; transform: translateX(-50%); width: 9cqw; z-index: 6; border-radius: 2px; overflow: hidden; box-shadow: 0 1px 5px rgba(0,0,0,0.6); line-height: 0; }
.tfc-flag img { width: 100%; height: auto; display: block; }

/* TF-103 v2 — ONAYLI Futbolcu Kartı düzen değişikliği: OVR+POZİSYON grubu TEK "knob" (--tfc-ovr-size)
   ile %20 büyütülür (12cqw -> 14.4cqw); pozisyon/gap ORANLARI (em, .tfc-meta'nın KENDİ font-size'ına
   göre) korunur, böylece grup TEK BİRİM olarak ölçeklenir.
   TF-103 baskı-parite (KESİN) — `left` ARTIK cqw İÇEREN calc DEĞİL, düz %: eski formül
   `calc(18% + 6.5cqw - (--tfc-digit7-ratio × 1em))` idi ve TAM OLARAK 18.178% üretiyordu
   (18% + 6.5% - 0.439×14.4%). Ama `6.5cqw` (raw container-query uzunluğu) Admin'in html-to-image
   ile YAKALADIĞI baskı PNG'sinde (izole SVG foreignObject) GÜVENİLMEZ çözülüyor -> OVR/POZİSYON
   bloğu yatayda KAYIYORDU (canlı önizleme cqw'yi doğru çözdüğü için "preview doğru, print kaymış").
   Aynı değeri (18.18%) cqw'siz, düz % ile veririz -> font-size cqw'nin (html-to-image'ın DOĞRU
   çözdüğü) aksine layout cqw'ye BAĞIMLILIK KALKAR; canlı önizleme konumu birebir AYNI kalır. */
.tfc-meta {
  position: absolute;
  top: 19.5%;
  font-size: var(--tfc-ovr-size);
  left: 18.18%;
  z-index: 6;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.0833333em;
  line-height: 0.95;
}
.tf-custom-card .tfc-meta .tfc-ovr { font-family: 'Oswald', sans-serif; font-size: 1em; font-weight: 700; color: var(--tfc-text); }
.tf-custom-card .tfc-meta .tfc-pos { font-family: 'Oswald', sans-serif; font-size: 0.5416667em; font-weight: 600; color: var(--tfc-text); letter-spacing: 0.04em; }

.tf-custom-card .tfc-name { position: absolute; top: 56%; left: 6%; right: 6%; text-align: center; font-family: 'Oswald', sans-serif; font-size: 8.4cqw; font-weight: 700; letter-spacing: 0.02em; color: var(--tfc-text); z-index: 6; text-transform: uppercase; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* TF-103 baskı-parite (KESİN) — stat aralığı ARTIK cqw margin DEĞİL, flexbox DAĞITIMI (space-evenly).
   TARİHÇE: aralık önce flex "gap: 2.7cqw" idi -> html-to-image'da çöküyordu; sonra "margin: 0 1.35cqw"
   yapıldı ("margin her motorda aynı davranır" varsayımıyla). Ama GERÇEK kök neden PROPERTY değil BİRİM:
   `cqw` (container-query uzunluğu), Admin'in html-to-image ile aldığı baskı PNG'sinde (izole, offscreen
   klonlanmış SVG foreignObject) GÜVENİLMEZ çözülüyor -> hem gap hem margin (hem de % margin) sıfıra
   çöküp stat sütunlarını YAPIŞTIRIYOR ("PACSHOPAS DRI DEFPHY"), font-size cqw ise doğru çözülüyor.
   ÇÖZÜM: aralığı HİÇBİR uzunluk birimi kullanmayan flexbox dağıtımıyla (justify-content: space-evenly)
   yap -- tarayıcı bunu kapsayıcının GERÇEK px genişliğinden hesaplar (cqw yok), html-to-image de canlı
   DOM da AYNI sonucu verir. Preview = Cart = Admin baskı PNG'si artık birebir aynı stat aralığı. */
/* Kapsayıcı ÇERÇEVENİN İÇ PENCERESİNE (custom-frame.png'de ~%12–%87.5) göre daraltıldı: eski
   left/right:5% (space-evenly ile) PAC ve PHY'yi altın çerçeveye BİNDİRİYORDU. left/right:16% ->
   statlar %16–%84 arasında yayılır (çerçeve içinde ~%4 pay), sütun boşlukları ~%2.9 (eski 2.7cqw
   margin ile neredeyse aynı) -> okunaklı, merkezî, çerçeveye binmez. space-evenly cqw'siz olduğu
   için canlı önizleme = baskı PNG'si (bkz. yukarıdaki html-to-image cqw notu). */
.tfc-stats { position: absolute; top: 66%; left: 16%; right: 16%; display: flex; justify-content: space-evenly; z-index: 6; }
.tf-custom-card .tfc-stats .tfc-stat { display: flex; flex-direction: column; align-items: center; line-height: 0.98; font-family: 'Oswald', sans-serif; }
/* TF-103 parite düzeltmesi — KÖK NEDEN: sayfanın genel ".tf-section--light .tf-stage span" kuralı
   (2 sınıf + 1 tip = özgüllük 0-2-1) "çıplak <span>" statik önizleme statlarını (#tfcPac vb.)
   EŞLEŞTİRİYORDU ve eski ".tfc-stat { color: var(--tfc-text) }" (1 sınıf = 0-1-0) BUNU KAZANAMIYORDU
   -- statlar müşterinin seçtiği rengi DEĞİL, sayfanın "açık bölüm" temasını gösteriyordu. OVR/POS/NAME
   (<div>) bu genel kuralın tip listesinde OLMADIĞI için "kazara" etkilenmiyordu -- kırılgan, gerçek bir
   koruma değildi. Admin/sepet render'ı (buildCardHtml -> ayrı, .tf-stage DIŞINDA bir DOM ağacı) bu genel
   kuralla HİÇ karşılaşmadığı için ZATEN doğruydu -- "print doğru, preview yanlış" raporunun tam nedeni.
   Çözüm: seçiciyi (rengi DEĞİL) üç sınıfa (0-3-0/0-3-1) çıkararak KESİN olarak kazanacak şekilde
   güçlendirmek -- gelecekte benzer bir genel sayfa kuralı eklenirse bile artık kırılmaz. TEK kanonik
   dosya: bu düzeltme Preview/Cart/Admin'in ÜÇÜNÜ DE otomatik kapsar (hepsi .tf-custom-card kullanır). */
.tf-custom-card .tfc-stats .tfc-stat,
.tf-custom-card .tfc-stats .tfc-stat .lbl,
.tf-custom-card .tfc-stats .tfc-stat span { color: var(--tfc-text); }
.tf-custom-card .tfc-stats .tfc-stat .lbl { font-size: 5.0cqw; font-weight: 600; letter-spacing: 0.01em; }
.tf-custom-card .tfc-stats .tfc-stat span:last-child { font-size: 6.4cqw; font-weight: 700; }
/* TF-103 parite düzeltmesi — gölge/parlama AZALTILDI (bulanıklık 14px->6px, dış opaklık .7->.4,
   iç temas gölgesi .95->.7/2px->1px): gerçek cihaz testi mevcut ağır gölgenin okunabilirlik payının
   ötesinde metni "bulanık/farklı fontmuş gibi" gösterdiğini doğruladı. Derinlik/okunabilirlik KORUNUR,
   yalnız yoğunluk düşürüldü. 65: Forge XI (fx-ov) İLE AYNI TEK kanonik gölge (fifa kartındaki TÜM
   yazı/rakamlara: isim + OVR/pozisyon + statlar) — iki katman ARTIK BİR DAHA SAPMASIN. */
/* Okunabilirlik (Kerem: "açık zeminde yazılar okunmuyor"): dar bir karartma HALESİ (0 0 3px)
   eklendi -> beyaz yazı açık fotoğraf/placeholder üstünde de ayrışır; alt katmanlar korundu.
   Baskı paritesi: aynı CSS baskı render'ında (html-to-image) da geçerli, önizleme=baskı. */
.tfc-meta, .tfc-name, .tfc-stats { text-shadow: 0 0 2px rgba(0,0,0,.72), 0 0 4px rgba(0,0,0,.5), 0 1px 2px rgba(0,0,0,.88), 0 2px 7px rgba(0,0,0,.45); }

.tf-custom-card.theme-gold { --tfc-text: #ffffff; --tfc-cloud: rgba(0,0,0,0.82); }
.tf-custom-card.theme-neon { --tfc-text: #2fe0ff; --tfc-cloud: rgba(120,210,255,0.85); }
.tf-custom-card.theme-stadium { --tfc-text: #46e08a; --tfc-cloud: rgba(150,255,200,0.82); }
.tf-custom-card.theme-carbon { --tfc-text: #ffffff; --tfc-cloud: rgba(220,220,225,0.85); }
.tf-custom-card.theme-cyber { --tfc-text: #ff5cf0; --tfc-cloud: rgba(255,170,250,0.82); }

/* Forge XI overlay */
/* TF-103 baskı-parite — DİKEY yazı aralığı ARTIK cqw `gap` DEĞİL, em `gap` (font-size üzerinden):
   `gap: cqw` (fitForgeTextBlock --fx-gap'i cqw yazıyordu) html-to-image baskı PNG'sinde ÇÖKÜP
   KERO/İSİM/SÖZ bloğunu farklı (daha sıkışık/alçak) konumlandırıyordu -> "Forge XI preview != print".
   font-size cqw html-to-image'da DOĞRU çözülür; bu yüzden aralığı fx-ov'un font-size'ına (cqw) bağlı
   `1em` ile veririz -> gap = font-size (cqw-çözülmüş px) -> canlı DOM = baskı PNG. fitForgeTextBlock
   artık --fx-gap yerine fx-ov'un font-size'ını (3.344cqw × scale) ayarlar (aynı orantılı küçültme). */
.forgexi-card .fx-ov { position:absolute;left:7%;right:7%;top:50%;bottom:7.6%;z-index:6;display:flex;flex-direction:column;justify-content:flex-end;align-items:center;font-size:3.344cqw;gap:1em;text-align:center;text-shadow:0 0 2px rgba(0,0,0,.72),0 0 4px rgba(0,0,0,.5),0 1px 2px rgba(0,0,0,.88),0 2px 7px rgba(0,0,0,.45); }
.fx-top,.fx-name,.fx-slogan { width:84%;line-height:1.12;white-space:nowrap;overflow:visible; }
.fx-top { font-family:Oswald,sans-serif;font-weight:600;letter-spacing:.26em;font-size:6.688cqw;color:var(--fx-top-color,#d4af37);text-transform:uppercase; }
.fx-top { margin-bottom:0; }
.fx-name { font-family:Oswald,sans-serif;font-weight:700;letter-spacing:.02em;font-size:16.72cqw;text-transform:uppercase;color:var(--fx-name-color,#f4f2ec); }
.fx-slogan { font-style:italic;font-size:5.3504cqw;color:var(--fx-slogan-color,#e7e4db); }
/* logo görünmez (opacity:0) ama yer korunur -- müşterinin onayladığı görünüm budur; bu, index.html'in
   ESKİ kopyasıyla zaten birebir aynıydı (fark yoktu) -- TF-103 v2'de artık TEK tanım olarak kalır. */
.forgexi-card .fx-logo { display: block; margin: 1.5cqw auto 0; width: 18cqw; opacity: 0; filter: drop-shadow(0 2px 6px rgba(0,0,0,.6)); transform: translateY(-1.5cqw); }

/* ===== ÇERÇEVE AİLELERİ (metalik / tahta / kemik / seker) =====
   Kanonik kayıt: assets/js/tf-card-render.js FRAME_FAMILIES (aile id + PNG asset yolu + etiket).
   Sınıf: .tf-custom-card.frame-family-<id>  — buildCardHtml (sepet/admin) VE index.html canlı
   önizleme (applyFrameFamily) AYNI sınıfı yazar. 'classic' aile SINIFSIZDIR (bugünkü DOM birebir).

   KURALLAR:
   - Aile PNG'leri custom-frame.png ile AYNI kanvas/siluet hizasında üretilir (scripts/
     gen_frame_families.py + scripts/prep_frame_asset.py) -> yukarıdaki kalkan clip-path'leri ve
     foto penceresi TÜM ailelerde geçerlidir; bu yüzden aşağıdaki bloklar başlangıçta BOŞTUR.
   - "Her frame kendine özgü" ayar (Kerem): bir ailenin İÇE OTURTMA penceresi / yazı konumu / alt
     maske değeri sapacaksa override BURAYA yazılır (örn. daha kalın çerçeve bandı olan bir ailede
     .tf-custom-card.frame-family-seker .tfc-stats { left: 18%; right: 18%; } gibi) — böylece
     Preview/Cart/Admin ÜÇÜ DE aynı override'ı otomatik alır (tek kanonik dosya kuralı korunur).
   - Renk stilleri (frame-silver/copper/rainbow filtre+tint) bu ailelere UYGULANMAZ — frameClasses
     classic dışı ailede stil sınıfı ÜRETMEZ; canlı önizleme de aile seçilince stil sınıflarını
     temizler. .tfc-frame-tint'in maskesi custom-frame.png'ye sabittir ve yalnız classic'te görünür. */
.tf-custom-card.frame-family-metalik .tfc-frame-img,
.tf-custom-card.frame-family-tahta .tfc-frame-img,
.tf-custom-card.frame-family-kemik .tfc-frame-img,
.tf-custom-card.frame-family-seker .tfc-frame-img { filter: none; }
/* Aileye özgü RENK (tint): klasik frame-rainbow tint mekanizmasının AYNISI (mix-blend-mode:color,
   parlaklık korunur, ton+doygunluk seçilen renge döner) — TEK farkla: maske O AİLENİN KENDİ PNG'sidir.
   Böylece seçilen renk, o çerçevenin materyal dokusu/silueti üzerinden uygulanır (Kerem: "renkleri de
   o frame tarzı üzerinden değişecek"). 4-sınıf özgüllük klasik maskeyi (custom-frame.png) güvenle ezer;
   baskı paritesi klasikle aynı (html-to-image maske+blend'i doğru basar — TF-103'te kanıtlı). */
.tf-custom-card.frame-family-metalik.frame-rainbow .tfc-frame-tint { -webkit-mask-image: url(../web/frames/frame-metalik.png?v=a5d1e139); mask-image: url(../web/frames/frame-metalik.png?v=a5d1e139); }
.tf-custom-card.frame-family-metalik.frame-rainbow .tfc-frame-tint { -webkit-mask-image: image-set(url(../web/frames/frame-metalik.webp?v=52feb5ff) type("image/webp"), url(../web/frames/frame-metalik.png?v=a5d1e139) type("image/png")); mask-image: image-set(url(../web/frames/frame-metalik.webp?v=52feb5ff) type("image/webp"), url(../web/frames/frame-metalik.png?v=a5d1e139) type("image/png")); }
.tf-custom-card.frame-family-tahta.frame-rainbow .tfc-frame-tint { -webkit-mask-image: url(../web/frames/frame-tahta.png?v=2d86fc5b); mask-image: url(../web/frames/frame-tahta.png?v=2d86fc5b); }
.tf-custom-card.frame-family-kemik.frame-rainbow .tfc-frame-tint { -webkit-mask-image: url(../web/frames/frame-kemik.png?v=8d8bac49); mask-image: url(../web/frames/frame-kemik.png?v=8d8bac49); }
.tf-custom-card.frame-family-seker.frame-rainbow .tfc-frame-tint { -webkit-mask-image: url(../web/frames/frame-seker.png?v=f58e2a5c); mask-image: url(../web/frames/frame-seker.png?v=f58e2a5c); }
/* AİLE BAŞINA KARIŞIM REÇETESİ (Kerem: "ana renkleri TAM verip ara renklerde de iyi sonuç").
   TEK reçete her materyalde doğru sonuç VERMEZ: color-blend taban PARLAKLIĞI korur -> AÇIK
   materyalde (kemik fildişi, tahta beyaz-ahşap: taban ~%90 parlak) saf kırmızı bile PASTEL pembeye
   yıkanır. Bu iki AÇIK ailede reçete MULTIPLY: beyaza yakın taban × seçilen renk ≈ RENGİN KENDİSİ
   (ana renk TAM; ara tonlar da hue'yu birebir korur çünkü taban nötr), bevel gölgeleri/damarlar
   çarpımdan koyulaşarak İÇİNDEN görünür (boyanmış kemik/ahşap etkisi). METAL aileler (metalik krom,
   seker rose — geniş/orta parlaklık aralığı) classic altın ile AYNI color-blend'de KALIR: metalik
   spekülar karakteri ancak parlaklık korunarak yaşar (lacivert-krom kanıtıyla doğrulandı; multiply
   renkli rose tabanda ara renkleri kirletirdi — nötr olmayan taban hue'yu bozar). */
.tf-custom-card.frame-family-kemik.frame-rainbow .tfc-frame-tint,
.tf-custom-card.frame-family-tahta.frame-rainbow .tfc-frame-tint { mix-blend-mode: multiply; }
/* SEKER — rose taban RENKLİDİR: tek color-blend SOLUK kalır (taban çok parlak), multiply ise kanal
   dengesizliğinden SOĞUK ara renkleri kirletir (rose'un düşük G/B kanalı yeşil/maviyi çamurlaştırır —
   renk matrisi v2 ile ölçüldü). Reçete: renk seçiliyken TABAN çerçeve görseli NÖTR karartılır
   (brightness — tüm kanallara EŞİT etki, hue bozmaz; yalnız frame-rainbow durumunda, DOĞAL hâl
   etkilenmez), üzerine standart color-blend tint gelir -> seçilen ton ORTA parlaklıkta yeniden
   kurulur: ana renkler TAM, soğuk ara renkler TEMİZ, krem iç bant koordineli tonda kalır. */
.tf-custom-card.frame-family-seker.frame-rainbow .tfc-frame-img { filter: brightness(0.68); }
/* SPEKÜLAR PARLAMA KATMANI (Kerem: "koyu renk seçeneklerinde parlak noktalar belirgin kalmalı" —
   kemik/tahta/seker). multiply (ve koyu tint) spekülar parlamaları boyar; bu katman ailenin KENDİ
   görselinden YALNIZ EN PARLAK noktaları izole edip tint'in üstüne screen ile geri ekler. İzolasyon:
   AYNI görsel 4 kez üst üste multiply (background-blend-mode) = L^4 güç eğrisi -> parlak gövde
   bastırılır, spekülar sivrilir; ardından grayscale (renk sızmasın) + brightness/contrast ile eşik
   keskinleştirilir. YALNIZ renk seçiliyken (frame-rainbow) devrededir — doğal hâl zaten parlaktır.
   metalik/classic'te gerek yok: color-blend parlaklığı zaten korur. */
.tfc-frame-shine { display: none; }
.tf-custom-card.frame-family-kemik.frame-rainbow .tfc-frame-shine,
.tf-custom-card.frame-family-tahta.frame-rainbow .tfc-frame-shine,
.tf-custom-card.frame-family-seker.frame-rainbow .tfc-frame-shine {
  display: block; position: absolute; inset: 0; z-index: 5; pointer-events: none;
  mix-blend-mode: screen;
  background-position: center; background-size: contain; background-repeat: no-repeat;
  background-blend-mode: multiply, multiply, multiply;
  filter: grayscale(1) brightness(0.8) contrast(2.4);
  opacity: 0.8;
}
.tf-custom-card.frame-family-kemik.frame-rainbow .tfc-frame-shine { background-image: url(../web/frames/frame-kemik.png?v=8d8bac49), url(../web/frames/frame-kemik.png?v=8d8bac49), url(../web/frames/frame-kemik.png?v=8d8bac49), url(../web/frames/frame-kemik.png?v=8d8bac49); }
.tf-custom-card.frame-family-tahta.frame-rainbow .tfc-frame-shine { background-image: url(../web/frames/frame-tahta.png?v=2d86fc5b), url(../web/frames/frame-tahta.png?v=2d86fc5b), url(../web/frames/frame-tahta.png?v=2d86fc5b), url(../web/frames/frame-tahta.png?v=2d86fc5b); }
.tf-custom-card.frame-family-seker.frame-rainbow .tfc-frame-shine { background-image: url(../web/frames/frame-seker.png?v=f58e2a5c), url(../web/frames/frame-seker.png?v=f58e2a5c), url(../web/frames/frame-seker.png?v=f58e2a5c), url(../web/frames/frame-seker.png?v=f58e2a5c); }
/* Aileye özgü GEOMETRİ (foto içe-oturtma penceresi + Forge XI dış silueti): her çerçevenin ŞEKLİ
   FARKLIDIR (Kerem) — bu clip-path'ler scripts/install_frame_art.py tarafından o ailenin PNG
   ALFASINDAN türetilir ve aşağıdaki işaretli bloklara YAZILIR (kanonik türetme kuralı: klasik
   çerçevenin kendi clip'lerinin üretiliş yöntemiyle aynı — yoğun satır örnekleme, katı alfa eşiği).
   İşaretli blokların İÇİNİ elle düzenleme (script sonraki koşuda ezer); el ince-ayarı gerekirse
   blokların DIŞINA, aşağıdaki serbest alanlara yaz. */
/* >>> AUTO-GEN GEOMETRI metalik (install_frame_art.py) */
.tf-custom-card.frame-family-metalik .tfc-bg, .tf-custom-card.frame-family-metalik .tfc-photo-container { clip-path: polygon(50.00% 5.70%,52.59% 6.00%,59.19% 7.50%,69.01% 8.50%,80.62% 13.00%,90.62% 15.00%,90.62% 81.00%,84.37% 84.50%,82.76% 85.00%,56.87% 90.50%,50.00% 92.30%,25.45% 86.50%,16.52% 85.00%,9.20% 81.00%,9.20% 15.00%,19.56% 13.00%,30.09% 9.00%,41.34% 7.50%,47.24% 6.00%); }
.tf-custom-card.frame-family-metalik.forgexi-card .tfc-photo-container { clip-path: polygon(50.00% 0.50%,51.61% 0.50%,60.36% 2.50%,64.29% 3.00%,71.61% 3.50%,81.07% 7.50%,88.75% 9.50%,97.32% 11.00%,97.32% 70.50%,99.29% 72.00%,99.64% 72.50%,99.64% 84.50%,89.82% 91.00%,79.64% 92.00%,60.89% 96.00%,50.89% 99.50%,48.93% 99.50%,35.18% 95.00%,19.82% 92.00%,10.00% 91.00%,0.18% 84.50%,0.18% 72.50%,2.50% 70.50%,2.50% 11.00%,15.36% 8.50%,28.21% 3.50%,35.54% 3.00%,48.21% 0.50%); -webkit-mask-image: none; mask-image: none; }
.tf-custom-card.frame-family-metalik { --tfc-ovr-size: 15.84cqw; --fx-info-scale: 1.05; }
.tf-custom-card.frame-family-metalik .tfc-meta { top: 17.24%; left: 15.03%; }
.tf-custom-card.frame-family-metalik .tfc-name { top: 60.14%; left: 1.6%; right: 1.33%; font-size: 9.24cqw; }
.tf-custom-card.frame-family-metalik .tfc-stats { top: 71.89%; left: 12.63%; right: 12.36%; }
.tf-custom-card.frame-family-metalik .tfc-stats .tfc-stat .lbl { font-size: 5.5cqw; }
.tf-custom-card.frame-family-metalik .tfc-stats .tfc-stat span:last-child { font-size: 7.04cqw; }
.tf-custom-card.frame-family-metalik .tfc-flag { top: 84.82%; width: 9.9cqw; }
.tf-custom-card.frame-family-metalik.forgexi-card .fx-ov { left: 4.85%; right: 4.6%; top: 52.9%; bottom: 0.6%; }
/* <<< AUTO-GEN GEOMETRI metalik */
/* >>> AUTO-GEN GEOMETRI tahta (install_frame_art.py) */
.tf-custom-card.frame-family-tahta .tfc-bg, .tf-custom-card.frame-family-tahta .tfc-photo-container { clip-path: polygon(50.00% 5.70%,58.48% 7.50%,68.12% 8.50%,79.91% 13.00%,86.87% 14.50%,90.62% 15.00%,90.80% 80.50%,84.19% 84.50%,50.00% 92.30%,23.66% 86.00%,15.63% 84.50%,9.38% 81.00%,9.02% 80.50%,9.02% 15.50%,10.27% 15.00%,23.13% 12.00%,30.27% 9.00%,39.74% 8.00%,47.77% 6.00%); }
.tf-custom-card.frame-family-tahta.forgexi-card .tfc-photo-container { clip-path: polygon(50.00% 0.50%,51.61% 0.50%,59.82% 2.50%,72.50% 4.00%,81.43% 8.00%,89.11% 10.00%,97.14% 11.50%,97.14% 18.50%,97.32% 19.50%,97.14% 21.00%,97.32% 21.50%,97.14% 27.00%,97.32% 28.00%,97.14% 34.50%,97.32% 35.00%,97.14% 67.50%,97.32% 68.00%,97.14% 68.50%,97.32% 70.00%,97.14% 70.50%,97.32% 71.00%,99.64% 72.50%,99.64% 84.00%,90.54% 90.50%,89.29% 91.00%,71.96% 93.50%,54.82% 98.00%,50.89% 99.50%,48.93% 99.50%,35.36% 95.00%,20.71% 92.00%,9.64% 90.50%,0.18% 84.00%,0.18% 72.50%,2.32% 71.00%,2.68% 70.50%,2.68% 11.50%,16.25% 8.50%,27.14% 4.00%,40.18% 2.50%,48.21% 0.50%); -webkit-mask-image: none; mask-image: none; }
.tf-custom-card.frame-family-tahta { --tfc-ovr-size: 15.84cqw; --fx-info-scale: 1.05; }
.tf-custom-card.frame-family-tahta .tfc-meta { top: 17.24%; left: 14.88%; }
.tf-custom-card.frame-family-tahta .tfc-name { top: 60.14%; left: 1.38%; right: 1.12%; font-size: 9.24cqw; }
.tf-custom-card.frame-family-tahta .tfc-stats { top: 71.89%; left: 12.46%; right: 12.2%; }
.tf-custom-card.frame-family-tahta .tfc-stats .tfc-stat .lbl { font-size: 5.5cqw; }
.tf-custom-card.frame-family-tahta .tfc-stats .tfc-stat span:last-child { font-size: 7.04cqw; }
.tf-custom-card.frame-family-tahta .tfc-flag { top: 84.82%; width: 9.9cqw; }
.tf-custom-card.frame-family-tahta.forgexi-card .fx-ov { left: 4.64%; right: 4.4%; top: 52.9%; bottom: 0.6%; }
/* <<< AUTO-GEN GEOMETRI tahta */
/* >>> AUTO-GEN GEOMETRI kemik (install_frame_art.py) */
.tf-custom-card.frame-family-kemik .tfc-bg, .tf-custom-card.frame-family-kemik .tfc-photo-container { clip-path: polygon(50.00% 5.70%,59.19% 7.50%,69.19% 8.50%,79.19% 12.50%,85.62% 14.00%,89.01% 14.50%,90.80% 15.00%,90.80% 81.00%,90.44% 81.50%,84.19% 85.00%,50.00% 92.30%,20.81% 86.00%,15.63% 85.00%,9.20% 81.50%,8.84% 81.00%,8.84% 15.00%,22.06% 12.00%,29.74% 9.00%,41.34% 7.50%,46.88% 6.00%); }
.tf-custom-card.frame-family-kemik.forgexi-card .tfc-photo-container { clip-path: polygon(50.00% 0.50%,51.43% 0.50%,57.14% 2.00%,63.57% 3.00%,70.18% 3.50%,80.18% 7.50%,90.36% 10.00%,96.79% 11.00%,97.14% 11.50%,97.14% 71.00%,99.64% 73.00%,99.64% 84.50%,99.46% 85.00%,90.36% 91.00%,69.64% 94.00%,50.89% 99.50%,49.11% 99.50%,32.32% 94.50%,17.86% 92.00%,9.82% 91.00%,0.54% 85.00%,0.18% 84.50%,0.18% 73.00%,2.32% 71.50%,2.50% 11.50%,2.86% 11.00%,15.36% 8.50%,27.14% 4.00%,40.18% 2.50%,48.04% 0.50%); -webkit-mask-image: none; mask-image: none; }
.tf-custom-card.frame-family-kemik { --tfc-ovr-size: 15.84cqw; --fx-info-scale: 1.05; }
.tf-custom-card.frame-family-kemik .tfc-meta { top: 17.24%; left: 14.71%; }
.tf-custom-card.frame-family-kemik .tfc-name { top: 60.14%; left: 1.18%; right: 1.1%; font-size: 9.24cqw; }
.tf-custom-card.frame-family-kemik .tfc-stats { top: 71.89%; left: 12.29%; right: 12.2%; }
.tf-custom-card.frame-family-kemik .tfc-stats .tfc-stat .lbl { font-size: 5.5cqw; }
.tf-custom-card.frame-family-kemik .tfc-stats .tfc-stat span:last-child { font-size: 7.04cqw; }
.tf-custom-card.frame-family-kemik .tfc-flag { top: 84.82%; width: 9.9cqw; }
.tf-custom-card.frame-family-kemik.forgexi-card .fx-ov { left: 4.45%; right: 4.39%; top: 52.9%; bottom: 0.6%; }
/* <<< AUTO-GEN GEOMETRI kemik */
/* >>> AUTO-GEN GEOMETRI seker (install_frame_art.py) */
.tf-custom-card.frame-family-seker .tfc-bg, .tf-custom-card.frame-family-seker .tfc-photo-container { clip-path: polygon(50.00% 8.20%,52.23% 8.50%,58.12% 10.00%,69.73% 11.00%,76.34% 14.00%,81.69% 15.50%,87.59% 16.50%,88.48% 17.00%,88.66% 35.50%,88.48% 36.00%,88.66% 60.00%,88.48% 60.50%,88.66% 62.00%,88.48% 62.50%,88.66% 77.00%,88.48% 77.50%,88.66% 79.50%,88.48% 80.00%,88.66% 80.50%,88.48% 81.00%,84.19% 84.00%,82.94% 84.50%,56.51% 90.00%,51.87% 91.50%,50.00% 91.80%,47.24% 91.50%,30.45% 87.00%,16.16% 84.50%,11.70% 81.50%,11.16% 80.50%,11.16% 66.00%,10.99% 65.00%,11.16% 60.50%,10.99% 60.00%,11.16% 37.50%,10.99% 36.00%,11.16% 19.50%,10.99% 19.00%,11.16% 17.00%,11.52% 16.50%,22.59% 14.00%,29.38% 11.00%,40.45% 10.00%,46.34% 8.50%); }
.tf-custom-card.frame-family-seker.forgexi-card .tfc-photo-container { clip-path: polygon(50.00% 0.50%,51.61% 0.50%,59.11% 3.00%,70.36% 3.50%,72.86% 4.00%,81.79% 8.00%,87.68% 9.50%,93.39% 10.50%,95.89% 11.50%,97.14% 13.00%,97.32% 70.50%,99.64% 72.50%,99.64% 84.00%,99.46% 84.50%,90.54% 90.50%,89.46% 91.00%,71.25% 93.50%,54.64% 98.00%,50.54% 99.50%,48.57% 99.50%,32.32% 94.50%,18.39% 92.00%,10.00% 91.00%,0.18% 84.50%,0.18% 72.50%,2.14% 71.00%,2.68% 70.00%,2.68% 55.00%,2.50% 52.50%,2.68% 48.00%,2.50% 47.50%,2.68% 45.50%,2.50% 44.50%,2.68% 28.50%,2.50% 28.00%,2.68% 25.00%,2.50% 22.00%,2.68% 21.50%,2.50% 14.00%,3.39% 12.00%,4.64% 11.00%,18.75% 7.50%,26.07% 4.00%,35.71% 3.50%,39.11% 3.00%,46.79% 0.50%); -webkit-mask-image: none; mask-image: none; }
.tf-custom-card.frame-family-seker { --tfc-ovr-size: 15.84cqw; --fx-info-scale: 1.05; }
.tf-custom-card.frame-family-seker .tfc-meta { top: 19.35%; left: 16.75%; }
.tf-custom-card.frame-family-seker .tfc-name { top: 60.75%; left: 3.97%; right: 3.73%; font-size: 9.24cqw; }
.tf-custom-card.frame-family-seker .tfc-stats { top: 72.09%; left: 14.46%; right: 14.22%; }
.tf-custom-card.frame-family-seker .tfc-stats .tfc-stat .lbl { font-size: 5.5cqw; }
.tf-custom-card.frame-family-seker .tfc-stats .tfc-stat span:last-child { font-size: 7.04cqw; }
.tf-custom-card.frame-family-seker .tfc-flag { top: 84.57%; width: 9.9cqw; }
.tf-custom-card.frame-family-seker.forgexi-card .fx-ov { left: 7.06%; right: 6.84%; top: 53.76%; bottom: 1.32%; }
/* <<< AUTO-GEN GEOMETRI seker */
/* Aileye özgü SERBEST ince ayar blokları (script DOKUNMAZ — yazı konumu/maske gibi el ayarları): */
.tf-custom-card.frame-family-metalik { /* metalik'e özgü el override'ları buraya */ }
.tf-custom-card.frame-family-tahta { /* tahta'ya özgü el override'ları buraya */ }
.tf-custom-card.frame-family-kemik { /* kemik'e özgü el override'ları buraya */ }
.tf-custom-card.frame-family-seker { /* seker'e özgü el override'ları buraya */ }
