﻿/* MANROPE — KENDİ SUNUCUMUZDAN, DEĞİŞKEN FONT.
   [KUSUR 2026-08-10 · denetim F3] Font Google CDN'inden BEŞ ayrı ağırlık olarak isteniyordu
   (§G2 tavanı 4), `preload` yoktu, subset yoktu. İki ayrı bedeli vardı:
   · her ziyaretçide üçüncü bir alan adına bağlantı + iki tur (CSS, sonra font dosyası)
   · rıza öncesi üçüncü tarafa istek — çerez gitmiyor ama IP gidiyor (§K4.2'nin ruhu)

   Manrope DEĞİŞKEN bir font: 400-800 arası bütün ağırlıklar TEK dosyada. Yani "kaç ağırlık"
   sorusu dosya sayısıyla değil bir aralıkla cevaplanıyor ve toplam 39 KB'a iniyor
   (latin 24 KB + latin-ext 15 KB).

   latin-ext ZORUNLU: ğ ş İ ı ç ö ü orada. `unicode-range` ikisini ayırıyor, yani Türkçe
   karakter içermeyen bir sayfa ikinci dosyayı hiç indirmiyor.

   `font-display:swap` + `preload` birlikte: metin hiçbir zaman görünmez kalmıyor, font da ilk
   boyamadan önce geliyor. */
@font-face{font-family:Manrope;font-style:normal;font-weight:400 800;font-display:swap;
  src:url("/fonts/manrope-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,
    U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,
    U+A720-A7FF}
@font-face{font-family:Manrope;font-style:normal;font-weight:400 800;font-display:swap;
  src:url("/fonts/manrope-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,
    U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

/* ============================================================
   manavda prototip — ortak stil
   Token'lar docs/design/style-guide.html ile birebir aynı.
   KURAL: ham px/hex/em YALNIZ token tanımında (:root) geçer.
   Kırılma noktaları tek sistem: 1280 / 960 / 640 (min-width karşılıkları 961/641).
   ============================================================ */
:root{
  /* ---- ilkel (primitive) ---- */
  --pine-900:#053a2c; --pine-700:#00543f; --pine-600:#00674f;
  --pine-500:#0a7a5e; --pine-400:#34a884; --pine-200:#a9d3c1;
  --pine-100:#d7ebe1; --pine-050:#edf6f1;
  --terra-800:#945522; --terra-500:#f4a261;
  --terra-300:#f9c79b;
  --neutral-000:#ffffff; --neutral-025:#f4f9f7; --neutral-050:#e8f2ee;
  --neutral-100:#d6e5de; --neutral-300:#6f817a; --neutral-600:#4a5c55; --neutral-900:#0e1a15;
  --badge-fresh-bg:#0a7a5e; --badge-fresh-fg:#ffffff;
  --badge-deal-bg:#f4a261;  --badge-deal-fg:#0e1a15;
  --badge-alert-bg:#d93a2b; --badge-alert-fg:#ffffff;
  --badge-info-bg:#e8f2ee;  --badge-info-fg:#00543f;
  /* [KALDIRILDI 2026-08-14] `--badge-gone-*` buradaydı. Tükendi ROZETİ kaldırıldığı için
     (kart aynı kelimeyi iki kez söylüyordu — bkz. _ProductCard.cshtml) token'ları da kaldırıldı;
     kullanılmayan renk değişkeni bir gün "var zaten" diye yanlış yere bağlanır. */
  --amber-800:#7a5000; --amber-100:#fbf1d9;
  --red-700:#9e2a24;   --red-100:#fbe9e5;

  /* ---- anlamsal (semantic) ---- */
  --primary:var(--pine-600); --primary-hover:var(--pine-500); --primary-pressed:var(--pine-700);
  --primary-soft:var(--pine-050); --on-primary:var(--neutral-000);
  --quick:var(--pine-100); --quick-ink:var(--pine-700);
  --accent:var(--terra-500);
  --accent-soft:#fff1e3; --accent-ink:var(--terra-800);
  --warning:var(--amber-800); --warning-soft:var(--amber-100);
  --danger:var(--red-700);   --danger-soft:var(--red-100);
  --surface:var(--neutral-000); --ground:var(--neutral-025); --quiet:var(--neutral-050);
  --divider:var(--neutral-100); --control-border:var(--neutral-300);
  --text:var(--neutral-900); --text-2:var(--neutral-600); --on-dark:var(--neutral-000);
  --focus:var(--pine-700); --price:var(--text);
  /* Koyu zemin üstü ikincil yüzey (adres çipi, hesap ve sepet düğmesi).
     [KUSUR 2026-08-14 · denetimde ölçüldü] Alfa .18 idi ve marka yeşiliyle harmanlanınca
     rgb(46,130,111) veriyordu: üstündeki BEYAZ yazının kontrastı 4,61:1 — eşiği (4,5) geçiyor
     ama payı yalnız 0,11. Sayfanın en kırılgan yeriydi; çubuk bir tık açılsa ihlale düşerdi.
     Alfa DÜŞÜNCE yüzey koyulaşıyor ve beyaz yazı rahatlıyor: .14 → 5,04:1 (pay 0,54, beş kat).
     Daha aşağısı yazıyı daha da rahatlatırdı ama çipin çubuktan ayrışması 1,49 → 1,20'ye
     iniyor ve kontrol yüzey olmaktan çıkıyordu; .14 ikisinin kesişimi (ayrışma 1,37). */
  --on-primary-soft:rgb(255 255 255 / .14);
  --on-primary-soft-hi:rgb(255 255 255 / .30);
  --scrim:rgb(14 26 21 / .5); --scrim-blur:2px;
  /* Perdenin hover kademesi (manşet okları). Ayrı bir token, çünkü ham renk YALNIZ burada
     yazılır; kural gereği bileşen dosyasında `rgb(...)` geçemez. */
  --scrim-hi:rgb(14 26 21 / .72);
  /* Vurgu darbesi (pulse) — accent'in saydam iki kademesi. Ham renk yalnız burada. */
  --pulse-from:rgb(244 162 97 / .6); --pulse-to:rgb(244 162 97 / 0);

  /* ---- ölçek (4/8) ---- */
  --space-1:4px; --space-2:8px; --space-3:12px; --space-4:16px;
  --space-6:24px; --space-8:32px; --space-12:48px; --space-16:64px; --space-24:96px;

  /* ---- tipografi (8 rol, 1.25 oran) ---- */
  --font:'Manrope',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --text-display:39px; --text-h1:31px; --text-h2:25px; --text-h3:20px;
  --text-body:16px; --text-label:14px; --text-caption:13px; --text-micro:11px;
  --lh-tight:1.15; --lh-none:1.2; --lh-snug:1.35; --lh-body:1.6;
  --tr-h1:-.03em; --tr-h2:-.025em; --tr-h3:-.02em;
  /* [DEĞİŞTİ 2026-08-13 · Eyüp: "harflerin arasındaki boşluk biraz kısık"]
     -.035em idi: ölçekteki EN SIKI değer, başlıklardan (-.03) bile sıkı. Negatif harf aralığı
     büyük puntoda optik bir düzeltmedir (§B14) ama dozu boyutla ters orantılıdır — logo 39 px'e
     çıkınca aynı oran "sıkıştırılmış" okunuyordu, çünkü kerning zaten ölçeğe göre artıyor.
     -.015em marka adını toparlamaya devam ediyor, harfleri birbirine yapıştırmıyor.
     Token TEK yerde: başlık, footer ve giriş katmanındaki logolar birlikte düzelir. */
  --tr-label:.08em; --tr-micro:.02em;
  /* --w-medium (500) KALDIRILDI: tek yerde kullanılıyordu ve §G2 tavanı 4 ağırlık. */
  --w-regular:400; --w-semibold:600; --w-bold:700; --w-black:800;

  /* ---- biçim ---- */
  --radius-sm:4px; --radius-md:8px; --radius-lg:12px; --radius-xl:16px;
  --radius-2xl:20px; --radius-pill:9999px;
  --border-hairline:1px; --border-control:1.5px; --border-emphasis:2px; --border-focus:3px;
  --elev-card:0 1px 2px rgb(14 26 21 / .04), 0 4px 14px rgb(14 26 21 / .07);
  --elev-product:0 2px 4px rgb(14 26 21 / .05), 0 10px 26px rgb(14 26 21 / .10);
  --elev-product-hi:0 4px 8px rgb(14 26 21 / .06), 0 16px 36px rgb(14 26 21 / .14);
  /* --elev-float YALNIZ üste binen katman içindir (modal, çekmece, pencere, toast, menü).
     Kart hover'ı buraya sıçrayınca ürün kartı bir anlığına "üste binen katman" gibi
     okunuyordu; yükseklik dili katmanı anlatır, ilgiyi değil. */
  --elev-float:0 8px 16px rgb(14 26 21 / .10), 0 24px 56px rgb(14 26 21 / .20);
  --elev-bar:0 -4px 20px rgb(14 26 21 / .12);        /* alt sabit çubuk — gölge yukarı */
  --dur-press:80ms; --dur-micro:120ms; --dur-enter:200ms; --dur-drawer:300ms;
  /* Bekleme göstergesinin AÇILMA eşiği (§A4: 100–400 ms akıcı sayılır, gösterge o aralıkta
     gösterilmez — hızlı yanıtta ekran çakar). Aynı sayı JS'te de var: commit-lock.js `DELAY`.
     [KUSUR 2026-08-10 · denetim J10] İki yerde ham `400ms` yazılıydı; kuralın sayısı bir token'a
     bağlanmazsa üçüncü yerde 300 yazılır ve bekleme dili sayfadan sayfaya değişir. */
  --dur-wait-gate:400ms;
  --ease-out:cubic-bezier(0,0,.2,1); --ease-spring:cubic-bezier(.34,1.56,.64,1);

  /* ---- kontrol geometrisi ---- */
  --icon-sm:16px; --icon-md:20px; --icon-lg:24px; --icon-xl:32px; --icon-gap:8px;
  --control-h:44px; --control-h-sm:36px; --control-box:24px; --tap-min:44px; --tap-box:24px;
  /* Yükleme yeri (iskelet çubuğu + görsel yükleme parlaması) — TEK token seti.
     Yüzey token'ları (--quiet) ödünç alınmaz: o bir ZEMİN (üstüne metin gelir, bilerek soluk),
     bu ise ŞEKİL — görülmesi işinin tamamı. Ödünç alınan değerler 1,10-1,14:1 ölçülmüştü,
     yani ekranda yoktular. Yeni taban 1,43:1: okunur ama içerik sanılacak kadar koyu değil. */
  --skeleton:#cadcd4; --skeleton-shine:#dceae5;
  /* LOGO YÜKSEKLİĞİ — tipografi ölçeğinden AYRI token seti.
     [KUSUR 2026-08-13 · Eyüp: "desktop menüdeki logo çok büyük oldu" · ölçüldü, haklı]
     Logo yazıyken yüksekliği `--text-display` (39 px) veriyordu ve bu bir PUNTOydu: Manrope 800'de
     "manavda"nın gerçek mürekkep yüksekliği puntonun 0,735'i (ölçüldü, canvas TextMetrics), yani
     ekranda görünen harfler 29 px'ti — kalan 10 px satır boşluğuydu.
     SVG ise KIRPILMIŞ geliyor (mürekkep kutusu 2171×422 / viewBox 2246×440, %2 pay): aynı 39
     sayısı artık baştan sona harf demek. Sonuç, aynı token ile %35 büyüyen bir logo.
     Ders: yazıdan görsele geçerken sayı KORUNMAZ, optik boyut korunur.
     Değerler onaylanmış görünümün mürekkep karşılıkları: masaüstü 29 → ölçekten 25,
     mobil 18 → 20, giriş katmanı 15 → 16. Punto token'ı kullanmıyorlar çünkü punto değiller. */
  --logo-h:25px; --logo-h-sm:20px; --logo-h-xs:16px;
  --thumb-sm:56px; --thumb-lg:88px;
  --prod-media:420px;        /* ürün sayfasındaki görsel sütunu */
  --bnr-min:320px; --seg-min:88px;
  /* Manşetin yüksekliği token DEĞİL: içerik sadece görsel olduğu için yükseklik ORANDAN doğuyor
     (`.hslide picture` — masaüstü 3:1, mobil 2:1). Sabit bir yükseklik, oranla çelişip afişi
     ikinci kez kırpardı. */
  --camp-min:320px;          /* kampanya kartı taban genişliği */
  /* Kampanya kartı TAVANI. [KUSUR 2026-08-14] Izgara `auto-fill` ile üç şerit açıyor ve tek
     kampanya varken ikisi BOŞ kalıyordu (ölçüldü: 766 px ölü alan). `auto-fit` boş şeritleri
     kapatır ama bu sefer tek kart 1181 px'e yayılır — afiş kartı poster olmaktan çıkar.
     Tavan ikisini birden çözüyor: şerit kapanır, kart makul boyda kalır. */
  --camp-max:480px;
  --camp-wide:280px;         /* geniş kampanya kartının kapak sütunu */
  --camp-media:640px;        /* kampanya kapağı sütunu — 3:2'de 427 px yüksek */
  /* [KALDIRILDI 2026-08-19] `--camp-copy:60ch` buradaydı ve kampanya sayfasına DÖRDÜNCÜ bir
     genişlik katıyordu (hero 1280 · başlık 586 · koşullar 704 · dipnot 544 → tırtıklı sağ
     kenar). Başlık bloğu artık manşetin sağ sütununda ve ölçüsü oradan (34rem) geliyor. */
  --camp-term-lbl:200px;     /* koşul tablosunda etiket sütunu */
  --ref-stat-min:160px;      /* davet istatistik kartı */
  --shut-w:620px;            /* kapalı ekranı metin genişliği */
  --shut-time:84px;          /* "ne zaman" cevabı — sayfanın en büyük öğesi */
  --shut-tile-h:300px;       /* dekoratif tezgâh karosu */
  --shut-grid-h:340px;       /* tezgâh ne kadar görünsün */
  /* Üst çubuk yüksekliği — JS ölçüp yazar (top-inset.js); buradaki değer JS'ten ÖNCEKİ ilk
     boyamanın ve yapışkan hesaplarının tabanı, o yüzden gerçeğe yakın durmalı.
     [ÖLÇÜLDÜ 2026-08-13 · tarayıcıda] Bir ara 72 yazılmıştı: logo 39 px'lik YAZIYDI ve satır
     kutusu 47 px olduğu için çubuğu 71 px'e çıkarıyordu. Logo SVG'ye dönünce görsel tam 39 px
     yüksekliğinde ve 44 px'lik dokunma hedefinin İÇİNDE kalıyor — yani çubuğun yüksekliğini
     artık komşu kontrollerle aynı şey belirliyor: 12 + 44 + 12 = 68.
     Değer yanlış kalsaydı yapışkan kategori rayı ilk boyamada 4 px aşağı otururdu (JS düzeltene
     kadar arkasındaki içerik görünür). */
  --topbar-h:68px;

  /* ---- yerleşim ---- */
  /* [DEĞİŞTİ 2026-08-13 · iki tasarım incelemesi birden: "sayfa çok dar"]
     İçerik 1072 px'ti; kılavuzun KENDİ kuralı §B10 "uygulama içeriği 1200–1280 px" diyor, yani
     kendi standardımızın altındaydık ve 1440 px'lik ekranda kap, viewport'un %83'ünü boş
     bırakıyordu.

     [TEKRAR DEĞİŞTİ 2026-08-13 · Eyüp: "buna bişey yapmamışız gibi, getirde baksana"]
     1152 yetmedi ve haklı: 1920 px'lik ekranda içerik ortada 1152 px kalıyor, iki yanda 384'er px
     boş duruyordu. Getir ölçüldü — kabı **1232 px** (tek `max-width`, tüm sayfada). Yani biz
     rakibin 80 px altındaydık ve kılavuzun kendi §B10 bandının (1200–1280) dışındaydık.

     KISIT NEREDEN GELİYORDU: `.wrap`ın tavanı `--grid-max + 2×--grid-margin` ve marjin bir
     kırılımda 64→32 düşüyor. Marjin adımı, kap HÂLÂ AKIŞKANKEN atılırsa içerik ekran daralırken
     GENİŞLER (1281'de 1153, 1280'de 1200) — sütun eklenir, kart küçülür. Önceki tur bunu
     `--grid-max`i 1152'ye çekerek çözmüştü; asıl çözüm ADIMI DOĞRU YERE koymak.

     Süreklilik koşulu: marjin adımı, kabın tavanına ULAŞTIĞI genişlikte ya da ondan sonra
     atılmalı. Tavan = 1280 + 2×64 = 1408, ölçekteki bir sonraki kırılım 1536 (§B10 listesinde
     zaten var). Doğrulandı:
       1920 → kap 1408, içerik 1280      1537 → kap 1408, içerik 1280
       1536 → kap 1344, içerik 1280      1440 → kap 1344, içerik 1280
       1280 → kap 1280, içerik 1216      1024 → kap 1024, içerik  960
     Hiçbir yerde ekran daralırken içerik genişlemiyor.

     KART TABANI BUNUNLA BİRLİKTE HAREKET EDER, yoksa iş tersine döner: 1280 px'lik içerikte
     216 px'lik taban `(1280+24)/240 = 5,43` ile ızgarayı 5 sütuna çıkarır ve kartı 270 → 237'ye
     KÜÇÜLTÜR — genişletmenin amacının tam tersi. 244 px taban 4 sütunu koruyor ve kartı 302 px'e
     çıkarıyor. Pencere [244, 302]: 244'ün altı 5. sütunu açıyor, 302'nin üstü 4.'yü kapatıyor.
     KATALOG IZGARASI ARTIK BU TABANDAN TÜREMİYOR: sütun sayısı `.grid`de açık yazılı (4/3/2),
     çünkü türetme ters basamak üretiyordu — gerekçesi orada. `--card-min` yalnız akışkan
     yardımcılarda (`.grow`, `.rec-main`, `.shut-grid`) taban olarak kalıyor. */
  --grid-max:1280px; --grid-gutter:24px; --grid-margin:64px;
  --card-min:216px;          /* akışkan yardımcıların tabanı — katalog ızgarası bunu KULLANMAZ */
  --rail-w:380px;            /* sepet/ödeme özet sütunu */
  --field-w:520px;           /* tek sütunlu form/kart genişliği */
  /* Form sütunu = alanın kendisi + panelin payı. Formun sağ kenarı panelin sağ kenarıyla
     BULUŞSUN diye türetiliyor; ölü boşluk "yarım kalmış" okunuyor (`.rw--cardrow` notundaki
     ölçüm). Sayı elle yazılmıyor: alan genişliği ya da panel payı değişirse sütun onunla gelir. */
  --form-col:calc(var(--field-w) + var(--space-6) * 2);
  /* O günkü 1072 px'lik içerik genişliğinde 480 px arama, kenar sütunlarını 184 px'e sıkıştırıp
     adres adını kırpıyordu (ölçüldü). 380 → kenar 330, çip 234 px: ad tam sığar.
     Kap 1152'ye çıkınca kenarlar 80 px daha rahatladı; kutu BÜYÜTÜLMEDİ — genişliği içerik
     belirler (aranan şey iki-üç kelime), kabın büyümesi kutuya bir şey kazandırmıyor. */
  --search-min:200px; --search-max:380px;
  --dialog-w:440px; --sheet-w:460px; --toast-w:420px; --drawer-w:420px;
  --acct-rail:240px;         /* hesap sayfası sol navigasyonu */
  --measure:34ch;            /* okunabilir satır uzunluğu */
  --cur-scale:.62;           /* ₺ simgesi / fiyat oranı */
  --caret:6px;               /* select oku */
  --money-w:76px;            /* "1.234,56 ₺" için ayrılan sabit yer — başlık hoplamasın */
  /* Çubuğun GERÇEK yüksekliği: 2×12 padding + 56 px düğme + güvenli alan.
     72 px sabit yazılıydı, çentikli ekranda ~40 px eksik kalıyordu. */
  --bar-h:calc(var(--space-3) * 2 + 56px + env(safe-area-inset-bottom, 0px));
  --bar-live:0px;              /* mobil alt sepet çubuğu */
  --consent-btn-w:168px;     /* kabul/reddet SABİT eşit genişlik (§K2 simetri) */
  --slot-min:152px;          /* teslimat kutusunun asgari genişliği — hem mod kademesi (.dmode)
                                hem saat ızgarası (.slotgrid) buradan doğar */
  --consent-h:0px;           /* çerez bandı yüksekliği — JS ölçüp yazar */
  
  /* Uygulama tanıtımındaki maket telefon. 230 → 280 (2026-08-13): metin sütunu 52ch'lik bir
     blok iken telefon 230 px'lik bir süse dönüşmüştü; bölümün iki sütunu 1.15fr/.85fr olduğu
     hâlde sağ sütunun içi boş kalıyordu. */
  --phone-w:280px;
  --elev-phone:0 24px 48px rgb(0 0 0 / .35);
  --line-2:calc(var(--text-body) * var(--lh-snug) * 2);   /* 2 satırlık isim alanı */
}
/* KIRILIMLAR ÖLÇEKTEN: 640 · 768 · 1024 · 1280 · 1536 (§B10, hepsi 8'e bölünür).
   [KUSUR 2026-08-10 · denetim J10] On yerde ölçek dışı `960px` vardı. Ölçek dışı bir kırılım
   tek başına zarar vermez; zararı, bir sonraki kişinin "burada 960 kullanılmış" diye üçüncü bir
   sayı eklemesidir. Hepsi en yakın ölçek değerine (1024) alındı — geçiş 64 px erken oluyor ve
   1024 zaten tablet-yatay sınırı, yani doğal yeri. */
/* [DEĞİŞTİ 2026-08-13] Adım 1280'den 1536'ya taşındı. Gerekçe `--grid-max` notunda: marjin adımı
   kap HÂLÂ AKIŞKANKEN atılırsa içerik, ekran daralırken genişliyor. Kap tavanına 1408'de ulaşıyor,
   ölçekteki bir sonraki kırılım 1536 — adım orada atılınca fonksiyon sürekli kalıyor. */
@media (max-width:1536px){:root{--grid-margin:var(--space-8)}}
/* Dar ekranda kart tabanı küçülür — 328 px'lik tek sütun kart israftır, ızgara 2 sütuna iner. */
@media (max-width:640px){:root{--grid-margin:var(--space-4);--grid-gutter:var(--space-4);
  --card-min:150px}}

*,*::before,*::after{box-sizing:border-box}

/* [KÖK NEDEN KURALI] `hidden` HER ZAMAN gizler.
   Tarayıcının `[hidden]{display:none}` kuralı UA stil sayfasında; bizim yazdığımız HERHANGİ bir
   `display` bildirimi onu ezer (öznitelik/sınıf seçicisi daha güçlü). O zaman öğe görünmez ama
   YER KAPLAMAYA devam eder — hata çıkmaz, yalnız arayüzde açıklanamayan boşluklar belirir.
   Gerçek örnek: `[data-cart-total]{display:inline-block}` yüzünden boş sepette üst çubuktaki
   düğme 136 px genişliğinde, %85'i boş bir yeşil hap olarak duruyordu.
   Prototip bunu seçici seçici yamamıştı (.cart-badge[hidden], .err[hidden] …) ve kaçınılmaz
   olarak biri unutulmuştu. Tek kural, bütün sınıf. */
[hidden]{display:none !important}
/* Yapışkan footer: kısa sayfada (hata, boş sepet, tek sonuç) footer ekranın ortasında kalıp
   altında boş bir şerit bırakıyordu. Prototipte fark edilmemişti çünkü orada her sayfa uzundu.
   Gövde sütun akışına alınır, footer artan alanı yukarıdan iter. */
body{margin:0;background:var(--ground);color:var(--text);font-family:var(--font);
  font-size:var(--text-body);line-height:var(--lh-body);-webkit-font-smoothing:antialiased;
  min-height:100dvh;display:flex;flex-direction:column}
.site-foot{margin-top:auto}
h1,h2,h3,h4{margin:0;line-height:var(--lh-tight);text-wrap:balance}
p{margin:0} ul{margin:0;padding-left:var(--space-4)}
/* `small` ÖLÇEĞE bağlanır.
   [KUSUR 2026-08-10 · denetim J9] Tarayıcı varsayılanı `font-size:0.8333em` — yani ebeveyne göre
   KAYAN bir değer. Ölçüldü (/sepet): 16 px kapta 13,33 px · 14 px kapta 11,67 px. İkisi de
   ölçekte yok ve sayfadaki farklı boyut sayısını 6'dan 8'e çıkarıyordu (§B2.1 tavanı 6).
   Ölçek dışı bir boyut hiyerarşiye bir şey katmaz, yalnız ne kadar küçük olduğunu bağlamın
   tesadüfüne bırakır. `small` semantik olarak "yan bilgi"dir; ölçekteki karşılığı caption.
   Daha spesifik kurallar (`.chip small` → micro) bunu ezmeye devam eder. */
small{font-size:var(--text-caption)}
a{color:inherit}
:where(a,button,input,select,textarea,[tabindex]):focus-visible{
  outline:var(--border-focus) solid var(--focus);outline-offset:var(--border-emphasis);
  border-radius:var(--radius-sm)}
/* --grid-max artık İÇERİK ölçüsü. Önce max-width padding'i içeriyordu; 1281→1280'de
   marjin 64→32 düşünce içerik GENİŞLİYORDU (1072→1136) — ekran daralırken katalog
   ızgarasına sütun ekleniyor, kart 42 px küçülüyordu. Fonksiyon artık monoton. */
.wrap{width:100%;max-width:calc(var(--grid-max) + var(--grid-margin) * 2);
  margin-inline:auto;padding-inline:var(--grid-margin)}
/* İÇERİK FOOTER'A DAYANMAZ.

   [KUSUR 2026-08-13 · Eyüp: "dip dipe girmiş" · TARANDI] Eyüp anasayfadaki bir yeri gösterdi;
   ölçünce kusurun sayfaya özel olmadığı çıktı: `main`in ne alt padding'i ne alt margin'i vardı
   ve taranan ON sayfanın ONUNDA da içerik ile footer arası boşluk SIFIRDI (/, /sepet,
   /kategori, /kampanyalar, /yasal, /hakkimizda, /iletisim, /davet, /siparislerim, /urun).
   Sebebi `.section`ın yalnız ÜST payı olması (`padding-block: var(--space-12) 0`): bölümler
   birbirinden ayrılıyor ama sonuncusunun altı açıkta kalıyordu.

   Pay `main`e veriliyor, `.section`a değil: son bölümün hangisi olduğunu sayfa biliyor, CSS
   bilmiyor — `:last-child`e bağlamak, tek bölümlü sayfada payı yanlış yere koyardı. */
main.wrap{padding-bottom:var(--space-16)}
@media (max-width:640px){main.wrap{padding-bottom:var(--space-8)}}
.sr{position:absolute;width:var(--border-hairline);height:var(--border-hairline);overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap}

/* başlık rolleri — sayfa içinde inline style ile yazılmaz */
/* line-height ŞART: bu sınıflar çoğu yerde <b>/<span> üzerine biniyor ve o öğeler
   gövdeden 1.6 miras alıyordu — h1-h4 elementleri 1.15 alırken aynı görünmesi gereken
   başlık iki kat daha açık satırlı çıkıyordu (6 yer). */
.h1{font-size:var(--text-h1);font-weight:var(--w-black);letter-spacing:var(--tr-h1);
  line-height:var(--lh-tight);text-wrap:balance}
.h2{font-size:var(--text-h2);font-weight:var(--w-black);letter-spacing:var(--tr-h2);
  line-height:var(--lh-tight);text-wrap:balance}
.h3{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3);
  line-height:var(--lh-tight);text-wrap:balance}
.stack{display:grid;gap:var(--space-4)}
.stack--tight{display:grid;gap:var(--space-2)}
.stack--wide{display:grid;gap:var(--space-6)}

/* ---------- İKON STANDARDI ----------
   Tüm ikonlar 24×24 ızgarada, çizgi tabanlı, currentColor.
   Ölçü BURADAN gelir — SVG'ye width/height yazılmaz. Varsayılan --icon-md.
   Bir kontrolün içinde ikon+metin varsa aralarındaki boşluk --icon-gap (btn/chip zaten verir). */
svg{width:var(--icon-md);height:var(--icon-md);flex:none;display:block}

/* ---------- üst çubuk ----------
   #top bir sarmalayıcı div; display:contents olmazsa sticky o div'in
   (= başlık yüksekliği kadar) içinde hapsolur ve hiç yapışmaz. */
/* Yapışkan çocuklar sarmalayıcının kutusuna hapsolur — sarmalayıcı yerleşimden
   çekilir ki sticky bağlamı gerçek bölüm olsun (#top → body, #catbar → #catalog). */
/* `#catbar` BURADAN ÇIKARILDI 2026-08-13: `display:contents` yalnız YAPIŞKAN çocuğun
   sarmalayıcının kutusuna hapsolmaması için gerekiyordu. Ray artık yapışkan değil, dolayısıyla
   kuralın koruduğu bir şey kalmadı. `#top` duruyor — üst çubuk hâlâ yapışkan. */
#top{display:contents}
.topbar{position:sticky;top:0;z-index:40;background:var(--primary);color:var(--on-primary);
  box-shadow:var(--elev-card)}
/* Kenar sütunlar eşit esner → arama GERÇEKTEN ortalanır (flex+auto margin 51 px kaydırıyordu). */
/* İKİ sütun: sol grup (marka + adres) esner, sağ grup (hesap + sepet) içeriği kadar yer alır
   ve KENARA yaslanır.

   [KUSUR 2026-08-11 · Eyüp: "header çok kötü"] Şema `1fr auto 1fr` idi çünkü ORTA sütun arama
   kutusuydu. Arama sayfa içine alınınca grid'in üçüncü çocuğu kayboldu; kalan iki çocuk ilk iki
   sütuna yerleşti ve sağ grup ORTADA kaldı. Ölçüldü (1440 px): sağ gruptan kenara 652 px boşluk,
   bütün öğeler sola yığılı. Sütun sayısı içeriğe göre belirlenir — bir öğe kalkınca şema onunla
   birlikte güncellenmezse yerleşim sessizce yanlış olur. */
/* [KARAR 2026-08-12] Arama üst çubuğa GERİ DÖNDÜ (yalnız katalog yüzeylerinde, bkz. TopBar).
   Sütun şeması `1fr auto 1fr` DEĞİL, `auto 1fr auto`:
     · `1fr auto 1fr` kutuyu ekranın ortasına kilitler. İki yan grup farklı genişlikte (sol ~300,
       sağ ~108) olduğu için sol grup kutuyu iterek asimetrik bir boşluk üretiyordu — prototipte
       51 px sapma ölçülmüştü, o notun kaynağı bu.
     · `auto 1fr auto` yan gruplara İÇERİKLERİ kadar yer verir, ORTA sütun kalanı doldurur.
       Arama kutusu kendi `max-width`i kadar büyür ve `margin-inline:auto` ile ortalanır; iki
       yan grup kenarlara yaslanır. Boşluk kalmaz, kutu da ekranın ortasında durur.
   [DEĞİŞTİ 2026-08-21 · "tek header"] Kutu artık gezinme basılan HER yüzeyde; üç sütunlu şema
   kuralın kendisi, iki sütunlu hâl ise tek istisnanın (devir/3DS — çubukta yalnız marka işareti)
   karşılığı. Yani şema sayfaya göre değil, çubuğun araçlı/araçsız olmasına göre değişiyor. */
.topbar .in{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;
  gap:var(--space-4);padding-block:var(--space-3)}
/* Araçsız çubuk (devir/3DS): iki grup, ikincisi sağa yaslı. */
.topbar .in:not(:has(.searchbox--top)){grid-template-columns:auto minmax(0,1fr)}
.topbar .in:not(:has(.searchbox--top)) .tb-side--end{justify-self:end}
.tb-side{display:flex;align-items:center;gap:var(--space-3);min-width:0}
.tb-side--end{justify-content:flex-end}
/* Dokunma hedefi: yalnız line-height kadar yüksekti (mobilde 19 px) ve WCAG 2.5.8'in SERT
   alt sınırı olan 24 px'in altında kalıyordu. Cümle içi bağlantı istisnası burada geçmez —
   logo bir gezinme hedefi. Metin boyutu değişmiyor, yalnız tıklama alanı büyüyor. */
/* [KUSUR 2026-08-12 · Eyüp: "headerdaki logo gerçekten küçük" · ölçüldü, haklı]
   Logo `--text-h3` (20 px) idi. Aynı sayfada ürün fiyatı 25 px, "Sebze" reyon başlığı 20 px:
   marka, bir reyon etiketiyle aynı boyda ve bir domatesin fiyatından KÜÇÜKTÜ. Başlıkta da
   ölçüldü — logo 85 px, yanındaki adres çipi 208 px; görsel ağırlık markada değil adresteydi.
   `--text-h1` (31 px) ile logo başlığın en büyük öğesi oluyor: 68 px'lik çubukta üstte ve
   altta 18 px pay kalıyor, komşu kontrollerin 44 px'lik yüksekliği değişmiyor.

   [2026-08-13 · Eyüp: "masaüstünde de bi tık büyütelim"] Bir kademe daha: 31 → 39 px
   (`--text-display`). Ölçekte bir SONRAKİ basamak bu — ara bir sayı uydurmak, sayfadaki
   farklı punto sayısını §B2.1 tavanının üstüne çıkarırdı. Bedeli bilinerek ödendi: çubuk
   68 → ~72 px (bkz. `--topbar-h`). Marka artık başlıktaki en büyük öğe olmakla kalmıyor,
   sayfadaki her başlıktan da büyük — bir mağazanın kartviziti için doğru sıra. */
/* LOGO = GÖRSEL (2026-08-13). Yukarıdaki punto tartışmasının tamamı, logonun CSS ile dizilmiş
   bir KELİME olduğu döneme ait ve artık tarihçe: marka işareti Eyüp'ün verdiği SVG dosyası.
   Boyut hâlâ tipografi ölçeğinden okunuyor — `--text-display` (39 px) burada punto değil
   YÜKSEKLİK; logo, yanındaki 44 px'lik kontrollerle aynı optik ağırlıkta kalsın diye o ölçekte
   tutuluyor ve ölçek değişirse logo da onunla birlikte değişiyor.
   Genişlik ORANDAN doğar (`width:auto`): dosyanın oranı 5.105:1 ve bir gün yeni bir sürüm
   gelirse CSS'te sabit bir genişlik onu ezerdi. */
.logo{display:inline-flex;align-items:center;flex:none;
  text-decoration:none;min-height:var(--tap-min)}
.logo img{height:var(--logo-h);width:auto;display:block}
/* İki satırlı olduğu için dikey padding'le 52 px'e çıkıyordu; başlıktaki diğer her kontrol
   44 px. Yükseklik SABİTLENİR, iki satır içeride ortalanır — başlıkta tek bir kontrol
   yüksekliği olur (§B5). */
/* TEK SATIR: iki satırlı çip, başlığın en karmaşık öğesiydi ama en önemli işi değil.
   Ad + mahalle kalın, teslimat penceresi soluk; dar ekranda pencere düşer. */
.addr-chip{display:flex;align-items:center;gap:var(--space-2);background:var(--on-primary-soft);
  border:0;color:var(--on-primary);font:inherit;font-size:var(--text-label);font-weight:var(--w-bold);
  padding-block:0;padding-inline:var(--space-4);min-width:0;
  height:var(--control-h);min-height:var(--control-h);border-radius:var(--radius-pill);
  cursor:pointer;text-align:left;line-height:var(--lh-none);white-space:nowrap}
.addr-main{overflow:hidden;text-overflow:ellipsis;min-width:0}
.addr-main{font-weight:var(--w-bold)}
.addr-chip:hover{background:var(--on-primary-soft-hi)}
.addr-chip svg:last-child{width:var(--icon-sm);height:var(--icon-sm);opacity:.7}
/* Artan yer, max-width'e takılan aramadan sonra TEK bir boşlukta birikiyordu:
   acct→cart 54 px, diğer tüm boşluklar 16 px. margin-inline:auto artığı iki yana eşit
   böler; sol grup (logo+adres) ve sağ grup (hesap+sepet) kendi içinde sıkı kalır,
   arama ikisinin ortasında durur — Gestalt yakınlık (§C2) ile okunan bir gruplama. */
/* [DEĞİŞTİ 2026-08-12 · iki tasarım incelemesinde birden] Kutu TAM KAPSÜLDÜ (--radius-pill,
   9999px). İki gerekçeyle 12 px'e (--radius-lg) çekildi:
     · Sistemde kapsül BİR ROL taşıyor — rozet, durum, filtre çipi. Bir GİRDİ alanının aynı
       geometriyi kullanması rolü siliyor; ölçüldü, sayfada 12 öğe kapsül / 9 öğe 12 px'ti.
     · Kart, panel ve modal zaten 12 px. Girdinin onlarla aynı dili konuşması, kutuyu sayfaya
       ait kılıyor — kapsül hâli "arama motoru kutusu" gibi duruyordu.
   Yükseklik ve genişlik DEĞİŞMEDİ (44 px / 380 px): burada değişen yalnız geometri. */
.searchbox{width:var(--search-max);max-width:100%;min-width:var(--search-min);
  display:flex;align-items:center;gap:var(--space-2);
  background:var(--surface);border-radius:var(--radius-lg);padding-inline:var(--space-4);
  min-height:var(--tap-min);color:var(--text-2)}
.searchbox svg{flex:none;width:var(--icon-md);height:var(--icon-md)}
/* Girdi kabın YÜKSEKLİĞİNİ doldurur. Önceden yalnız 24 px yüksekliğindeydi ve hapın üst/alt
   ~10 px'ine tıklamak odağı vermiyordu — görünen hedef 44 px, gerçek hedef 24 px (ölçüldü
   2026-08-09: elementFromPoint kabın üstünde FORM döndürüyordu). WCAG 2.5.8 dokunma hedefi
   GÖRÜNEN değil TIKLANAN alandır. */
/* [KUSUR 2026-08-10 · denetim E1] Font 14 px'ti (--text-label). iOS, 16 px altındaki bir girdiye
   dokunulduğunda sayfayı KENDİLİĞİNDEN yakınlaştırıyor ve kullanıcı geri çıkamıyor — arama kutusu
   HER sayfada olduğu için mobilde en sık dokunulan alan tam da bu. §F: "girdi font ≥16 px".
   Görsel ölçek değişimi kabul edildi: zıplayan bir sayfa, 2 px'lik puntodan pahalı. */
.searchbox input{border:0;outline:0;font:inherit;font-size:var(--text-body);flex:1;
  background:none;color:var(--text);min-width:0;align-self:stretch;min-height:var(--tap-min)}
/* Sayfa içindeki arama kutusu (§bkz. _Search). Üst çubuktaki 380 px'lik sabit genişlik burada
   yanlış: kutu bir yan öğe değil, tezgâhın giriş kapısı — bulunduğu şeridi doldurur.
   Zemin `--surface`: sayfa zemini zaten `--quiet` tonunda ve kutu ondan AYRILMALI, yoksa
   tıklanabilir bir alan olduğu okunmuyor. */
/* ---------- ARAMA KUTUSU: ÇUBUĞUN ORTA ŞERİDİNİN TAMAMI ----------

   [KARAR 2026-08-20 · Eyüp · /demo/ust #1 "Arama dominant"] Kutu buraya kadar `--search-max`
   (380 px) kadar genişleyip `margin-inline:auto` ile ortalanıyordu; orta sütunun kalanı boş
   kalıyordu. Artık sütunun TAMAMINI alıyor.

   Gerekçe içerikten değil HİYERARŞİDEN geliyor. Eski notun ("girdi genişliği içeriğe göre
   belirlenir; aranan şey iki-üç kelime") mantığı bir yan öğe için doğruydu — ama bu sayfada
   arama bir yan öğe değil, tezgâhın giriş kapısı. Dominans alan × konum × kontrast; kutu
   konumu ve kontrastı zaten sabitken elimizdeki tek vekil alan.

   `min-width:0` ŞART: `--search-min` (200 px) taban olarak kalsaydı 390 px'lik ekranda kutu
   yan gruplarla birlikte satırı taşırırdı. Taban artık sütunun kendisi.

   [SİLİNDİ 2026-08-20] `.searchbox--inset` ve onun iki medya sorgusu. Kutu ≤767'de sayfaya
   iniyordu, yani aynı kontrolün ekran genişliğine göre İKİ AYRI yeri vardı. Tek yer kaldı;
   `Catalog/_Search.cshtml` de bu yüzden silindi. */
.searchbox--top{width:100%;max-width:none;min-width:0;
  /* Adres öneki kabın soluna dayanıyor; hover zemini yuvarlak köşenin dışına taşmasın. */
  overflow:hidden}

/* ADRES, KUTUNUN İÇİNDE ÖNEK. Ayrı bir çip değil — iki kontrol tek kontrole indi (bkz. TopBar).
   Sağındaki saç teli tek kutuyu iki ALANA bölüyor: kullanıcı nereye yazacağını görmeli. */
.search-addr{display:flex;align-items:center;gap:var(--space-1);flex:none;min-width:0;
  max-width:13rem;align-self:stretch;
  padding-inline:var(--space-3) var(--space-4);
  /* Kabın kendi sol payını geri alıyor: önek kutunun kenarından başlamalı. */
  margin-left:calc(var(--space-4) * -1);
  border-right:var(--border-hairline) solid var(--divider);
  color:var(--primary-pressed);text-decoration:none;
  font-size:var(--text-label);font-weight:var(--w-bold);line-height:var(--lh-none)}
.search-addr:hover{background:var(--primary-soft)}
.search-addr svg{width:var(--icon-sm);height:var(--icon-sm)}
.search-addr-tx{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
/* ---------- DAR EKRAN: KUTU YERİNE İKON (≤900 px) ----------

   [KARAR 2026-08-22 · Eyüp · TARAYICIDA ÖLÇÜLDÜ] Kutu her genişlikte çubuktaydı ve dar ekranda
   kendi satırına da inmiyordu. Ölçüm (390 px iframe — Chrome 390'a inmiyor):

     girişli  → kap 175,9 px · GERÇEK yazma alanı  86,9 px
     misafir  → kap 101,6 px · GERÇEK yazma alanı  41,6 px
     yer tutucu ("domates, maydanoz, kabak…") ihtiyacı 208,9 px → ekranda "domates, m"

   Yani kullanıcı ~10 karakterlik bir pencereye yazıyordu; "maydanoz" tek başına 75,5 px, kutuda
   11 px kalıyordu. O genişlikte bu bir kutu değil, kutu taklidiydi.

   KIRILIM TEK VE ÖLÇÜYLE KONDU. Yazma alanı ≈ `viewport − 644 px` (adres adı + sepet düğmesi
   varken); yer tutucunun 208,9 px'i için 853 px gerekiyor, uzun adres etiketi
   ("Caferağa Mah., Kadıköy" = 158 px) 34 px daha yiyor → 887 px. 900, onun bir üstündeki
   yuvarlak sayı.

   AYNI KURAL 641–900 BANDINDAKİ AYRI KUSURU DA KAPATIYOR. O bantta adres ADI ve sepet düğmesi
   geri geldiği için kutu mobilden de dardı: 700 px'te yazma alanı 56 px (390 px'tekinden az),
   768 px'te 124 px. Üç ayrı ayarlanmış eşik yerine tek kural — şema, öğe sayısının değiştiği
   yerde değişir (§R2.4).

   SEPET DÜĞMESİNE DOKUNULMADI: onu ≤640'ta gizleyen kural alt sepet çubuğuyla eşleşiyor
   (`.cart-bar` da ≤640). Eşiği yukarı taşımak 641–900'de sepeti hiçbir yerde bırakmayan bir
   boşluk açardı. */
/* ≥901'de tetikleyici YOK: kutunun kendisi zaten orada. */
.search-open{display:none}

@media (max-width:900px){
  /* Kutu KAP olmaktan çıkar, saydam bir satıra döner. Form DOM'da KALIYOR: `role="search"` yer
     imi ve JS'siz gönderim onunla, adres öneki de onun çocuğu — kutuyu komple gizleseydik önek
     de onunla birlikte düşerdi. */
  .searchbox--top{background:none;border-radius:0;padding-inline:0;min-height:0;
    overflow:visible;gap:var(--space-3)}
  .searchbox--top:focus-within{outline:0}
  /* Kutunun kendi büyüteci ve yazma alanı düşer. `display:none` bilinçli: görünmez ama
     odaklanabilir bir girdi bırakmak, klavye kullanıcısını hiçbir yere götürmeyen bir alana
     sokmak olurdu (§E). */
  .searchbox--top>svg,.searchbox--top input,.searchbox--top label{display:none}

  /* ADRES KENDİ ÇİPİ OLUR. Kutu-içi önek geometrisi (negatif marj, sağdaki saç teli) burada
     anlamsız: bölünecek bir kutu yok. Renk de değişir — beyaz kabın içinde koyu yeşildi, marka
     yeşilinin üstünde beyaz olmalı (kontrast). */
  .search-addr{max-width:none;min-width:0;flex:0 1 auto;margin-left:0;border-right:0;
    padding-inline:var(--space-3);gap:var(--space-2);
    background:var(--on-primary-soft);color:var(--on-primary);
    border-radius:var(--radius-pill);min-height:var(--tap-min)}
  .search-addr:hover{background:var(--on-primary-soft-hi)}

  /* Tetikleyici SAĞA yaslanır: ara · sepet · hesap üç ikon tek grup olarak okunmalı (§C2
     yakınlık). Ortada bırakmak aynı işi yapan kontrolleri ikiye bölerdi. */
  .search-open{display:flex;align-items:center;justify-content:center;flex:none;
    margin-left:auto;width:var(--tap-min);min-height:var(--tap-min);
    background:var(--on-primary-soft);color:var(--on-primary);
    border-radius:var(--radius-pill);text-decoration:none}
  .search-open:hover{background:var(--on-primary-soft-hi)}
  .search-open svg{width:var(--icon-lg);height:var(--icon-lg)}
}

/* ADRES ADI ARTIK DÜŞMÜYOR — ama yalnız girişlide.

   [DEĞİŞTİ 2026-08-22] Burada `.search-addr-tx{display:none}` yazıyordu ve gerekçesi "390 px'te
   ad kutunun yarısını yiyor"du. Kutu gidince gerekçe de gitti: ad, kalan yerin tamamını alıp
   taşarsa kırpılıyor. Kazanılan bilgi küçük değil — fiyat, stok ve şube ADRESE bağlı ve mobilde
   hangi adreste olduğu HİÇ görünmüyordu.

   Misafirdeki önek başka bir şey söylüyor ("Bölgende var mıyız?") ve o bir davet, karar bilgisi
   değil; yanında duran "Giriş yap" düğmesi 118 px yiyor. ≤640'ta yalnız o düşer. */
@media (max-width:640px){
  /* [KUSUR 2026-08-28 · PageSpeed erişilebilirlik denetimi] Burada `display:none` yazıyordu ve
     düşürdüğü şey yalnız piksel değildi: `display:none` öğeyi ERİŞİLEBİLİRLİK AĞACINDAN da
     siler. Geriye ikondan ibaret, ADSIZ bir bağlantı kalıyordu — ekran okuyucu "bağlantı" deyip
     susuyor, nereye gittiği söylenmiyor.

     Kusur ancak MOBİLDE var (kural ≤640'ta), masaüstünde öğe zaten görünmüyor; bu yüzden
     masaüstü denetimlerine hiç yakalanmadı. 390 px'te axe `link-name` ile doğrulandı: düzeltme
     öncesi 1 ihlal, sonrası 0.

     Kalıp `.sr` ile aynı (bkz. ~satır 300) ve metin İŞARETLEMEDE kalıyor: `aria-label` ile
     kopyalasaydık aynı cümle iki yerde yaşar, biri değişince öbürü sessizce eskirdi.
     Görünen düzen değişmez — mutlak konumlu çocuk flex öğesi sayılmaz, `gap` de eklenmez. */
  .search-addr--ask .search-addr-tx{position:absolute;width:var(--border-hairline);
    height:var(--border-hairline);overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
}

/* ---------- ARAMA KATMANI — kutunun AÇILMIŞ hâli (bkz. _SearchDialog) ----------
   Tam ekran: dar ekranda arama, sayfanın bir köşesi değil işin kendisidir. Klavye açıkken
   ekranın yarısı gidiyor; kalan yarıda hem yazma alanı hem son aramalar hem reyonlar duruyor —
   87 px'lik kutunun asla gösteremeyeceği şeyler. */
.search-dlg{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh}
/* Perde görünmez: katman ekranın tamamını kaplıyor, arkasında karartılacak bir şey kalmıyor. */
.search-dlg::backdrop{background:var(--surface)}
.search-sheet{display:flex;flex-direction:column;height:100dvh;background:var(--surface)}
/* Üst şerit kaydırmaz: kullanıcı listeyi kaydırırken yazma alanı ve çıkış hep yerinde (§H1). */
.search-sheet-hd{flex:none;display:flex;align-items:center;gap:var(--space-2);
  padding:var(--space-3) var(--grid-margin);
  padding-top:calc(var(--space-3) + env(safe-area-inset-top, 0px));
  border-bottom:var(--border-hairline) solid var(--divider)}
/* Üst çubuktaki kutunun sabit ölçüleri burada yanlış: kutu şeridin kalanını doldurur.
   Zemin `--quiet` — kabuk beyaz, kutu ondan AYRILMALI ki yazılacak yer olduğu okunsun. */
.searchbox--sheet{flex:1;width:auto;max-width:none;min-width:0;background:var(--quiet)}
/* `[hidden]` bu düğmede AÇIKÇA yazılmalı: `display:flex` UA'nın `display:none`unu ezerdi ve
   temizleme düğmesi boş kutuda da durur, hiçbir şey yapmayan bir hedef olurdu (§M5). */
.search-clear{flex:none;display:flex;align-items:center;justify-content:center;
  width:var(--tap-min);min-height:var(--tap-min);margin-right:calc(var(--space-4) * -1);
  border:0;background:none;color:var(--text-2);cursor:pointer;border-radius:var(--radius-pill)}
.search-clear[hidden]{display:none}
.search-clear:hover{background:var(--divider);color:var(--text)}
.search-sheet-bd{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;
  display:grid;gap:var(--space-6);align-content:start;
  padding:var(--space-6) var(--grid-margin)
          calc(var(--space-6) + env(safe-area-inset-bottom, 0px))}
.search-block{display:grid;gap:var(--space-3)}
.search-block-hd{font-size:var(--text-label);font-weight:var(--w-bold);color:var(--text-2)}
.search-chips{display:flex;flex-wrap:wrap;gap:var(--space-2)}
/* İskelet çip genişlikleri: gerçek reyon adları eşit uzunlukta değil, iskelet de olmamalı —
   altı eşit kutu "yükleniyor" değil "tablo" gibi okunur (§A4.1). */
.search-chips .sk{width:5.5rem}
.search-chips .sk:nth-child(2){width:7rem}
.search-chips .sk:nth-child(3){width:4.5rem}
.search-chips .sk:nth-child(4){width:6.5rem}
.search-chips .sk:nth-child(5){width:5rem}
.search-chips .sk:nth-child(6){width:8rem}
.search-rows{display:grid}
.search-row{display:flex;align-items:center;gap:var(--space-2)}
.search-row-go{flex:1;min-width:0;display:flex;align-items:center;gap:var(--space-3);
  min-height:var(--tap-min);padding-inline:var(--space-2);border-radius:var(--radius-lg);
  color:var(--text);text-decoration:none}
.search-row-go svg{flex:none;width:var(--icon-md);height:var(--icon-md);color:var(--text-2)}
.search-row-go span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.search-row-go:hover{background:var(--quiet)}
/* Kaldırma satırın PARÇASI ama birincil değil: hedef 44 px, ikon 16 px (§A9.2). */
.search-row-x{flex:none;display:flex;align-items:center;justify-content:center;
  width:var(--tap-min);min-height:var(--tap-min);border:0;background:none;
  color:var(--text-2);cursor:pointer;border-radius:var(--radius-lg)}
.search-row-x svg{width:var(--icon-sm);height:var(--icon-sm)}
.search-row-x:hover{background:var(--quiet);color:var(--text)}
/* Odak halkası girdide `outline:0` ile kapatılmıştı; halka kabın kendisinde verilir
   (telefon alanıyla aynı desen) — WCAG 2.4.7. */
.searchbox:focus-within{outline:var(--border-focus) solid var(--focus);outline-offset:2px}
/* skip link — ilk odaklanabilir öğe (§0.6 / §E) */
.skip{position:absolute;left:var(--space-4);top:calc(var(--space-16) * -1);z-index:60;
  background:var(--surface);color:var(--primary-pressed);font-weight:var(--w-bold);
  padding:var(--space-3) var(--space-4);border-radius:var(--radius-lg);
  box-shadow:var(--elev-float);text-decoration:none;transition:top var(--dur-micro) var(--ease-out)}
.skip:focus-visible{top:var(--space-3)}

/* Hesap menüsünün konumlandığı kutu. Menü position:absolute; kapsayıcı relative olmazsa
   sayfanın en üstüne kaçar. */
.acct-wrap{position:relative;display:flex}

/* Prototipte <button>du, web'de gerçek adresleri olduğu için <a> oldular (adres çipi → adres
   sayfası, menü satırları → hesap sayfaları). Tarayıcı varsayılanı sıfırlanmazsa üst çubuk
   altı çizili bağlantılarla dolar (§6.3b — bu tuzağa bu projede üçüncü kez düşülüyor). */
a.addr-chip{text-decoration:none}
.acct-menu a{text-decoration:none}
.acct-btn{display:flex;align-items:center;gap:var(--space-2);background:var(--on-primary-soft);
  border:0;color:var(--on-primary);font:inherit;font-size:var(--text-label);
  font-weight:var(--w-bold);padding-inline:var(--space-3);min-height:var(--tap-min);
  border-radius:var(--radius-pill);cursor:pointer;text-decoration:none;white-space:nowrap;
  transition:background var(--dur-micro) var(--ease-out)}
.acct-btn:hover{background:var(--on-primary-soft-hi)}
.acct-btn svg:last-child{width:var(--icon-sm);height:var(--icon-sm);opacity:.7}
.acct-btn--ico{width:var(--tap-min);padding-inline:0;justify-content:center}
.acct-btn--ico svg{width:var(--icon-lg);height:var(--icon-lg)}
.acct-menu{position:absolute;right:0;top:calc(100% + var(--space-2));z-index:50;
  background:var(--surface);color:var(--text);border-radius:var(--radius-xl);
  box-shadow:var(--elev-float);min-width:calc(var(--control-h) * 5);padding:var(--space-2);
  display:grid;gap:var(--space-1)}
.acct-menu[hidden]{display:none}
.acct-head{padding:var(--space-3);border-bottom:var(--border-hairline) solid var(--divider);
  margin-bottom:var(--space-1);display:grid;gap:var(--space-1)}
.acct-head small{color:var(--text-2);font-size:var(--text-caption)}
.acct-menu a,.acct-menu button{display:flex;align-items:center;gap:var(--space-3);
  font:inherit;font-size:var(--text-label);font-weight:var(--w-semibold);text-align:left;
  color:var(--text);background:none;border:0;cursor:pointer;text-decoration:none;
  padding:var(--space-3);border-radius:var(--radius-md);min-height:var(--control-h-sm);
  transition:background var(--dur-micro) var(--ease-out)}
.acct-menu a:hover,.acct-menu button:hover{background:var(--quiet)}
.acct-menu svg{color:var(--text-2)}
.acct-menu [data-logout]{color:var(--danger);margin-top:var(--space-1);
  border-top:var(--border-hairline) solid var(--divider);border-radius:0}
.acct-menu [data-logout] svg{color:var(--danger)}

/* Accent'ten çıkarıldı: turuncu, sayfadaki gerçek çağrılar için ayrılmış
   ("Sepete ekle", "Ödemeye geç"). Başlıkta kalıcı duran bir accent düğme onları zayıflatıyordu. */
.cart-btn{display:flex;align-items:center;gap:var(--space-2);background:var(--on-primary-soft);
  color:var(--on-primary);border:0;font:inherit;font-weight:var(--w-bold);font-size:var(--text-label);
  padding-inline:var(--space-4);min-height:var(--tap-min);border-radius:var(--radius-pill);
  cursor:pointer;text-decoration:none;font-variant-numeric:tabular-nums;flex:none;
  white-space:nowrap}
.cart-btn svg{width:var(--icon-md);height:var(--icon-md)}
.cart-btn:hover{background:var(--on-primary-soft-hi)}
.cart-btn--gate{background:var(--surface);color:var(--primary-pressed)}
.cart-btn--gate:hover{background:var(--pine-050)}
/* Tutar büyüdükçe düğme genişlemesin — yoksa flex olan arama kutusu her eklemede
   yeniden boyutlanır ve başlık "hoplar". Yer baştan ayrılır, sayı sağa yaslanır. */
[data-cart-total]{display:inline-block;min-width:var(--money-w);text-align:right}
/* Kalem sayısı ROZET olarak ikonun üstünde (§J3) — yatayda yer yemez, kalıp tanıdık */
.cart-ico{position:relative;display:grid;place-items:center;flex:none}
.cart-badge{position:absolute;top:calc(var(--space-2) * -1);right:calc(var(--space-2) * -1);
  min-width:var(--space-4);height:var(--space-4);padding-inline:var(--space-1);
  border-radius:var(--radius-pill);background:var(--surface);color:var(--primary-pressed);
  font-size:var(--text-micro);font-weight:var(--w-bold);line-height:var(--space-4);
  text-align:center;font-variant-numeric:tabular-nums}
.cart-badge[hidden]{display:none}


/* ---------- BAŞLIK — dar ekran ----------
   ≤640: SEPET ALT ÇUBUĞA iner, hesap ikon-only olur, logo bir kademe küçülür.
         Sepet hem üstte hem altta = gürültü (§J3).

   [DÜZELTİLDİ 2026-08-21] Burada bir de "≤960: arama kendi satırına iner" satırı vardı ve
   aşağıdaki blok "yerleşim 960 bloğundan devralınır (`side end` / `search search`)" diyordu.
   İkisi de ÖLÜ ATIFTI: o blok 14 Ağustos'ta silindi (aşağıdaki KUSUR notu) ve bu dosyada
   `grid-template-areas` hiç yok. Yorum, anlattığı davranışı olmayan bir yorumdu.

   [ÖLÇÜLDÜ 2026-08-22 · o not kapandı] Kutuya kalan gerçek yazma alanı 390 px'te 86,9 px
   (misafirde 41,6 px) ölçüldü; yer tutucunun ihtiyacı 208,9 px'ti. Kutu artık ≤900'de hiç
   basılmıyor — yerini arama ikonu + tam ekran katman alıyor (bkz. yukarıdaki "DAR EKRAN"
   bloğu). Bu blokta kalan iş yalnız SEPET ve HESAP kontrolleri; arama ve adres orada
   çözülüyor. */
/* [KUSUR 2026-08-14 · R8 checklist'i koşarken ölçüldü] Burada `@media (max-width:1024px)` ile
   `.topbar .in{grid-template-columns:minmax(0,1fr) auto}` yazıyordu ve yorumu "Arama üst
   çubuktan ÇIKTI, kalan iki grup tek satırda" diyordu. Ama aramayı gizleyen kural 1024'te değil
   **767**'de: iki kırılım birbirini tutmuyordu.

   Sonuç 768–1024 bandında ölçüldü: arama kutusu HÂLÂ BASILIYOR (3 çocuk) ama ızgarada 2 sütun
   var; üçüncü grup ikinci satıra sarıyor ve yapışkan üst çubuk 68 → **124 px** oluyordu.
   Fazladan 56 px, doğrudan ilk ekrandan çalınıyor (§R4.1).

   Yer sorunu da yoktu: 1024'te içerik 960 px ve bu, 1025'tekiyle AYNI — üç sütun (347+389+192)
   oraya da sığıyor. Kural yalnız yanlış kırılımdaydı.

   Blok kaldırıldı; iki sütunluk şema aramanın gerçekten gizlendiği yerde (≤767) zaten tanımlı.
   `gap` de oraya taşındı. Aynı sınıf hata bu dosyada üçüncü kez: ŞEMA, ÖĞE SAYISI DEĞİŞTİĞİ
   YERDE değişmeli — bir kırılım önce ya da sonra değil (§R2.4 ile aynı aile). */
@media (max-width:640px){
  /* Sütun şeması DEĞİŞMİYOR: `.topbar .in` her genişlikte içerik sayısına göre kuruluyor
     (aramalı 3, aramasız 2 sütun). Burada yalnız kontrollerin kendisi değişiyor. */
  .cart-btn{display:none}
  /* Misafirde .cart-btn YERİNE giriş düğmesi duruyor; onu da gizleyince başlıkta
     yalnız etiketsiz kişi ikonu kalıyordu — sitenin TEK kapısı bilmeceye dönüyor.
     Kapı görünür kalır, yanındaki ikon-only kopyası kalkar (aynı iş, iki düğme). */
  .cart-btn--gate{display:flex}
  .acct-btn--ico[data-open-auth]{display:none}
  /* [KUSUR 2026-08-12 · kritik] Burada `.acct-btn svg:last-child` yazıyordu ve amaç METİNLİ
     varyanttaki sondaki chevron'u gizlemekti. Ama ikon-only varyantta svg BİR TANE — o tek svg
     aynı zamanda `:last-child`. Kural, gizlemesi gereken oku değil kişi ikonunun KENDİSİNİ
     siliyordu: girişli her müşteri, her sayfada, 44×44'lük bomboş bir yeşil daire görüyordu —
     üstelik hesap menüsüne giden tek kapı o.
     Ölçüldü: seçici ikon-only svg'yi tutuyor (`svg.matches(...)` → true), buton içinde tek svg var
     ve o `:last-child`. Kırılma noktası tam bu medya sorgusu.
     `:not(.acct-btn--ico)` ile chevron kuralı ait olduğu varyanta kilitlendi. */
  .acct-btn span,.acct-btn:not(.acct-btn--ico) svg:last-child{display:none}
  .acct-btn{padding-inline:var(--space-3)}
  .addr-chip{padding-inline:var(--space-3)}
  /* Dar ekranda gövde metniyle aynı boydaydı (16 px) — marka, bir paragrafla aynı ağırlıkta.
     Masaüstündeki kademeyle aynı oranda iniyor: bir basamak küçülür, gövdeye düşmez.
     [2026-08-13 · Eyüp: "mobilde logo gerçekten küçük duruyor" · doğrulandı] 20 px'ti ve
     masaüstü 31 iken mobil 20 demek, markanın telefonda reyon başlığıyla (20 px) aynı boyda
     olması demekti — oysa telefonda başka hiçbir marka işareti yok. 25 px: tek satırda kalıyor,
     44 px'lik dokunma hedefini büyütmüyor, sağdaki iki kontrolün yerini yemiyor.
     Kare app ikonu bilerek KULLANILMADI: iki satırlı kilit (man/avda) ve kendi yeşil karosu
     bir launcher için tasarlandı; 72 px'lik çubukta ya karo kenarı görünür ya iki satır ezilir.
     [2026-08-13] Logo artık SVG; kural punto değil YÜKSEKLİK veriyor. Ölçek aynı kaldı (25 px),
     değişen yalnız neyin ölçüldüğü. */
  .logo img{height:var(--logo-h-sm)}
}

/* ---------- mobil alt sepet çubuğu (§H1/H2 — birincil aksiyon başparmak bölgesinde) ---------- */
.cart-bar{position:fixed;left:0;right:0;bottom:0;z-index:45;display:none;
  align-items:center;gap:var(--space-4);background:var(--surface);
  border-top:var(--border-hairline) solid var(--divider);
  box-shadow:var(--elev-bar);
  padding:var(--space-3) var(--grid-margin);
  padding-bottom:calc(var(--space-3) + env(safe-area-inset-bottom))}
.cart-bar .sum{display:grid;gap:var(--space-1);min-width:0}
.cart-bar .sum b{font-size:var(--text-h3);font-weight:var(--w-black);
  letter-spacing:var(--tr-h3);font-variant-numeric:tabular-nums;line-height:var(--lh-none)}
.cart-bar .sum small{font-size:var(--text-caption);color:var(--text-2)}
.cart-bar .btn{margin-left:auto;flex:none}
@media (max-width:640px){
  .cart-bar[data-has="1"]{display:flex}
  /* Alt yerleşim TEK kaynaktan (aşağıdaki --bottom-inset). Buradaki üç kural dosyanın
     sonundaki medya-dışı bildirimlerle eziliyordu: toast sepet çubuğunun ALTINDA kalıyor,
     scroll-padding 72 → 16 px'e düşüyordu (WCAG 2.4.11 için yazılan kural ölüydü). */
  html:has(.cart-bar[data-has="1"]){--bar-live:var(--bar-h)}
}

/* Kategori rayı — KATALOG BÖLÜMÜNÜN başında, o bölüm boyunca yapışık.
   Üst çubuğun içindeyken filtrelediği listeden 1500 px uzaktaydı; kontrol
   etkilediği içeriğin bitişiğinde durur. */
/* RAY ARTIK YAPIŞKAN DEĞİL — SAYFANIN AKIŞINDA, BAŞLIĞIN ALTINDA.

   [KARAR 2026-08-13 · Eyüp: "catbar kötü, tasarım da UX de"] Önce kart görünümü (gölge+köşe)
   kaldırılmıştı; yetmedi, çünkü asıl sorun görünüş değil KALICILIKTI. Zincir şöyleydi:
     ray kalıcı → "hangi reyondayım" göstergesi gerekiyor → gösterge için scroll-casusu yazıldı
     → casusun referans çizgisi ile çapa hedefi iki ayrı yerde hesaplandı → çift telafi
   Ölçülen sonuç: çipe basınca başlık hedefin 84 px altına düşüyor ve gösterge bir bölüm geride
   kalıyordu ("Meyve"ye bas, "Yeşillik" yazsın).

   Ray akışa inince zincirin TAMAMI gereksizleşiyor:
     · Kalıcı değilse "neredeyim" göstergesi de gerekmiyor → casus mantığı silindi (aisle-nav.js)
     · Yapışkan katman yoksa çapa payı da gerekmiyor → `.aisle` ve `.section` scroll-margin'leri
       silindi; kökteki `scroll-padding-top` (üst çubuk + 16) tek kaynak olarak kaldı
     · `--catbar-h` token'ı ve onu ölçen JS satırı da öldü
   Kazanç ölçüldü: yapışkan katman 137 → 68 px, yani ekranın %7'si alışverişe geri döndü.

   Ölçüm şu da diyordu: 3 çip = 244 px mürekkep, şerit 1181 px — %79'u boş. Tam genişlikte
   beyaz bir bandı %21 doldurmak, boşluğu tasarım gibi göstermekti. Zemin ve kenarlık kalktı;
   çipler artık başlığın altında duran sıradan bir satır. */
.catbar{margin-bottom:var(--space-6)}
/* Yatay pay SIFIR: çipler bölüm başlığı ve ürün ızgarasıyla AYNI hizadan başlar. 16 px'lik
   iç pay, kart görünümünün kalıntısıydı ve rayı sayfanın hizasından kaydırıyordu (§C2). */
.catbar .in{display:flex;gap:var(--space-2);align-items:center;overflow-x:auto;overflow-y:hidden;
  padding:var(--space-3) 0;scrollbar-width:none}
.catbar .in::-webkit-scrollbar{display:none}

/* ---------- buton ---------- */
.btn{font:inherit;font-size:var(--text-label);font-weight:var(--w-bold);line-height:var(--lh-none);
  display:inline-flex;align-items:center;justify-content:center;gap:var(--icon-gap);
  padding:var(--space-2) var(--space-6);min-height:var(--control-h);
  border:var(--border-emphasis) solid transparent;border-radius:var(--radius-lg);cursor:pointer;
  text-decoration:none;transition:background var(--dur-micro) var(--ease-out),
    color var(--dur-micro) var(--ease-out),
    border-color var(--dur-micro) var(--ease-out),transform var(--dur-press) var(--ease-out)}
.btn:active{transform:scale(.97)}
.btn svg{width:var(--icon-md);height:var(--icon-md)}
.btn--primary{background:var(--primary);color:var(--on-primary)}
.btn--primary:hover{background:var(--primary-hover)}
.btn--quick{background:var(--quick);color:var(--quick-ink)}
.btn--quick:hover{background:var(--pine-200)}
.btn--secondary{background:var(--surface);color:var(--primary-pressed);border-color:var(--control-border)}
.btn--secondary:hover{border-color:var(--primary);background:var(--primary-soft)}
/* katalogdaki "sepete ekle" — 100 kartta dolu yeşil duvar olmasın diye çerçeveli */
.btn--add{background:var(--surface);color:var(--primary-pressed);border-color:var(--primary)}
.btn--add:hover{background:var(--primary);color:var(--on-primary)}
.btn--ghost{background:transparent;color:var(--text-2);padding-inline:var(--space-3)}
.btn--ghost:hover{background:var(--quiet);color:var(--primary-pressed)}
.btn--danger{background:var(--surface);color:var(--danger);border-color:var(--danger)}
/* Satır içi mikro aksiyon — çerçevesiz, yalnız metin. Üç eşit ağırlıkta düğme
   yan yana durunca hiçbiri öne çıkmıyordu (buton taksonomisi). */
/* DEVRE DIŞI DÜĞME. [KUSUR 2026-08-22 · ölçüldü] Sitede `:disabled` kuralı hiç yoktu: dolu
   yeşil birincil düğme etkinken nasıl görünüyorsa devre dışıyken de aynı görünüyordu — bölge
   sorgusunda "Sorgula" seçim yapılmadan basılabilir sanılıyordu. Kural DÜĞMEYE yazılıyor
   (sayfaya değil): bu bir sayfa sorunu değil, tasarım sisteminde eksik bir durum.
   `pointer-events` KAPATILMAZ — imleç "yasak" işaretini gösterebilmeli. */
.btn:disabled{opacity:.45;cursor:not-allowed;box-shadow:none}
.btn:disabled:hover{background:inherit}
.btn--text{background:none;border-color:transparent;color:var(--primary);
  padding-inline:var(--space-2);min-height:var(--control-h-sm)}
.btn--text:hover{background:var(--primary-soft)}
/* yıkıcı ama sakin: her satırda kırmızı bir çerçeve, sayfayı alarma çeviriyordu */
.btn--text.btn--danger{background:none;border-color:transparent;color:var(--danger)}
.btn--text.btn--danger:hover{background:var(--danger-soft)}
/* KÜÇÜK DÜĞME, TAM DOKUNMA HEDEFİ.
   [KUSUR 2026-08-10] Ölçüldü: "Takip et" 113x40, "Kodu kopyala" 147x40 — kılavuzun kendi kontrol
   listesi ≥44 px istiyor (WCAG 2.5.5 pratik hedefi). Düğmeyi büyütmek "küçük" varyantını anlamsız
   kılardı; onun yerine GÖRÜNEN boyut aynı kalıp TIKLANAN alan 44'e tamamlanıyor. Aynı deyim
   `.term-btn`te zaten kullanılıyor.
   Yalnız DİKEY genişletme: yatayda düğmeler zaten geniş ve yan yana duran düğmeler (satır
   aksiyonları) birbirine girmemeli. */
.btn--sm{font-size:var(--text-caption);padding:var(--space-2) var(--space-4);
  min-height:var(--control-h-sm);position:relative}
.btn--sm::after{content:"";position:absolute;left:0;right:0;
  top:calc((var(--tap-min) - 100%) / -2);bottom:calc((var(--tap-min) - 100%) / -2)}
.btn--lg{font-size:var(--text-body);padding:var(--space-4) var(--space-8)}
.btn--block{width:100%}
.btn[aria-disabled="true"]{background:var(--quiet);color:var(--text-2);border-color:transparent;
  cursor:not-allowed}
/* SEÇİLEMEYEN ÇİP. [KUSUR 2026-08-10] Ödeme adımında geçmiş teslimat pencereleri
   `aria-disabled="true"` ile basılıyordu ama .chip için hiçbir kural yoktu — tarayıcıda ölçüldü:
   "Bu saat geçti" yazan pencere, seçilebilir pencereyle AYNI zemin ve AYNI kenarlıkla duruyordu.
   Kullanıcı hangisini seçebileceğini ancak alt satırdaki küçük yazıyı okuyarak anlıyordu.
   Öğe tıklanabilir KALIYOR (§M5.2: kilitli kontrol sebebini söylemez; basılır, sebep söylenir) —
   değişen yalnız görünüm: sönük zemin, kesikli kenar, gri metin. */
.chip[aria-disabled="true"]{background:transparent;color:var(--text-2);
  border-style:dashed;border-color:var(--divider);cursor:not-allowed}
.chip[aria-disabled="true"]:hover{background:transparent;color:var(--text-2)}
/* iki uçlu liste satırı (mahalle seçimi gibi) */
.btn--row{justify-content:space-between;text-align:left;width:100%}
.btn--row .rowtx{display:grid;gap:var(--space-1)}
.btn--row .rowtx small{font-weight:var(--w-regular);color:var(--text-2);font-size:var(--text-caption)}
.spinner{width:var(--icon-sm);height:var(--icon-sm);
  border:var(--border-emphasis) solid currentColor;border-right-color:transparent;
  border-radius:var(--radius-pill);animation:spin .7s linear infinite;flex:none}
/* ---------- 3D Secure: banka ekranı KATMANI ----------

   Doğrulama ekranı sayfanın içine gömülü DEĞİL, üstünde bir katman. Gerekçe görünümün başında
   (`ThreeDSecure.cshtml`): kart ödemesinin kullanıcı tarafından tanınan deseni bu — katman açılır,
   kod girilir, kapanır, altta "ödemen alınıyor" kalır.

   Katmanın kendisi `.modal` — sitenin diyalog dili (giriş katmanı da aynısını kullanıyor).
   Ölçü ONA ait değil: `.modal` `--dialog-w` (440 px) ile sınırlı ve o bir FORM genişliği.
   Buradaki içerik bizim formumuz değil, bankanın sayfası.

   [KUSUR 2026-08-21 · denetim C1 · ölçüldü] Çerçeve bir form sütununa (`--field-w`, 520 px)
   hapsedilmişti: 1512 px masaüstünde banka belgesi 720 px istiyor, kutu 520 px veriyor → sağdan
   200 px KIRPILIYOR ve kullanıcı SMS kodunu yazacağı satırı ancak çerçeveyi yatay kaydırarak
   görüyordu. 390 px telefonda taşma 362 px'ti.

   Genişlik KATMANA BAĞLI yazılıyor, yeni bir `.modal--*` varyantına değil. İki sebep:
     · `.modal--wide` ADI ZATEN ALINMIŞ (ayarlar katmanı, `--sheet-w` = 460 px). Onu ikinci kez
       tanımlamak, dosyanın hangi kuralının sonda kaldığına bağlı sessiz bir çakışma üretiyordu —
       yazıldığı gibi denendi ve modal 720 değil 460 px açıldı.
     · Bu ölçü bir "geniş modal" tercihi değil, bu ekrana ait bir zorunluluk: içeride bankanın
       sayfası var. Varyant adı vermek, ölçüyü başka katmanların da alabileceğini ima ederdi. */
.tds-dlg .modal{width:min(720px,calc(100vw - var(--space-8)))}

/* Çerçeve modalın gövdesi: `.bd`nin iç boşluğu YOK, çünkü banka sayfası kendi payını kendi
   veriyor ve dışarıdan eklenen her piksel onun genişliğinden çalıyor. Kenarlık de yok — kutu
   zaten modalın kendisi; iç içe iki çerçeve gürültüdür.

   Yükseklik bir TAVAN değil, katmanın verebileceği en büyük pay: bankaların doğrulama ekranı SMS
   kodu, uygulama onayı ya da tam bir form olabiliyor ve kısa tutmak formu kesiyor. Taban da var
   (420 px) — kısa ekranlarda çerçeve kullanılamaz hâle gelmesin. */
.tdsframe{width:100%;border:0;background:var(--surface);display:block;
  /* [DÜZELTİLDİ 2026-08-22 · denetim D8] Değerler px'ti; §11 "clamp() değerleri rem mi" diyor.
     Kullanıcı tarayıcı yazı boyutunu büyütünce px'lik bir çerçeve büyümez, içindeki banka formu
     büyür — yani tam da kaydırma üreten hâl. rem ile çerçeve metinle birlikte ölçekleniyor. */
  height:clamp(25rem,62vh,37.5rem);
  /* Modal bir sütun-flex ve tavanı var; çerçeve gerekirse KISALSIN, katmanı taşırmasın.
     `min-height:0` olmadan flex öğesi içerik tabanına kilitlenir ve kısalmayı reddeder. */
  min-height:0}

/* Tutar, kullanıcının bankanın SMS'iyle eşleştirdiği TEK referans — soluk değil, gövde ölçüsü. */
.tds-ctx{font-size:var(--text-body);color:var(--text)}

/* ---------- ONAY İŞARETİ (sipariş alındı) ----------
   Lottie DEĞİL, ÇİZİLEN YOL. Gerekçe görünümde (`Checkout/Result.cshtml`): `script-src 'self'`
   altında lottie-web'i kendimiz barındırmak gerekirdi ve ömürde bir kez görülen bir ekran için
   ~250 KB betik, üçüncü taraf fontu bile kaldırmış bir projede türdeş olmazdı.

   Teknik: yolun uzunluğu kadar `stroke-dasharray`, aynı kadar `stroke-dashoffset` — yol
   görünmez başlar ve offset sıfıra inerken çizilir. Halka önce, tik onun ardından. */
/* Ölçü ikon ölçeğinin DIŞINDA ve bilerek: bu bir ikon değil, ekranın kahramanının yanındaki
   onay anı. En büyük ikon token'ı (--icon-xl, 32px) burada cılız kalıyor. */
/* Ölçü ham değil token'dan (`--thumb-sm` = 56px) — denetim O5. */
.okmark{width:var(--thumb-sm);height:var(--thumb-sm);flex:none;
  fill:none;stroke:var(--primary);stroke-width:3;
  stroke-linecap:round;stroke-linejoin:round}
.okmark-ring{stroke-dasharray:151;stroke-dashoffset:151;
  animation:okmark-draw .45s var(--ease-out) forwards}
.okmark-tick{stroke-dasharray:36;stroke-dashoffset:36;
  animation:okmark-draw .3s var(--ease-out) .35s forwards}
@keyframes okmark-draw{to{stroke-dashoffset:0}}
/* Hareket kısıtlıysa işaret ÇİZİLMEZ, ama GÖRÜNÜR: animasyonu kapatmak yolu görünmez bırakırdı
   (offset başlangıç değerinde kalır), yani onay işareti hiç olmazdı. */
@media (prefers-reduced-motion:reduce){
  .okmark-ring,.okmark-tick{animation:none;stroke-dashoffset:0}
}

/* ---------- BÖLGE SORGUSU SONUCU (/bolge-talebi) ----------
   Cevabı taşıyan tek blok, iki yüzü var: geliyoruz / gelmiyoruz. Yeni bir görsel dil ÜRETMEZ —
   olumlu yüzde sitenin kendi `.okmark`'ını (çizilen yol), olumsuz yüzde durağan bir pin kullanır.
   Kötü haber çizilerek kutlanmaz.

   Zemin `alert` ailesinin yumuşak tonlarından: sonuç bir uyarı değil ama aynı "bu bir durum
   bildirimi" dilini konuşuyor. */
/* Sorgu bloğu. `.state` ortalar; İÇERİK ortalanmaz — etiket-kutu ikilisi sola yaslı okunur. */
/* SAYFA YÜZEYİ: kap ORTALANIR (`.solo`), içerik SOLA yaslanır.
   `.state` ortalaması bir KARŞILAMA ekranı içindir (404); burada altında bir FORM var ve
   ortalanmış etiket kutusuyla bağını kaybeder (§F: etiket üstte, sola yaslı). Başlık da sola
   iner — ortalanmış başlık + sola yaslı form aynı blokta iki ayrı eksen demek olurdu. */
.cvg-page{text-align:start;display:grid;gap:var(--space-3);justify-items:stretch}
/* Dar kabukta display ölçüsü taşıyor: 520 px'lik sütunda başlık üç satıra düşüyordu. */
.cvg-page h1{font-size:var(--text-h1)}
.cvg-page .state-lead{font-size:var(--text-body);max-width:none}
.cvg-page .cvg-form{margin-top:var(--space-6)}

/* ---------- BÖLGE SORGUSU ----------
   Tek parça, iki yüzey: `/bolge-talebi` sayfası ve global katman (`_CoverageDialog`).
   Ölçüyü YÜZEY verir, parça değil — sayfada `.solo` (520), katmanda `--dialog-w` (440).
   Parçanın kendisi kaba uyar. */
.cvg-form{width:100%;display:grid}
/* Aşamalar aynı yuvada: üst üste eklenmiyor, birbirinin yerini alıyor. */
.cvg-stage{display:grid;gap:var(--space-4);justify-items:stretch}
/* Kademe TEK SÜTUN. Kılavuz §F: tek kolon, çok kolondan ortalama 15,4 sn hızlı; iki yüzeyin
   dar olanı (440 px katman) zaten üç sütun kaldırmıyor. */
.cvg-q{display:grid;gap:var(--space-4)}
.cvg-act{display:flex;gap:var(--space-3);flex-wrap:wrap;align-items:center}
.cvg-geo{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}
/* Konum kısayolu kutulardan ÖNCE ve daha sessiz: kutu doldurmaya alternatif, rakip değil. */
.cvg-geo .btn{margin-inline-start:calc(var(--space-3) * -1)}
.cvg-subject{font-size:var(--text-label);color:var(--text-2);line-height:var(--lh-snug)}
.cvg{display:flex;gap:var(--space-4);align-items:center;text-align:start;
  padding:var(--space-4);border-radius:var(--radius-lg)}
.cvg[data-state="in"]{background:var(--primary-soft)}
.cvg[data-state="out"]{background:var(--warning-soft)}
.cvg-tx{display:grid;gap:var(--space-1);min-width:0}
.cvg[data-state="in"] .cvg-tx b{color:var(--primary-pressed)}
.cvg[data-state="out"] .cvg-tx b{color:var(--warning)}
/* İki yüz AYNI kutuyu doldurur ki geçişte blok zıplamasın. Sarmalayıcı span şart: `hidden`
   SVG'de işlemez (HTMLElement özelliği), o yüzden gizlenen şey span'dir. */
.cvg-mark,.cvg-pin{width:var(--thumb-sm);height:var(--thumb-sm);flex:none;display:grid;place-items:center}
.cvg-pin svg{width:var(--icon-xl);height:var(--icon-xl);color:var(--warning)}
/* ONAY AŞAMASI ortalanır: burada doldurulacak alan yok, okunacak tek bir cevap var. */
.cvg-done{justify-items:center;text-align:center;gap:var(--space-3)}
.cvg-done b{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3)}
.cvg-done-tx{font-size:var(--text-body);color:var(--text);line-height:var(--lh-snug)}

/* ---------- açılır kapanır satır ----------
   Sitenin kendi kalıbı: `aria-expanded` + `aria-controls` + chevron. Görünüm sessiz — bu bir
   aksiyon değil, bir kapak; basılınca altındaki dökümü açar. */
.disclose{width:100%;display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-3);min-height:var(--tap-min);padding:var(--space-3) var(--space-4);
  border:var(--border-hairline) solid var(--divider);border-radius:var(--radius-lg);
  background:transparent;color:var(--text);font:inherit;font-weight:var(--w-semibold);
  cursor:pointer;text-align:start}
.disclose:hover{background:var(--quiet)}
/* Chevron `aria-expanded`in GÖZLE görünen karşılığı — öznitelik ekran okuyucuya söylüyor.
   Yön kuralı teslimat saati kapağıyla AYNI (`.dmode .seg-i small svg`): chevron kaynağı sağa
   bakıyor (`m9 6 6 6-6 6`), kapalıyken çeyrek tur aşağı, açıkken çeyrek tur yukarı. Sitede iki
   ayrı açılır gösterge yönü olmamalı. */
.disclose svg{transform:rotate(90deg);
  transition:transform var(--dur-micro) var(--ease-out)}
.disclose[aria-expanded="true"] svg{transform:rotate(-90deg)}

/* AÇILAN DÖKÜM KAPAĞA YAPIŞIK. Aralarında boşluk bırakmak kapağı ve içeriğini iki ayrı kutu gibi
   gösteriyordu — bu ekranda düzeltilen "kutu çorbası"nın aynısını geri getiriyordu. Kapak açıkken
   alt köşeleri düzleşir, döküm de üstten kenarlıksız devam eder: tek bir nesne. */
.disclose[aria-expanded="true"]{border-bottom-left-radius:0;border-bottom-right-radius:0}
.disclose[aria-expanded="true"] + .sums{margin-top:calc(var(--space-2) * -1);
  padding:var(--space-4);background:transparent;
  border:var(--border-hairline) solid var(--divider);border-top:0;
  border-radius:0 0 var(--radius-lg) var(--radius-lg)}

/* ---------- renksiz bilgi listesi ----------
   İki renkli `alert` kutusunun yerine. Anlatılanlar bir UYARI değil bilgi; renkli kutu ikisini de
   "dikkat et" tonuna çekiyor ve üst üste gelince kutu çorbası üretiyordu (denetim 2026-08-22). */
/* ÖLÇÜ TAVANI (2026-08-22 · Eyüp: "kompozisyon kötü" · ölçüldü).
   Liste 520 px'lik bir kartın içinde yazılmıştı; onay ekranı iki sütuna geçince kap 876 px oldu
   ve satır 833 px'e, yani ~105 karaktere uzadı. Okunabilir tavan 60-75 karakter; sitenin kendi
   ölçüsü zaten 34rem (`.state-lead`, `.page-head p`). Tavan bileşenin kendisinde: bir NOT satırı
   hangi kapta olursa olsun bu ölçüden uzun olmamalı. */
.notelist{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3);max-width:34rem}
.notelist li{display:flex;gap:var(--space-3);align-items:flex-start;
  font-size:var(--text-label);line-height:var(--lh-snug);color:var(--text-2)}
.notelist li>svg{width:var(--icon-md);height:var(--icon-md);color:var(--text-2);
  margin-top:var(--space-1)}

/* Katmanın alt şeridi: solda kademeli mesaj, sağda çıkış. `.modal .ft` sağa yaslıyor; burada
   iki farklı iş var ve ikisi ekranın iki ucunda durmalı. Mesaj yokken şerit yalnız çıkışı
   taşır ve sağda kalır. */
.tds-ft{justify-content:space-between}
.tds-ft .lock-slow{margin:0;text-align:start}

/* JS YOKSA KATMAN YİNE GÖRÜNÜR. İşaretlemede `open` var; betik onu `showModal()`e yükseltiyor.
   Yükseltilmemiş (`:not(:modal)`) hâlde tarayıcının varsayılanı MUTLAK konumlandırma — o hâlde
   katman sayfanın üstüne biner ve okunamaz. Burada akışın içine geri alınıyor: ödeme
   tamamlanamayan bir ekran, çirkin bir ekrandan çok daha kötü. */
   `[open]` ŞART: tarayıcının kendi kuralı `dialog:not([open]){display:none}` ve buradaki
   `display:block` onu ezer — kullanıcı katmanı kapattığında katman gizleneceğine sayfanın
   altında yeniden belirirdi (yazıldığı gibi denendi, aynen oldu). */
.tds-dlg[open]:not(:modal){position:static;display:block;width:100%;margin-top:var(--space-6)}
.tds-dlg[open]:not(:modal) .modal{margin-inline:auto}

/* Telefonda katman neredeyse tam ekran: banka sayfası zaten sığmıyor ve kazanılan her piksel
   yatay kaydırmayı azaltıyor. Yükseklik `dvh` — adres çubuğu gizlenip açılırken katman
   zıplamasın. */
@media (max-width:640px){
  .tds-dlg .modal{width:100vw;height:100dvh;max-height:100dvh;border-radius:0}
  /* Yükseklik HESAPLANMIYOR, kalan alan doldurulıyor. Sabit bir `calc(100dvh - …)` başlığın ve
     alt şeridin gerçek boyunu tahmin etmek demekti ve tahmin tutmadı: şerit ekranın altından
     taştı, "vazgeç" görünmez oldu. Kap zaten sütun-flex; çerçeve artık payını ondan alıyor. */
  .tdsframe{height:auto;flex:1 1 auto}
}
.spinner--lg{width:var(--icon-xl);height:var(--icon-xl);border-width:var(--border-focus);
  color:var(--primary)}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- chip / badge ---------- */
.chip{font:inherit;font-size:var(--text-label);font-weight:var(--w-bold);line-height:var(--lh-none);
  display:inline-flex;align-items:center;gap:var(--space-2);padding:var(--space-3) var(--space-4);
  min-height:var(--tap-min);border:0;border-radius:var(--radius-pill);background:var(--quiet);
  color:var(--text-2);cursor:pointer;white-space:nowrap;
  transition:background var(--dur-micro) var(--ease-out),color var(--dur-micro) var(--ease-out)}
/* Prototipte .chip ve kart öğeleri <button>'dı; web'de gerçek adresleri olduğu için <a> oldular.
   Bağlantı varsayılanları (altçizgi + mavi) tasarım sistemini deliyor — sıfırlanır. */
.chip,a.chip{text-decoration:none;color:var(--text)}
.pcard .name,.pcard .art{text-decoration:none;color:inherit}
.chip:hover{background:var(--primary-soft);color:var(--primary-pressed)}
/* Etkin çip: gezinmede `aria-current="page"`. `aria-pressed` seçicisi KALDIRILDI — o bir düğme
   durumu ve çipler bağlantı (2026-08-14). */
.chip[aria-current]{background:var(--primary);color:var(--on-primary)}
/* Sayfa numarası çipi. `aria-current="page"` çünkü bu bir SEÇİM değil KONUM: kullanıcı bir
   süzgeç açmıyor, listenin neresinde olduğunu okuyor. Görünüm seçili çiple aynı — iki farklı
   "buradasın" dili olmasın (§6.3b). Rakamlar tabular: sayfa sayısı değişince çipler zıplamaz. */
.chip[aria-current="page"]{background:var(--primary);color:var(--on-primary)}
.pager .chip{font-variant-numeric:tabular-nums;min-width:var(--tap-min);justify-content:center}
/* Atlanan aralık işareti tıklanabilir değil: hedefi olmayan bir kontrol gibi görünmemeli. */
.pager .gap{color:var(--text-2);padding-inline:var(--space-2);user-select:none}
.pager{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--space-2)}
.chip small{font-size:var(--text-micro);font-weight:var(--w-semibold);opacity:.8;
  font-variant-numeric:tabular-nums}
/* Teslimat saati ızgarası ARTIK BURADA DEĞİL: çipler `.seg-i` kart diline geçti,
   kural `.seg` ailesinin yanında duruyor (bkz. .slotgrid, aşağıda). */
.badge{white-space:nowrap;display:inline-flex;align-items:center;font-size:var(--text-micro);font-weight:var(--w-bold);
  padding:var(--space-1) var(--space-3);border-radius:var(--radius-pill);line-height:var(--lh-none);
  letter-spacing:var(--tr-micro)}
.badge--fresh{background:var(--badge-fresh-bg);color:var(--badge-fresh-fg)}
.badge--deal{background:var(--badge-deal-bg);color:var(--badge-deal-fg)}
.badge--last{background:var(--badge-alert-bg);color:var(--badge-alert-fg)}
.badge--info{background:var(--badge-info-bg);color:var(--badge-info-fg)}
.badge svg{width:var(--icon-sm);height:var(--icon-sm);margin-right:var(--space-1)}

/* ---------- fiyat ---------- */
/* [DÜZELTİLDİ 2026-08-22 · denetim D6] Ağırlık `--w-black` (800) idi. İki kural birden:
   §J1 tablosu güncel fiyat için 600–700 diyor, §B2.3 ağırlık eksenini 400/500/600/700 olarak
   sayıyor — 800 ikisinde de yok. Üstelik §B2.3'ün ikinci yarısı "boyut ve kalınlık aynı anda
   artırılmaz; biri yeter" diyor ve fiyat zaten BOYUTLA öne çıkıyor (25 px = ürün adının 1,56
   katı, ölçüldü). Ağırlık 700'e iniyor; oran, renk ve `tabular-nums` değişmiyor. */
.price{font-size:var(--text-h2);font-weight:var(--w-bold);color:var(--price);
  letter-spacing:var(--tr-h2);font-variant-numeric:tabular-nums;line-height:var(--lh-none)}
/* Simge ölçekten DEĞİL fiyatın kendisinden türer (`em`): "1.234,56 ₺"de ₺ rakamlarla aynı
   boyutta olursa sayıyla yarışır. Oran her fiyat boyutunda aynı görünsün diye göreli — bu
   bilinçli bir tipografi kararı, `small`ınki gibi sıfırlanmamış bir tarayıcı varsayılanı değil. */
.price .cur{font-size:calc(1em * var(--cur-scale));font-weight:var(--w-bold)}
.price--sm{font-size:var(--text-h3);letter-spacing:var(--tr-h3)}
.per{font-size:var(--text-label);font-weight:var(--w-semibold);color:var(--text-2);
  line-height:var(--lh-none)}
/* Kartta birim fiyat KENDİ satırında: tavan tutarla aynı satıra girerse iki sayı
   yarışır ve hangisinin ödeneceği bulanıklaşır. */
.price-unit--row{flex-basis:100%;margin-top:calc(var(--space-1) * -1)}
.price-unit{font-size:var(--text-caption);color:var(--text-2);font-weight:var(--w-semibold);
  font-variant-numeric:tabular-nums;line-height:var(--lh-none)}
/* hap içi metin sarmaz — sarınca hap deforme olur; satır gerekirse kapsayıcı sarar */
.price-est{display:inline-flex;align-items:center;white-space:nowrap;
  font-size:var(--text-micro);font-weight:var(--w-bold);color:var(--accent-ink);
  background:var(--accent-soft);padding:var(--space-1) var(--space-2);border-radius:var(--radius-pill);
  letter-spacing:var(--tr-micro);line-height:var(--lh-none)}

/* ---------- ürün kartı ----------
   Hizalama kuralı: kartın her satırı sabit yükseklik tutar (isim 2 satır, çip şeridi,
   birim satırı, aksiyon yuvası). Böylece sepetteki kart ile boş kart AYNI yükseklikte
   olur, satır boyunca fiyatlar aynı hizada durur. */
/* Oluk sistemin kendi token'ından gelir — --grid-gutter tanımlıydı ama hiçbir ızgara
   onu kullanmıyordu; katalog 24 yerine 16 px oluk çiziyordu (§B10). */
/* REYON BÖLÜMÜ (anasayfa) — ÇAPA PAYI ARTIK YOK.

   TARİHÇE, çünkü aynı tuzağa üçüncü kez düşülmesin: burada bir `scroll-margin-top` vardı ve iki
   kez düzeltildi (önce 64 px tahminle, sonra `--catbar-h` ölçümüyle). İkisi de yanlış katmanı
   çözüyordu — gerçek hata, üst çubuğun payının HEM kökte (`scroll-padding-top`) HEM burada
   sayılmasıydı; toplanıyorlardı.

   [KALDIRILDI 2026-08-13: ray yapışkan olmadığı için çapanın
   telafi edeceği bir katman kalmadı. Üst çubuğun payını kökteki `scroll-padding-top` zaten
   veriyor (84 px) — İKİSİ BİRDEN yazıldığında toplanıyorlardı ve hedef 229 px'e düşüyordu
   (ölçüldü: 84 + 145 = 229). Tek kaynak: kök. */
/* Sayfanın h1'i.

   [KUSUR 2026-08-12 · Eyüp] `.h3` ile basılıyordu, yani 20 px — ve reyon başlıkları da
   (`.aisle .sec-head h2`) 20 px. Sayfanın TEK h1'i, altındaki bölüm başlıklarıyla birebir
   aynı boydaydı: işaretlemede duran hiyerarşi ekranda yoktu, başlık bir sayfa başlığı gibi
   değil bir etiket gibi okunuyordu.

   Ölçek sınıfı işaretlemede (`class="h1"`), sitenin kendi deyimiyle — `.h2` taşıyan `<h1
   id="cat-title">` ile aynı kalıp. Burada yalnız yerleşim payı duruyor: boyutu iki yerden
   birden yönetmek, bir gün ikisinin ayrışması demek. */
.aisle-h1{margin-bottom:var(--space-6)}
/* Dar ekranda bir kademe iner. 31 px, 390 px'lik ekranda satırın üçte ikisini yiyor ve altındaki
   reyon başlığıyla (20 px) arasındaki fark hiyerarşi için gereğinden büyük. 25 px hem farkı
   koruyor hem ilk ürün kartına yer bırakıyor — mobilde her piksel katlamadan çalınıyor. */
@media (max-width:640px){.aisle-h1{font-size:var(--text-h2);letter-spacing:var(--tr-h2)}}
.aisle + .aisle{margin-top:var(--space-12)}
/* REYON BAŞLIĞI SİTENİN BÖLÜM BAŞLIĞIYLA AYNI BOYDA (25 px).
   [KUSUR 2026-08-13 · iki tasarım incelemesi birden: "section heading'ler çok küçük"]
   Burada `--text-h3` (20 px) ezmesi vardı: reyon başlığı, sitedeki DİĞER bütün bölüm
   başlıklarından (`.sec-head h2` = 25 px) küçüktü. Ürün kartı 270 px ve fiyatı 25 px iken
   "Sebzeler" 20 px kalıyor, bölümün NEREDE başladığı hissedilmiyordu — yorumun "premium kartlar,
   arada minik yazı" tarifi tam olarak buydu. Ezme kalktı, ölçek ortak sınıftan geliyor.

   AMA MOBİLDE EZME ŞART ve silinmesi bir regresyon olurdu: `.aisle-h1` ≤640'ta 25 px'e iniyor
   (bir üstteki not). Reyon başlığı da 25 kalsaydı sayfanın h1'i ile bölüm başlığı telefonda
   BİREBİR eşitlenirdi — 12 Ağustos'ta düzeltilen hatanın aynısı. Ezme silinmedi, ait olduğu
   kırılıma taşındı. */
@media (max-width:640px){
  .aisle .sec-head h2{font-size:var(--text-h3);letter-spacing:var(--tr-h3)}
}
/* "Tüm sebze ürünleri (39) ›" TEK satır: sayı ve ok başlıktan kopup alt satıra düşüyordu.
   [KUSUR 2026-08-13] Kural `align-items:center` taşıyordu ama öğe FLEX KAPSAYICI DEĞİLDİ —
   yani o bildirim hiçbir şey yapmıyordu. Global kural `svg{display:block}` olduğu için chevron,
   satır içi bir bağlantının içinde BLOK kutu oluyor ve kendi satırına düşüyordu; `white-space:
   nowrap` metni tutuyor ama bir blok kutuyu tutamaz. Gerçek geometri veriliyor: inline-flex +
   ortak `--icon-gap` yerine 4 px (metin ile ok arasındaki mesafe, kelime arası kadar olmalı).
   Ok `--icon-sm`: bu bir düğme değil, cümlenin sonundaki yön işareti — 20 px ok, 16 px'lik
   metinden büyük duruyordu. */
.aisle .sec-head .linkbtn{display:inline-flex;align-items:center;gap:var(--space-1);
  white-space:nowrap;flex:none}
.aisle .sec-head .linkbtn svg{width:var(--icon-sm);height:var(--icon-sm)}

/* SÜTUN SAYISI AÇIK YAZILIR — `auto-fill` DEĞİL.

   [DEĞİŞTİ 2026-08-13 · kap 1152 → 1280 genişletilirken ölçüldü] `auto-fill` sütun sayısını
   `--card-min`den TÜRETİYORDU ve taban kırılımda değiştiği için ızgara TERS BASAMAK üretiyordu:
   1025 px'te 3 sütun / 304 px kart, bir piksel daha dar olan 1024 px'te 4 sütun / 222 px kart.
   Yani ekran daralırken sütun ARTIYOR ve kart küçülüyordu.

   Bu bir ayar hatası değil, yöntemin sınırı. İçerik 1024 px'te 960, 768 px'te 704 — ikisinde de
   3 sütun isteyen bir taban aralığı YOK: (960+24)/4 = 246 tavanı ile (704+24)/3 = 242,67 tabanı
   kesişmiyor. Yani tek bir `--card-min` bu iki genişlikte aynı düzeni kuramaz; hangi değer
   seçilirse seçilsin bir yerde basamak ters döner.

   Açık sayı bunu bitiriyor: sütun sayısı 4 → 3 → 2 ve yalnız kırılımda değişiyor. Kart genişliği
   her bantta ekranla birlikte SÜREKLİ küçülüyor (1280→222 · 304→176 · 296→171); tek sıçrama
   kırılımın kendisinde, yani olması gereken yerde.

   `minmax(0,1fr)`: `1fr` tek başına `auto` tabanı taşır ve uzun ürün adı sütunu şişirir. */
.grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--grid-gutter)}
@media (max-width:1024px){.grid{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:640px){.grid{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* "DAHA FAZLA GÖSTER" (§A8). Ortada tek bir aksiyon, altında ilerleme sayacı — sayaç aksiyonun
   YANINDA değil ALTINDA: bakılan şey düğme, sayı onu doğrulayan ikincil bilgi. */
.more{display:flex;flex-direction:column;align-items:center;gap:var(--space-2);
  margin-top:var(--space-7)}
.pcard{background:var(--surface);border-radius:var(--radius-2xl);box-shadow:var(--elev-product);
  overflow:hidden;display:flex;flex-direction:column;
  transition:box-shadow var(--dur-micro) var(--ease-out),transform var(--dur-micro) var(--ease-out)}
.pcard:hover{box-shadow:var(--elev-product-hi);transform:translateY(calc(var(--space-1) * -1))}
.pcard[data-incart="1"]{box-shadow:0 0 0 var(--border-emphasis) var(--primary),var(--elev-product)}
.pcard[data-out="1"]{opacity:.72;box-shadow:var(--elev-card)}
/* Görsel oranı 1/.94 → 1/.82. Yemek görseli iştah açar, o yüzden küçültme SINIRLI tutuldu;
   asıl kısaltma ölü alanlardan geldi (boş birim satırı + çip şeridi). */
/* ORAN KAYNAK GÖRSELİN ORANI. [KUSUR 2026-08-10] Kutu 1/.82 idi ama katalogdaki ürün
   fotoğraflarının HEPSİ kare (tarayıcıda ölçüldü: 14/14 görsel 1024×1024, oran 1.00).
   `object-fit:cover` ile kare bir fotoğraf 1,22'lik kutuya oturunca üstten ve alttan
   toplam %18'i KIRPILIYORDU — meyve/sebze fotoğrafında ürünün kendisi kadraja tam
   oturduğu için kesilen yer doğrudan ürünün üstü ve altı.
   Tazelik satan bir sayfada ürünün kırpılmış fotoğrafı, tasarım tercihi değil kusurdur. */
.pcard .art{aspect-ratio:1/1;background:var(--primary-soft);position:relative;display:block;
  border:0;padding:0;cursor:pointer;width:100%;overflow:hidden}
/* Yükleme yeri: marka zemininde sakin bir parlama. Görsel hazır olunca kaybolur.
   TOKEN'LAR İSKELETLE ORTAK. Önceden --pine-050/--pine-100 kullanıyordu ve ölçüldü
   (2026-08-09): parlama bandının kendi içindeki kontrast 1,13:1, kutunun kart zeminine karşı
   kontrastı 1,10:1 — yani "yükleniyor" hâli görünmüyordu ve `loading=lazy` ile henüz gelmemiş
   kartlar BOŞ KUTU olarak okunuyordu. İskelet çubuklarında aynı kusuru düzeltmiştik; iki ayrı
   yükleme dili tutmanın anlamı yok, ikisi de artık --skeleton'dan geliyor. */
.pcard .art::before{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(100deg,var(--skeleton) 30%,var(--skeleton-shine) 50%,var(--skeleton) 70%);
  background-size:300% 100%;animation:shim 1.6s ease infinite;
  transition:opacity var(--dur-enter) var(--ease-out)}
.pcard .art[data-ready]::before{opacity:0;animation:none}
@media (prefers-reduced-motion:reduce){.pcard .art::before{animation:none}}
/* Görsel AKIŞTAN ÇIKARILIR. Aksi hâlde height:100% çözülemeyip img kendi doğal oranına
   düşüyor ve kabı büyütüyordu: aspect-ratio gerçek kartlarda hiç işlemiyor, yalnız
   görselsiz iskelette işliyordu — iskelet/kart uyuşmazlığının kaynağı buydu. */
/* [KURAL 2026-08-12 · Eyüp] ÜRÜN GÖRSELİ DE ASLA KIRPILMAZ — `cover` değil `contain`.

   Bugün için görsel bir değişiklik DEĞİL, bir GARANTİ: katalogdaki görsellerin ölçüldüğü kadarı
   (12/12) tam kare (1024² ve 2048²) ve kutu da 1:1, yani `cover` ile `contain` aynı sonucu
   veriyor. Fark ilk kare-olmayan görsel yüklendiğinde ortaya çıkar: `cover` onu sessizce keser
   — ve kesilen yer çoğu zaman ürünün sapı, ucu, etiketi olur. `contain`de kesilmez, kutunun
   zemini görünür.

   Kutunun 1:1 oranı KALIYOR: ızgarada bütün kartların aynı yükseklikte olmasını o sağlıyor
   (fiyat satırı hizası buna bağlı, bkz. `.buy .act` notu). Oran kutuda, kırpma yasağı görselde. */
.pcard .art img{position:absolute;inset:0;z-index:2;width:100%;height:100%;object-fit:contain;
  display:block;opacity:0;transition:opacity var(--dur-enter) var(--ease-out)}
/* [DÜZELTME 2026-08-08] Görsel varsayılan olarak GÖRÜNÜR. Önceden opacity:0 ile başlayıp
   `data-ready` bekliyordu; o bayrağı prototipte satır içi onload atıyordu ve CSP borcu (§7.8)
   yüzünden kaldırıldı — sonuç: yüklü görseller görünmez kaldı. İçeriğin görünürlüğü hiçbir zaman
   JavaScript'e bağlanamaz; geçiş bir SÜS, görünürlük bir ŞART. */
.pcard .art img{opacity:1}
.pcard .art img[data-fade]{opacity:0}
.pcard .art img[data-fade][data-ready]{opacity:1}
/* z-index ŞART. [KUSUR 2026-08-10] Rozet, görselin ALTINDA kalıyordu: `.art img` z-index:2
   taşıyor, rozette hiç yoktu ve işaretlemede görselden ÖNCE geldiği için üstüne binmiyordu.
   Sonuç ölçüldü: görseli olan kartta "Tükendi" rozeti HİÇ görünmüyor, yalnız görsel gelmemiş
   kartta görünüyordu — yani rozet tam da işe yarayacağı yerde yoktu. */
.pcard .art .badge{position:absolute;top:var(--space-3);right:var(--space-3);z-index:3}
.pcard .body{padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-3);flex:1}
.pcard .name{font-size:var(--text-body);font-weight:var(--w-bold);line-height:var(--lh-snug);
  text-align:left;background:none;border:0;padding:0;font-family:inherit;color:inherit;cursor:pointer;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
  /* İki satırlık yer HER kartta ayrılır (satır hizası bunun üstünde duruyor), ama ölçülen
     yükseklik 43,2 px çıkıyordu — dokunma hedefi eşiğinin bir piksel altı (WCAG 2.5.8).
     max() ikisini birden tutuyor: hiza için 2 satır, hedef için 44 px. Dolgu eklemek
     kartları birbirine göre kaydırırdı. */
  min-height:max(var(--line-2), var(--tap-min))}
.attrs{display:flex;flex-wrap:wrap;gap:var(--space-1);min-height:var(--space-6);overflow:hidden}
.at{font-size:var(--text-caption);font-weight:var(--w-semibold);color:var(--text-2);
  background:var(--quiet);padding:var(--space-1) var(--space-2);border-radius:var(--radius-pill);
  line-height:var(--lh-none)}
.buy{display:grid;gap:var(--space-2);margin-top:auto}
/* Fiyat + birim TEK satırda kalır; sarsaydı uzun fiyatlı kart komşusundan yüksek olur
   ve satır hizası yine bozulurdu. */
.buy .pline{display:flex;align-items:baseline;gap:var(--space-1);flex-wrap:nowrap;
  min-height:var(--space-6);white-space:nowrap}
/* Bantlı üründe ikinci satır (₺/kg) var — o kartta sarma AÇILIR. nowrap genel kural
   olarak kalır: diğer kartlarda fiyat/birim asla ayrı satıra düşmemeli. */
.buy .pline:has(.price-unit--row){flex-wrap:wrap}
@media (max-width:640px){.pcard .price{font-size:var(--text-h3);letter-spacing:var(--tr-h3)}}
/* Dar kartta stepper düğmeleri küçülür; yoksa "6 adet" etiketi iki satıra sarıyor.
   Dokunma hedefi stepper'ın kendi 44 px yüksekliğiyle korunur (§A9). */
@media (max-width:640px){
  .pcard .stepper button{width:var(--control-box);height:var(--control-box);position:relative}
  /* Görsel kutu 24 px, hedef stepper'ın tam yüksekliğine ve 44 px genişliğe taşar. */
  .pcard .stepper button::before{content:"";position:absolute;inset-block:-10px;inset-inline:-10px}
  .pcard .stepper button svg{width:var(--icon-sm);height:var(--icon-sm)}
  .pcard .stepper .q{font-size:var(--text-caption);white-space:nowrap}
}
/* TÜKENDİ SATIRI — düğme geometrisinde, düğme davranışında DEĞİL.
   Aynı yükseklik ve köşe: kartın altı artık delik değil. Zemin nötr, imleç yok, odaklanamaz —
   basılacak bir şey olmadığını biçimin kendisi söylüyor (§M5'in tersi değil: orada "düğmeyi
   pasifleştirme" deniyor, burada zaten düğme yok). */
.soldout{display:flex;align-items:center;justify-content:center;width:100%;
  min-height:var(--control-h);border-radius:var(--radius-lg);
  background:var(--quiet);color:var(--text-2);
  font-size:var(--text-label);font-weight:var(--w-semibold)}

/* Sepetteki miktar: seçiciyi açan düğme. Ortada durur, düğme kılığı yok — çevresindeki
   artı/eksi zaten kontrol dilini kuruyor; buradaki ikinci bir çerçeve satırı kalabalıklaştırırdı.
   Tıklanabilirliğini imleç ve odak halkası söylüyor. */
.buy .act .incart .stepper .q{background:none;border:0;font:inherit;cursor:pointer}

/* Sepetteki üründe kartın aksiyon satırı: stepper tam genişlik kaplar — düğmenin durduğu yer
   değişmiyor, yalnız içi kontrol oluyor (2026-08-14). */
.buy .act .incart{width:100%}
/* [DÜZELTİLDİ 2026-08-22 · denetim D4] Kart seçicisi 48 px'ti, "Sepete ekle" düğmesi 44:
   ızgara satırı en uzun öğeye göre uzadığı için sepetinde ürün BULUNAN kartın satırı 476 px,
   diğer satırlar 472 px oluyordu (ölçüldü, aynı ızgarada iki farklı satır boyu — §B4.2
   "kart yüksekliği sabit").
   Sebep dikey dolgunun mirası: taban `.stepper` `padding:var(--space-1)` veriyor ve buradaki
   kural yalnız `padding-inline`i eziyordu. Hesap: 4+4 dolgu + 2+2 kenarlık + 36 düğme = 48.
   `padding-block:0` ile toplam 40'a iniyor, `min-height:var(--control-h)` devreye giriyor ve
   seçici düğmeyle AYNI 44 px'e oturuyor. İç düğmelerin dokunma hedefi etkilenmiyor —
   dar ekranda `::before` zaten alanı genişletiyor (bkz. `.pcard .stepper button::before`). */
.buy .act .incart .stepper{width:100%;justify-content:space-between;
  min-height:var(--control-h);border:var(--border-emphasis) solid var(--primary);
  border-radius:var(--radius-lg);padding-block:0;padding-inline:var(--space-2)}
/* Miktar ORTADA ve büyümeye izin verir: "4,25 kg" iki yana yaslı düğmelerin arasında kalır. */
.buy .act .incart .stepper .q{flex:1;text-align:center;font-weight:var(--w-bold);
  color:var(--primary-pressed)}
.buy .act .incart .stepper button{color:var(--primary-pressed)}

/* uzun/kısa etiket çifti — hangisinin görüneceğini ekran genişliği seçer */
.lbl-short{display:none}
.buy .btn{white-space:nowrap}
@media (max-width:640px){
  .buy .lbl-full{display:none}
  .buy .lbl-short{display:inline}
  .buy .btn{padding-inline:var(--space-3)}
}
.buy .price-unit{min-height:var(--space-4)}     /* bant bilgisi yoksa da yer tutar */
/* [KUSUR 2026-08-12 · ölçüldü] Aksiyon YUVASI yer tutmuyordu.

   Kartın hizalama sözleşmesi (bu bölümün başındaki not) "aksiyon yuvası"nı sabit yükseklikli
   satırlardan biri sayıyor ve _ProductCard.cshtml de tükenmiş üründe boş `.act` basarken
   "aksiyon satırı boş kalır ve kart yüksekliği ızgarada bozulmasın diye yerini korur" diyor.
   İki yerde YAZILI olan bu söz, hiçbir kuralla KARŞILANMAMIŞTI: `.act`in tek kuralı
   `>*{width:100%}`, yani içi boşken yüksekliği 0.

   Ölçüm (anasayfa, Sebze reyonu): dolu kartta `.act` 44 px, tükenmiş kartta 0. `.buy`
   `margin-top:auto` ile kartın dibine yapıştığı için fiyat, düğmesi olmayan kartta 44 px
   AŞAĞI kayıyordu — aynı satırda üç fiyat 1265'te, dördüncüsü 1309'da. Satır yükseklikleri
   de ayrışıyordu (düğmeli satır 420, tümü tükenmiş satır 376).

   Fiyat satırı bir kartta bir yerde, komşusunda başka yerdeyse göz satırı yatay tarayamaz;
   fiyat karşılaştırması kartın en çok yapılan işi. Yuva doluyken düğmenin yüksekliği ne ise
   boşken de o: tek token, tek sayı. */
.buy .act{min-height:var(--control-h)}
.buy .act>*{width:100%}
/* Nötr stepper: yeşil dolgu, kartın kendi çağrısı olan "Sepete ekle" ile yarışıyordu
   ve ızgarada sepetteki her ürün bir yeşil blok gibi patlıyordu. Beyaz zemin + ince
   çerçeve; renk yalnız kontrol ikonlarında kalır. Dokunma alanı 44 px korunur. */
.stepper{display:flex;align-items:center;gap:var(--space-1);background:var(--surface);
  border:var(--border-control) solid var(--primary);
  border-radius:var(--radius-lg);padding:var(--space-1);min-height:var(--control-h)}
.stepper button{font:inherit;width:var(--control-h-sm);height:var(--control-h-sm);flex:none;border:0;
  border-radius:var(--radius-md);background:none;color:var(--primary);
  display:grid;place-items:center;cursor:pointer;padding:0;
  transition:background var(--dur-micro) var(--ease-out),transform var(--dur-press) var(--ease-spring)}
.stepper button svg{width:var(--icon-md);height:var(--icon-md)}
.stepper button:hover{background:var(--primary-soft)}
.stepper button:active{transform:scale(.85)}
/* Miktar etiketi HİÇBİR yerde sarmaz. Kart sayacında `nowrap` zaten vardı, sepet satırındaki
   sayaçta yoktu: "1,5 kg" ve "2 demet" iki satıra kırılıp o satırların yüksekliğini 17→34 px
   yapıyordu (ölçüldü 2026-08-09) — aynı listede satırlar birbirine göre kayıyordu. Kural
   bileşenin kendisine ait, yüzeye değil. */
.stepper .q{color:var(--text);font-weight:var(--w-black);font-size:var(--text-label);
  flex:1;text-align:center;font-variant-numeric:tabular-nums;line-height:var(--lh-none);
  white-space:nowrap}
.stepper--fit{width:fit-content;min-width:calc(var(--control-h) * 4)}

/* ---------- bölüm ---------- */
.section{padding-block:var(--space-12) 0}
/* ≤640: masaüstü ritmi telefonda pahalı. 360×800'de üst çubuk 120 + manşet 184 +
   bölüm boşluğu 138 = ilk ürün kartı katlamanın ALTINDA kalıyordu; mağaza
   "ne sattığını" ancak kaydırınca söylüyordu (§J1). Boşluk yarıya iner. */
@media (max-width:640px){
  .section{padding-block:var(--space-8) 0}
  .sec-head{margin-bottom:var(--space-4)}
}
/* [SİLİNDİ 2026-08-22 · denetim Y8] Burada `.section:last-of-type{padding-bottom:var(--space-16)}`
   vardı ve bu dosyanın 296. satırındaki kararla ÇELİŞİYORDU: "Pay `main`e veriliyor, `.section`a
   değil: son bölümün hangisi olduğunu sayfa biliyor, CSS bilmiyor — `:last-child`e bağlamak,
   payı yanlış yere koyardı."

   Öngörülen hata aynen gerçekleşmişti. Devam eden sipariş paneli canlı bölge sarmalayıcısının
   İÇİNDE (`<div data-live-region><section class="section resume-slot">`), yani kendi kabında
   TEK section — dolayısıyla her zaman `:last-of-type`. Ölçüldü: panelin `padding-bottom`u
   **64 px**, kutunun toplam 190 px'inin üçte biri; panelin kendi içeriği yalnız 94 px.
   O 64 px, manşetle birlikte ilk ürün kartını 797 px'e itiyordu (§R4.1 tavanı 760).

   Sayfa dibindeki nefes payı zaten `main.wrap{padding-bottom:var(--space-16)}`ten geliyor. */
.sec-head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-4);
  flex-wrap:wrap;margin-bottom:var(--space-6)}
.sec-head h2{font-size:var(--text-h2);font-weight:var(--w-black);letter-spacing:var(--tr-h2)}
/* Bölüm başlığı iki işi taşır: kimlik (başlık+sayım) ve sıralama denetimi.
   Denetim sağda, kendi başına — başlıkla aynı hizada ama onunla yarışmaz. */
.sec-head-tx{display:flex;align-items:baseline;gap:var(--space-3);min-width:0}
.sortbox{display:flex;align-items:center;flex:none}
.sortbox select{font:inherit;font-size:var(--text-body);font-weight:var(--w-semibold);
  color:var(--text);background:var(--surface);
  border:var(--border-hairline) solid var(--control-border);border-radius:var(--radius-pill);
  height:var(--control-h);padding-inline:var(--space-4);cursor:pointer}
.sortbox select:hover{border-color:var(--primary)}
/* Uygulanan daraltmalar: her biri KALDIRILABİLİR (§J12.6 — filtre görünür ve geri alınır). */
.applied{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-2);
  margin-bottom:var(--space-4)}
.chip--rm{gap:var(--space-2);padding-inline:var(--space-3)}
.chip--rm svg{width:var(--icon-sm);height:var(--icon-sm);opacity:.6}
.chip--rm:hover{border-color:var(--danger);color:var(--danger)}
.chip--rm:hover svg{opacity:1}
@media (max-width:640px){
  .sec-head{flex-wrap:wrap}
  .sortbox{width:100%}
  .sortbox select{font-size:var(--text-body);width:100%}
}
.sec-head .meta{font-size:var(--text-caption);font-weight:var(--w-semibold);color:var(--text-2);
  letter-spacing:var(--tr-label);text-transform:uppercase}
/* Arama eşleşme açıklaması — satırın neden geldiğini söyler (§L1.5) */
.panel{background:var(--surface);border-radius:var(--radius-xl);box-shadow:var(--elev-card);
  padding:var(--space-6)}
.rw{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center}
.grow{flex:1;min-width:calc(var(--card-min) - var(--space-2))}
.rw--split{justify-content:space-between}
.gap-top{margin-top:var(--space-4)}
.gap-top--sm{margin-top:var(--space-3)}
.lnk{color:var(--primary-pressed);font-weight:var(--w-bold)}
.opt{font-weight:var(--w-regular);color:var(--text-2)}
/* İşaret AZINLIKTA olana konur (§F). Adres formunda 2 zorunlu / 4 isteğe bağlı vardı ve işaret
   isteğe bağlı olanlardaydı: kullanıcı dört kez "bunu atlayabilirim" okuyup asıl iki alanı
   sessiz sanıyordu. `.req` görsel olarak `.opt` ile aynı ağırlıkta — zorunluluk bir uyarı değil,
   bir bilgi; kırmızı yıldız formu tehditkâr yapar. */
.req{font-weight:var(--w-regular);color:var(--text-2)}
.resume-slot{padding-top:var(--space-8)}
/* Durum ikonu — sitenin diğer durum şeritleriyle aynı renk mantığı: ikon marka renginde, metin
   nötr (`.promise-item svg` ve `.assure svg` ile aynı deyim).
   Seçici SINIFA değil KONUMA bağlı: `IconTagHelper` çıktıyı elle kurduğu için etikete yazılan
   `class` çıktıya geçmiyor (bkz. işaretlemedeki tuzak notu). */
.resume-slot .panel > svg{color:var(--primary);flex:none}
/* Dar ekranda panel üç satıra iniyor (ikon+metin, sonra tam genişlik düğme) ve 24 px'lik dolgu
   bu üç satırın altında ve üstünde iki kez sayılıyor. Ölçüldü: panel 150 px ve bunun 48'i saf
   dolgu. Bir kademe aşağı (16) panelin okunurluğunu bozmuyor, ilk ürüne 16 px yaklaştırıyor
   (§R4.1). Üst boşluğu da 32 → 24: panel manşetin hemen altında ve ikisi arasında iki ayrı
   pay birikiyordu. */
@media (max-width:640px){
  .resume-slot{padding-top:var(--space-6)}
  .resume-slot .panel{padding:var(--space-4)}
}
/* `.section,#catalog{scroll-margin-top}` KALDIRILDI 2026-08-13 — `.aisle` ile aynı gerekçe:
   kökteki `scroll-padding-top` üst çubuğun payını zaten veriyor, ikinci bir pay onunla toplanıp
   hedefi aşağı kaydırıyordu. */

/* ---------- modal / sheet ---------- */
dialog{border:0;padding:0;background:transparent;max-width:none;max-height:none}
dialog::backdrop{background:var(--scrim)}
.modal{background:var(--surface);border-radius:var(--radius-2xl);box-shadow:var(--elev-float);
  width:min(var(--dialog-w),calc(100vw - var(--space-8)));overflow:hidden;
  /* uzun içerikte modal viewport'u taşmaz: başlık ve alt aksiyonlar sabit, gövde kaydırır */
  max-height:calc(100dvh - var(--space-8));display:flex;flex-direction:column}
.modal .hd{padding:var(--space-6) var(--space-6) 0;display:flex;justify-content:space-between;
  gap:var(--space-4);align-items:flex-start;flex:none}
.modal .hd h3{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3)}
.modal .bd{padding:var(--space-4) var(--space-6) var(--space-6);display:grid;gap:var(--space-4);
  overflow-y:auto;overscroll-behavior:contain;min-height:0}
.modal .ft{padding:var(--space-4) var(--space-6);background:var(--quiet);display:flex;
  gap:var(--space-3);justify-content:flex-end;flex-wrap:wrap;flex:none}
/* İki uçlu şerit: solda soru, sağda çıkış yolu. Varsayılan `flex-end` ikisini de sağa
   toplardı — soru cümlesi bağlantının kuyruğu gibi okunurdu. */
.modal .ft--split{justify-content:space-between;align-items:center}
.xbtn{border:0;background:transparent;cursor:pointer;color:var(--text-2);width:var(--tap-min);
  height:var(--tap-min);border-radius:var(--radius-pill);display:grid;place-items:center;flex:none}
.xbtn svg{width:var(--icon-md);height:var(--icon-md)}
.xbtn:hover{background:var(--quiet);color:var(--text)}
/* ---------- İŞLEM KİLİDİ ----------
   Mühürleme sırasında sayfanın geri kalanı ELVERİŞSİZ olmalı; yoksa kullanıcı
   ödenmekte olan sepeti değiştirebilir. <dialog showModal> arka planı inert yapar.
   Görsel dil sessiz: perde + küçük kart. Büyük gürültülü katman panik hissi verir. */
.lock-dlg{background:transparent;border:0;padding:0;max-width:none;max-height:none;
  width:100%;height:100%}
/* Perdenin üçüncü bir tonu YOK: sistemde iki kademe var (--scrim / --scrim-hi).
   Buradaki .62 üçüncü bir sihirli sayıydı; kilit perdesi koyu olanı kullanıyor. */
.lock-dlg::backdrop{background:var(--scrim-hi);backdrop-filter:blur(var(--scrim-blur));
  animation:fade var(--dur-enter) var(--ease-out)}
@keyframes fade{from{opacity:0}to{opacity:1}}
.lock{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);
  width:min(var(--dialog-w),calc(100vw - var(--space-8)));
  background:var(--surface);border-radius:var(--radius-2xl);box-shadow:var(--elev-float);
  padding:var(--space-8) var(--space-6);display:grid;gap:var(--space-3);
  justify-items:center;text-align:center;
  animation:lock-in var(--dur-enter) var(--ease-out)}
@keyframes lock-in{from{opacity:0;transform:translate(-50%,-46%)}
                   to{opacity:1;transform:translate(-50%,-50%)}}
@media (prefers-reduced-motion:reduce){
  .lock,.lock-dlg::backdrop{animation:none}
}
.lock .spinner{margin-bottom:var(--space-2)}
.lock .fine{max-width:var(--measure)}
.lock-slow{color:var(--warning);font-weight:var(--w-semibold)}
.lock-slow[hidden]{display:none}

/* ---------- HARİTA İLE ADRES ---------- */
@media (min-width:641px){
}
@media (max-width:640px){.mapx{border-radius:0}}
.mapx-top .searchbox{flex:1;max-width:none;min-width:0}
/* Pin ekranın MERKEZİNDE sabit; harita altından kayar (TikTak/Getir paterni) */

/* ---------- mini sepet çekmecesi ----------
   Sağdan açılır, otomatik KAPANMAZ (§J3.2), kalem detayını gösterir (§J3.3). */
.drawer-dlg{margin:0 0 0 auto;height:100dvh;max-height:100dvh;width:min(var(--drawer-w),100vw)}
.drawer-dlg[open]{animation:slidein var(--dur-drawer) var(--ease-out)}
@keyframes slidein{from{transform:translateX(100%)}to{transform:none}}
/* Sunucudan gelen parçanın kabı. display:contents ile kutu ortadan kalkar ve parçanın kendi
   blokları (.drawer-list, .drawer-foot) doğrudan .drawer'ın flex çocukları olur — aksi hâlde
   liste esnemez, alt blok dibe yapışmaz. */
.mount{display:contents}
.drawer{background:var(--surface);height:100%;display:flex;flex-direction:column;
  box-shadow:var(--elev-float)}
.drawer-top{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  padding:var(--space-4) var(--space-4) var(--space-4) var(--space-6);
  border-bottom:var(--border-hairline) solid var(--divider);flex:none}
.drawer-top .cnt{font-size:var(--text-caption);font-weight:var(--w-semibold);color:var(--text-2);
  letter-spacing:0}
.drawer-list{flex:1;overflow-y:auto;overscroll-behavior:contain}
.drawer-foot{flex:none;padding:var(--space-4) var(--space-6) var(--space-6);
  border-top:var(--border-hairline) solid var(--divider);display:grid;gap:var(--space-3);
  background:var(--surface)}
.drawer-empty{flex:1;display:grid;gap:var(--space-3);align-content:center;justify-items:center;
  text-align:center;padding:var(--space-8)}
.drawer-empty>svg{width:var(--icon-xl);height:var(--icon-xl);color:var(--pine-200)}
.drawer-empty b{font-size:var(--text-h3);font-weight:var(--w-bold)}
.drawer-empty .btn{margin-top:var(--space-3)}
.citem--tight{grid-template-columns:var(--icon-xl) minmax(0,1fr) auto;gap:var(--space-3);
  padding:var(--space-3) var(--space-4)}
.citem--tight img{width:var(--icon-xl);height:var(--icon-xl)}
/* Çekmecedeki mini stepper her genişlikte 24 px hedefe düşüyordu (§A9.2). */
.stepper--mini{padding:var(--space-1);min-height:var(--control-h);
  width:calc(var(--control-h) * 2.6)}
.stepper--mini button{width:var(--control-box);height:var(--control-box)}
.stepper--mini button svg{width:var(--icon-sm);height:var(--icon-sm)}
.stepper--mini .q{font-size:var(--text-caption)}

.sheet{background:var(--surface);border-radius:var(--radius-2xl);box-shadow:var(--elev-float);
  width:min(var(--sheet-w),calc(100vw - var(--space-8)));overflow:hidden;
  max-height:calc(100dvh - var(--space-8));display:flex;flex-direction:column}
.sheet .bd{overflow-y:auto;overscroll-behavior:contain;min-height:0}
.sheet-top{flex:none}
/* Başlık: görsel · kimlik (esner) · kapat (sağ ÜST köşeye sabit).
   Kapat butonu akışta 3. eleman olduğu için kimlik bloğu esnemezse metnin dibine yapışıyordu. */
.sheet-top{display:flex;gap:var(--space-4);padding:var(--space-6);background:var(--primary-soft);
  align-items:flex-start;position:relative}
/* KIRPMA YASAĞI (2026-08-12 · Eyüp) — ürün/banner görseli kesilmez; bkz. `.pcard .art img`. */
.sheet-top img{width:var(--thumb-lg);height:var(--thumb-lg);border-radius:var(--radius-lg);
  object-fit:contain;flex:none;background:var(--surface)}
.sheet-id{flex:1;min-width:0;display:grid;gap:var(--space-1);align-content:center;
  min-height:var(--thumb-lg);padding-right:var(--space-8)}
.sheet-x{position:absolute;top:var(--space-3);right:var(--space-3)}
.sheet .bd{padding:var(--space-6);display:grid;gap:var(--space-6);align-content:start}
/* Kaydırmayan alt blok: tutar + birincil aksiyon her zaman görünür (§H1). */
.sheet-ft{flex:none;display:grid;gap:var(--space-4);padding:var(--space-6);
  border-top:var(--border-hairline) solid var(--divider);background:var(--surface)}
@media (max-width:640px){
  .sheet-ft{padding:var(--space-4) var(--space-4)
    calc(var(--space-4) + env(safe-area-inset-bottom, 0px))}
  .sheet .bd{padding:var(--space-4);gap:var(--space-4)}
}
.pick{display:grid;gap:var(--space-3)}
/* eşit genişlikli seçim kartları — miktar sorusunun cevabı */
/* Miktar seçenekleri DİNAMİK: bir üründe 4 gramaj adımı olur, başkasında 10. Eskiden
   `minmax(0,1fr)` idi — yani her sütun SIFIRA kadar ezilebiliyordu ve 6 seçenekte "500 g" iki
   satıra kırılıyordu (ölçüldü: 412 px'e 6 sütun = 62 px/sütun).

   Artık asgari genişlik var: seçenekler ezilmez, sığmayınca satır yatay KAYAR. `1fr` üst sınır
   olarak kalıyor, böylece az seçenekte satır yine tam genişliği doldurur — az sayıda seçenek için
   gereksiz bir kaydırma çubuğu ya da sola yaslanmış boşluk olmaz.

   Sağ kenarda kırpılan seçenek kaydırılabilirliğin kendi işaretidir; ayrı bir ok konmuyor.
   Alt padding odak halkasının kırpılmaması için (overflow:auto onu keser). */
/* KAYDIRMA KABI KENDİ HALKASINI KIRPMAZ.
   [KUSUR 2026-08-14 · Eyüp: "seçili olanın border'ı mı shadow'u mu kesiliyor" · ölçüldü, haklı]
   Kap `overflow-x:auto` + `overflow-y:hidden` ve dikey payı YOKTU (`padding-bottom:4px`, üstte 0).
   Seçili çipin üst kenarı kabın üst kenarına tam denk geliyordu (ölçüldü: 0 px) ve seçici
   açıldığında o çip odaklanmış geliyor — 3 px'lik odak halkası + 2 px offset üstte tamamen,
   altta kısmen kesiliyordu. Yani kullanıcı "yarım çizilmiş" bir seçim görüyordu.
   Pay halkanın tam ölçüsü kadar (3+2=5 → ölçekten 8 px) ve DIŞARI DOĞRU negatif marjinle geri
   alınıyor: kutu nefes alıyor ama yerleşimdeki ritim değişmiyor. */
.seg{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(var(--seg-min),1fr);
  gap:var(--space-2);overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scrollbar-width:none;
  padding-block:var(--space-2);margin-block:calc(var(--space-2) * -1);
  /* Yatayda da aynı sorun: ilk çipin sol halkası kabın kenarında kesiliyordu (ölçüldü: 0 px). */
  padding-inline:var(--space-1);margin-inline:calc(var(--space-1) * -1)}
.seg::-webkit-scrollbar{display:none}
.seg-i{scroll-snap-align:start}
.seg-i{font:inherit;cursor:pointer;background:var(--surface);color:var(--text);
  border:var(--border-control) solid var(--divider);border-radius:var(--radius-lg);
  padding:var(--space-3) var(--space-2);min-height:var(--control-h);
  display:grid;gap:var(--space-1);justify-items:center;align-content:center;
  transition:border-color var(--dur-micro) var(--ease-out),
    background var(--dur-micro) var(--ease-out)}
.seg-i b{font-size:var(--text-body);font-weight:var(--w-bold);line-height:var(--lh-none)}
.seg-i small{font-size:var(--text-caption);color:var(--text-2);font-weight:var(--w-semibold);
  font-variant-numeric:tabular-nums;line-height:var(--lh-none)}
.seg-i:hover{border-color:var(--primary-hover)}
.seg-i[aria-pressed="true"]{border-color:var(--primary);background:var(--primary-soft);
  color:var(--primary-pressed);box-shadow:inset 0 0 0 var(--border-hairline) var(--primary)}
.seg-i[aria-pressed="true"] small{color:var(--primary-pressed)}
/* SEÇİLEMEYEN KART — geçmiş teslimat penceresi.
   Dil `.chip[aria-disabled]` ile aynı (sönük zemin, kesikli kenar, gri metin) ama burada
   GERÇEKTEN görünür: `.chip` kenarlıksızdı (`border:0`), yani oradaki `border-style:dashed`
   hiçbir zaman çizilmiyordu. `.seg-i`'nin kenarlığı var, kesik çizgi işini yapıyor.
   Öğe tıklanabilir KALIR (§M5.2: kilitli kontrol sebebini söylemez; basılır, sebep söylenir). */
.seg-i[aria-disabled="true"]{background:transparent;color:var(--text-2);
  border-style:dashed;border-color:var(--divider);cursor:not-allowed}
.seg-i[aria-disabled="true"]:hover{border-color:var(--divider)}
.seg-i[aria-disabled="true"] small{color:var(--text-2)}

/* ---------- teslimat zamanı: mod kademesi + saat ızgarası ---------- */
/* [KUSUR 2026-08-21 · Eyüp: "tasarım acayip kötü"] Karar iki-yollu ("şimdi mi sonra mı", ancak
   sonraysa "hangi saat") ama onbir pencere tek düzlemde eşit ağırlıkta diziliyordu. Üstteki
   kademe o yapıyı görünür kılar: iki eşit kutu, kaydırma yok — `.seg`in aksine sabit iki sütun,
   çünkü seçenek sayısı ikiden fazla olmuyor. */
/* auto-fit, `1fr 1fr` DEĞİL: saatli pencere olmayan şubede kademe tek kutuya düşer ve o kutu
   yarım genişlikte öksüz kalmak yerine satırı doldurur. Dar ekranda da iki kutu sığmazsa alt
   alta geçer — sabit iki sütun onları 130 px'e ezerdi. */
.dmode{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--slot-min),1fr));
  gap:var(--space-2);margin-bottom:var(--space-4)}
/* İkon yalnız kademede: başlıkla aynı satırda, metnin solunda. Kural `.dmode` ile kapsanıyor —
   `.seg-i` miktar seçicide de kullanılıyor ve orada ikon yok, dokunulmuyor. */
.dmode .seg-i b{display:inline-flex;align-items:center;gap:var(--space-2)}
.dmode .seg-i b svg{width:var(--icon-sm);height:var(--icon-sm);flex:none}
.dmode .seg-i small{display:inline-flex;align-items:center;gap:var(--space-1)}
/* Açılır göstergesi: kapalıyken aşağı, açıkken yukarı bakar. Chevron kaynağı sağa bakıyor
   (`m9 6 6 6-6 6`), çeyrek tur döndürülüyor. */
.dmode .seg-i small svg{width:var(--icon-sm);height:var(--icon-sm);flex:none;
  transform:rotate(90deg);transition:transform var(--dur-micro) var(--ease-out)}
.dmode .seg-i[aria-expanded="true"] small svg{transform:rotate(-90deg)}
/* AÇIK ≠ SEÇİLİ. "İleri saat"e basmak sunucuya gitmez, yalnız listeyi açar — henüz seçilmiş bir
   saat yoktur. Açık hâl bu yüzden dolgusuz: kenarlık ve metin renklenir, zemin boş kalır. Dolgu
   (primary-soft + inset halka) YALNIZ gerçek seçime ait; iki durum aynı görünseydi ekran
   müşterinin vermediği bir sözü ona ait gösterirdi. */
.dmode .seg-i[aria-expanded="true"][aria-pressed="false"]{border-color:var(--primary);
  color:var(--primary-pressed)}
.dmode .seg-i[aria-expanded="true"][aria-pressed="false"] small{color:var(--primary-pressed)}
/* Saat ızgarası: kutular EŞİT genişlikte ve satırlar hizalı.
   Önceden `.rw` (flex-wrap) kullanılıyordu ve çipler içeriğe göre büyüyordu: dokuz pencerede
   ÜÇ farklı genişlik (117/119/145 px), satırlar 4+4+1 ve sonda öksüz bir çip (ölçüldü
   2026-08-10). Tırtıklı bir ızgara ödeme adımında doğrudan "özensiz" okunuyor.
   auto-fit + minmax: dar ekranda sütun sayısı kendiliğinden düşer, kutular yine eşit kalır. */
.slotgrid{display:grid;gap:var(--space-2);
  grid-template-columns:repeat(auto-fit,minmax(var(--slot-min),1fr))}
.slotgrid .seg-i b{font-variant-numeric:tabular-nums}
/* tutar okuması — ağır koyu blok yerine sakin, okunur bir şerit */
.readout{background:var(--primary-soft);border-radius:var(--radius-lg);
  padding:var(--space-4);display:flex;justify-content:space-between;gap:var(--space-4);
  align-items:center;flex-wrap:wrap}
.readout .amt{display:grid;gap:var(--space-1)}
.readout .v{font-size:var(--text-h2);font-weight:var(--w-black);color:var(--primary-pressed);
  font-variant-numeric:tabular-nums;letter-spacing:var(--tr-h2);line-height:var(--lh-none)}
.readout .l{font-size:var(--text-caption);color:var(--text-2);font-weight:var(--w-semibold);
  line-height:var(--lh-none)}
.readout .tail{display:inline-flex;align-items:center;gap:var(--space-2);
  background:var(--surface);border-radius:var(--radius-pill);
  padding:var(--space-2) var(--space-3);font-size:var(--text-caption);
  font-weight:var(--w-semibold);color:var(--primary-pressed)}
.readout .tail svg{width:var(--icon-sm);height:var(--icon-sm)}
/* ipuçları — ikonlu liste */
.tips{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3)}
.tips li{display:flex;gap:var(--space-3);align-items:flex-start;
  font-size:var(--text-caption);color:var(--text-2);line-height:var(--lh-snug)}
.tips svg{width:var(--icon-sm);height:var(--icon-sm);color:var(--primary);margin-top:var(--space-1)}
.tips b{color:var(--text);display:block}
/* BÖLÜM VE ADIM BAŞLIKLARI — `.lbl` DEĞİL.
   [KUSUR 2026-08-14 · derin tarama] `.lbl` (11 px, büyük harf) sitede 12 yerde BÖLÜM BAŞLIĞI
   olarak kullanılıyordu. En ağırı ödeme akışıydı: `1 · Teslimat`, `2 · İndirimler`,
   `3 · Sipariş notu`, `4 · Ödeme yöntemi`, `5 · Onay` — yani sitenin EN KRİTİK akışının beş
   adımı da sayfadaki en küçük puntoyla başlıyordu. Siparişlerim, sepet ve davet sayfalarında
   da aynısı vardı.
   `.lbl` bir ALAN ETİKETİDİR (form girdisinin üstündeki söz) — o kullanım yerinde kaldı
   (`_QuantityPicker`, `_CodeForm`). Başlık olan yerler gerçek başlığa çevrildi. */
.sec-title{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3);
  color:var(--text);margin-bottom:var(--space-4)}

/* Ödeme adımı başlığı: numara + ad. Numara görsel çapa — beş panelin sırası bir bakışta
   okunuyor, "3. adımdayım" sorusu cevaplanıyor. */
.step-title{display:flex;align-items:center;gap:var(--space-3);
  font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3);
  color:var(--text);margin-bottom:var(--space-4)}
.step-no{display:grid;place-items:center;flex:none;
  width:var(--icon-xl);height:var(--icon-xl);border-radius:var(--radius-pill);
  background:var(--primary-soft);color:var(--primary-pressed);
  font-size:var(--text-label);font-weight:var(--w-black);letter-spacing:0}

.lbl{font-size:var(--text-micro);font-weight:var(--w-bold);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--text-2);margin-bottom:var(--space-3)}
.lbl--flush{margin-bottom:0}
.fine{font-size:var(--text-caption);color:var(--text-2)}

/* ---------- form ---------- */
/* Tek kolon, etiket üstte (§F). Alan genişliği okunabilir sınırda tutulur —
   geniş panelde 800 px'lik "ad soyad" kutusu içeriğiyle orantısız kalır (§B4). */
.field{display:grid;gap:var(--space-2);max-width:var(--field-w)}
.field label{font-size:var(--text-label);font-weight:var(--w-bold)}
form.stack>.btn{justify-self:start;min-width:calc(var(--control-h) * 4)}
@media (max-width:640px){form.stack>.btn{justify-self:stretch}}
.input{font:inherit;font-size:var(--text-body);line-height:var(--lh-none);
  padding:var(--space-2) var(--space-4);height:var(--control-h);width:100%;
  background:var(--surface);color:var(--text);
  border:var(--border-hairline) solid var(--control-border);border-radius:var(--radius-lg);
  transition:border-color var(--dur-micro) var(--ease-out)}
.input::placeholder{color:var(--text-2)}
.input:hover{border-color:var(--primary-hover)}
.input:focus{outline:var(--border-focus) solid var(--focus);outline-offset:var(--border-hairline);
  border-color:var(--primary)}
.input--code{letter-spacing:var(--space-1);font-weight:var(--w-bold);
  font-variant-numeric:tabular-nums}
/* Son kullanma + güvenlik kodu: iki EŞİT sütun, formun tam genişliğinde.
   Önceden ikisi de sabit 176 px'ti ve satır 608'de bitiyordu; üstteki alanlar 764'e kadar
   uzandığı için formun sağ kenarı tırtıklı kalıyor, 156 px'lik ölü boşluk "yarım kalmış"
   okunuyordu (ölçüldü 2026-08-10). Ödeme adımında bu his doğrudan güveni düşürür.
   Alanlar dar OLMALI (dört hane, üç hane) ama satır kapanmalı — çözüm eşit sütun. */
.rw--cardrow{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3);align-items:start;
  max-width:var(--field-w)}   /* tek alanlarla AYNI sağ kenar — form tek hizada kapanır */
.rw--cardrow .field--cvv{max-width:none}
.field--cvv{max-width:calc(var(--control-h) * 4)}
textarea.input{height:auto;padding-block:var(--space-3);resize:vertical;line-height:var(--lh-body)}
.check{display:flex;align-items:flex-start;gap:var(--space-3);cursor:pointer;
  font-size:var(--text-label);padding-block:var(--space-2)}
.check input{width:var(--control-box);height:var(--control-box);flex:none;accent-color:var(--primary);
  margin:0}
select.input{cursor:pointer;appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
    linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:right var(--space-4) center,calc(100% - var(--space-3)) center;
  background-size:var(--caret) var(--caret),var(--caret) var(--caret);background-repeat:no-repeat;padding-right:var(--space-8)}
.input[readonly]{background:var(--quiet);color:var(--text-2);cursor:default}
.input[aria-invalid="true"]{border-color:var(--danger);border-width:var(--border-control)}
/* hata ve ipucu — alanın YANINDA, tooltip'te değil (§F, §M5.3) */
.err{display:flex;align-items:flex-start;gap:var(--space-2);font-size:var(--text-caption);
  font-weight:var(--w-semibold);color:var(--danger);line-height:var(--lh-snug)}
.err svg{width:var(--icon-sm);height:var(--icon-sm);margin-top:var(--space-1)}
.err[hidden]{display:none}
.hint{display:flex;align-items:flex-start;gap:var(--space-2);font-size:var(--text-caption);
  color:var(--text-2);line-height:var(--lh-snug)}
.hint svg{width:var(--icon-sm);height:var(--icon-sm);margin-top:var(--space-1);color:var(--primary)}

/* ---------- ilerleme / uyarı ---------- */
.progress{height:var(--space-2);background:var(--divider);border-radius:var(--radius-pill);
  overflow:hidden}
/* Dolgu turuncuyken track'e karşı 1.58:1 idi — bilgi taşıyan grafik 3:1 ister
   (WCAG 1.4.11). Marka yeşili track'e karşı 5.28:1. */
.progress i{display:block;height:100%;background:var(--primary);border-radius:var(--radius-pill);
  transition:width var(--dur-enter) var(--ease-out)}
.progress i[data-done="1"]{background:var(--primary)}
.nudge{background:linear-gradient(100deg,var(--accent-soft),var(--surface));
  border-radius:var(--radius-lg);padding:var(--space-4);display:grid;gap:var(--space-3)}
.nudge .t{font-size:var(--text-label);font-weight:var(--w-bold);
  display:flex;align-items:center;gap:var(--space-3);line-height:var(--lh-snug)}
.nudge .t svg{color:var(--accent-ink)}
.nudge .t b{color:var(--accent-ink);font-variant-numeric:tabular-nums}
.alert{border-radius:var(--radius-lg);padding:var(--space-4);font-size:var(--text-label);
  display:flex;gap:var(--space-3);align-items:flex-start;line-height:var(--lh-snug)}
.alert>svg{width:var(--icon-md);height:var(--icon-md);margin-top:var(--space-1)}
.alert--warn{background:var(--warning-soft)} .alert--warn b,.alert--warn>svg{color:var(--warning)}
.alert--err{background:var(--danger-soft)}  .alert--err b,.alert--err>svg{color:var(--danger)}
/* 9.2 — AYRI BİR "başarı yeşili" YOK. Marka #00674f ile #1a6b3c arasındaki fark 1.05:1;
   markası yeşil olan bir sitede ikinci yeşil sinyal taşımıyor, yalnız sinyal taşıdığını
   İDDİA ediyor. Onayın anlamını tik ikonu ve cümlenin kendisi taşır (karar: Eyüp). */
/* Fiyat değişimi listesi: eski → yeni, artış/düşüş renkle DEĞİL yönle okunur.
   Artan fiyatı kırmızıya boyamak kullanıcıyı korkutup karar aldırmaya çalışmak olurdu
   (§O); yön oku ve sayının kendisi yeterli. Yalnız düşüş marka rengiyle vurgulanır —
   kullanıcının LEHİNE olan tek durum. */
.pc-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-2)}
.pc-row{display:flex;align-items:baseline;flex-wrap:wrap;gap:var(--space-2);
  padding:var(--space-3) var(--space-4);background:var(--quiet);border-radius:var(--radius-lg);
  font-size:var(--text-label)}
.pc-nm{font-weight:var(--w-bold);flex:1 1 100%;min-width:0}
.pc-old{color:var(--text-2);text-decoration:line-through;font-variant-numeric:tabular-nums}
.pc-arrow{display:inline-flex;color:var(--text-2);transform:rotate(-90deg)}
.pc-arrow svg{width:var(--icon-sm);height:var(--icon-sm)}
.pc-new{font-variant-numeric:tabular-nums}
.pc-new[data-up="0"]{color:var(--primary)}
.pc-unit{color:var(--text-2);font-size:var(--text-caption)}
/* Üç meşru çıkışı olan diyalogda düğmeler yan yana sığmaz ve hiyerarşi kaybolur. */
.ft--stack{flex-direction:column;align-items:stretch;gap:var(--space-2)}
.ft--stack .btn{width:100%}
.failband{align-items:flex-start}
.failband .grow{min-width:0}
.failband .btn{flex:none;align-self:center}
@media (max-width:640px){
  .failband{flex-wrap:wrap}
  .failband .btn{width:100%}
}
.alert--ok{background:var(--primary-soft)}  .alert--ok b,.alert--ok>svg{color:var(--primary)}
.toast-host{position:fixed;left:50%;bottom:var(--space-6);transform:translateX(-50%);z-index:60;
  display:grid;gap:var(--space-2);width:min(var(--toast-w),calc(100vw - var(--space-8)))}
.toast{display:flex;align-items:center;gap:var(--space-4);background:var(--neutral-900);
  color:var(--on-dark);border-radius:var(--radius-lg);padding:var(--space-3) var(--space-4);
  font-size:var(--text-label);font-weight:var(--w-semibold);box-shadow:var(--elev-float);
  animation:rise var(--dur-enter) var(--ease-out)}
.toast button{font:inherit;font-weight:var(--w-bold);color:var(--accent);background:none;border:0;
  cursor:pointer;margin-left:auto;padding:var(--space-1);flex:none}
@keyframes rise{from{opacity:0;transform:translateY(var(--space-2))}to{opacity:1;transform:none}}
/* tekrarlanan mesaj: yeni kutu açmak yerine mevcut olan bir kez seker */
.toast--again{animation:nudge var(--dur-enter) var(--ease-spring)}
@keyframes nudge{0%,100%{transform:none}40%{transform:translateY(calc(var(--space-1) * -1))}}

/* ---------- terim açıklayıcı ----------
   Metin akışını bozmadan, tıklanabilir. Hover'a bağlı DEĞİL (§M6 — dokunmatikte hover yok). */
.term{display:inline-flex;align-items:center;gap:var(--space-1);white-space:nowrap}
.term-btn{display:inline-grid;place-items:center;width:var(--icon-md);height:var(--icon-md);
  padding:0;border:0;background:none;cursor:pointer;color:var(--text-2);flex:none;
  border-radius:var(--radius-pill);
  transition:color var(--dur-micro) var(--ease-out),background var(--dur-micro) var(--ease-out)}
.term-btn svg{width:var(--icon-sm);height:var(--icon-sm)}
/* Görünen daire 20 px — metnin yanında duran bir yardım işareti büyüyemez, büyürse cümleyi
   böler. Ama TIKLANAN alan 44 olmalı (WCAG 2.5.8): pay simetrik ve TÜRETİLMİŞ, (44 − 20) / 2 = 12.
   Aynı numara sepetteki "Sepeti boşalt" ve sayaç düğmelerinde de kullanılıyor — hedefi
   büyütmenin yolu görünümü büyütmek değil. */
.term-btn{position:relative}
.term-btn::before{content:"";position:absolute;inset:-12px}
.term-btn:hover{color:var(--primary);background:var(--primary-soft)}
.term-body p{margin-bottom:var(--space-3);line-height:var(--lh-body)}
.term-body p:last-child{margin-bottom:0}
.term-body .fine{background:var(--quiet);border-radius:var(--radius-lg);
  padding:var(--space-3) var(--space-4);line-height:var(--lh-snug)}

/* metin gibi görünen buton — yasal metni katmanda açar */
/* Cümle içinde duruyor, yüksekliğini satır yüksekliği belirliyor (22px) — WCAG 2.5.8'in sert
   alt sınırı 24. Metni büyütmek cümleyi bozar; tıklama alanı ::before ile genişletiliyor. */
.lnk--btn{position:relative;font:inherit;background:none;border:0;padding:0;cursor:pointer;
  text-decoration:underline;text-underline-offset:var(--space-1)}
.lnk--btn::before{content:"";position:absolute;inset-block:-6px;inset-inline:-4px}
/* [SİLİNDİ 2026-08-16] Burada `.legal-body--modal{max-width:none}` vardı: `.legal-body`nin
   PANEL üzerindeki 34rem tavanını ödeme katmanında iptal ediyordu. Tavan satıra taşınınca
   (bkz. `.legal-body > *`) ezecek bir şey kalmadı — katman zaten `--sheet-w` (460) ve gövde
   payından sonra ~412 px, yani satır tavanının altında. Sınıf işaretlemede duruyor
   (`Checkout/Index.cshtml`) ama artık yalnız niyet belirtiyor, ölçü taşımıyor. */
/* YASAL BELGE — METİN SOLA HİZALI, DÜZEN SAYFANIN TEK EKSENİNDE.

   [İKİ ADIMDA DÜZELMİŞTİ]
   (1) Panel 544 px'e kilitliydi; 240 px'lik navigasyonun yanındaki sütun 949 px olduğu için
       405 px boş kalıyordu.
   (2) Bunu çözerken paneli doldurup İÇİNDEKİ blokları ortalamıştım — Eyüp yakaladı: "içerikler
       neden böyle ortalanmış duruyor?". Haklıydı. Sözleşme metni ORTALANMAZ; madde madde okunan
       bir belgede her paragrafın sol kenarı aynı hizada olmak zorundadır, yoksa göz her satır
       başında yeniden yer arar.

   [ÜÇÜNCÜ ADIM · 2026-08-16 · Eyüp: "bazı sayfalarda dar" · TARAYICIDA ÖLÇÜLDÜ]
   2. adımın çözümü DÜZENİN TAMAMINI ortalamaktı ve kusuru oydu: ortalama sayfanın kendi başlık
   bandını dışarıda bıraktı. Aynı sayfada iki sol kenar ölçüldü —
       .page-head             L=116  W=1280
       .acct-layout.legal-layout  L=304  W=904     → 188 px kayma
   Kural zaten bu dosyada yazılıydı (bkz. `.legal-body` üstündeki not): "farklı genişlikte
   kutular ortalanınca sol kenarları ayrışır ve sayfa kayık görünür". Kendi kuralımızı kendi
   düzeltmemizle çiğnemişiz.

   Düzen artık ortalanmıyor. Kardeşi `/yasal/veri-talebi` ile BİREBİR aynı `.acct-layout`
   (ray 240 + içerik 1016) ve sayfanın tek ekseninde. İki kardeşin ayrışması zaten tesadüftü:
   aynı controller, aynı ray, iki farklı genişlik.

   OKUMA ÖLÇÜSÜNÜ TAŞIYAN ŞEY: PANELİN GENİŞLİĞİ.

   [İKİ ADIMDA ÇÖZÜLDÜ — ikincisi 2026-08-18]
   (a) Önce ölçüyü panelden SATIRA taşımıştım: düzen 1016'lık standart sütuna alınınca panelin
       34rem'lik tavanı satırı değil paneli daraltıyordu, o yüzden tavan `.legal-body > *`e geçti.
   (b) Eyüp yakaladı: "legal-body sınıfını kaldırınca düzeliyor". Haklıydı ve ölçüldü — panel
       1016, satır 544, yani BEYAZ SAYFANIN İÇİNDE 424 px ölü alan. Kutuyu doldurmayan metin,
       kutunun yarısının çizilmediği izlenimi veriyor; kaldırılan sınıfın "düzeltmesi" de tam
       olarak bu tavanı düşürmesiydi.

   Doğrusu: satırı genişletmek DEĞİL, paneli okuma ölçüsüne indirmek. Düzen yeniden 904 px
   (ray 240 + boşluk 24 + 40rem) — ama 2026-08-16'da kaldırılan `margin-inline:auto` GERİ
   GELMİYOR. Ölü alanın yeri önemli: panelin İÇİNDE beyaz boşluk "yarım çizilmiş sayfa"dır,
   düzenin SAĞINDA sayfa zemini ise normal bir kenar payıdır. Eksen de korunuyor: başlık bandı
   1280 @@ L=116, düzen 904 @@ L=116 — tek sol kenar (§R6.5).
   Satır artık panelin kendisinden geliyor: 640 − 2×24 pay = 592 px (37rem), §B4'ün 40rem
   tavanının altında. */
.legal-layout{max-width:calc(var(--acct-rail) + var(--space-6) + 40rem)}

/* sepet altı ikincil aksiyon */
.cart-foot{padding:var(--space-3) var(--space-6) var(--space-4);
  border-top:var(--border-hairline) solid var(--divider);display:flex;justify-content:flex-end}
.cart-foot .linkbtn{display:inline-flex;align-items:center;gap:var(--space-2);color:var(--text-2);
  text-decoration:none}
.cart-foot .linkbtn svg{width:var(--icon-sm);height:var(--icon-sm)}
.cart-foot .linkbtn:hover{color:var(--danger)}

/* ---------- sepet satırı / özet ---------- */
/* Kart içinde TEK dikey kenar: başlık ve altlık 24 px'teyken satırlar 16 px'te
   başlıyordu — 8 px'lik kayma (§C2). */
.citem{display:grid;grid-template-columns:var(--thumb-sm) minmax(0,1fr) auto;gap:var(--space-4);
  align-items:center;padding:var(--space-4) var(--space-6);
  border-bottom:var(--border-hairline) solid var(--divider)}
.citem:last-child{border-bottom:0}
/* KIRPMA YASAĞI (2026-08-12 · Eyüp) — ürün/banner görseli kesilmez; bkz. `.pcard .art img`. */
.citem img{width:var(--thumb-sm);height:var(--thumb-sm);border-radius:var(--radius-lg);
  object-fit:contain;background:var(--primary-soft)}
.citem .nm{font-weight:var(--w-bold);font-size:var(--text-label);line-height:var(--lh-snug)}
.citem .sb{font-size:var(--text-caption);color:var(--text-2);font-variant-numeric:tabular-nums;
  display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap}
.citem .rt{display:grid;gap:var(--space-2);justify-items:end}
/* width DEĞİL min-width: kısa etiketlerde hiza için sabit taban, uzun etiketlerde
   ("2 demet") kutunun büyümesine izin. Sabit genişlik etiketi kırıyordu. */
.citem .rt .stepper{min-width:calc(var(--control-h) * 3)}
/* Dokunma hedefi: görünen kutu 29 px, kılavuz 44 (§E). Metni büyütmek yerine tıklama alanı
   ::before ile genişletiliyor — ürün kartındaki stepper'da kullanılan aynı çözüm. Görsel
   geometri prototipteki gibi kalır, parmak hedefi standarda çıkar. */
.citem .drop{position:relative}
.citem .drop::before{content:"";position:absolute;inset-block:-8px;inset-inline:-8px}
.citem .rt .stepper button{position:relative}
.citem .rt .stepper button::before{content:"";position:absolute;inset-block:-4px;inset-inline:-4px}
.cart-foot .linkbtn{position:relative}
/* -9 sihirli sayı değil, TÜRETİLMİŞ: (44 − 26) / 2. Kontrol cümle içinde olduğu için yüksekliği
   satır yüksekliğinden geliyor; hedefi 44'e çıkarmanın tek yolu simetrik pay. */
.cart-foot .linkbtn::before{content:"";position:absolute;inset-block:-9px;inset-inline:-8px}
.citem .drop{font:inherit;font-size:var(--text-caption);font-weight:var(--w-bold);
  color:var(--text-2);background:none;border:0;cursor:pointer;padding:var(--space-1) 0;
  justify-self:start;display:inline-flex;align-items:center;gap:var(--space-2);
  transition:color var(--dur-micro) var(--ease-out)}
.citem .drop svg{width:var(--icon-sm);height:var(--icon-sm)}
.citem .drop:hover{color:var(--danger)}
/* ≤640: 3 sütun (72 + ad + 132 px sayaç) 360 px'e sığmıyordu — ad tek kelimeye
   düşüyor, birim fiyat satırı kırpılıyordu. Sayaç ALT SATIRA iner, görselle
   hizalı kalır: okuma sırası ad → fiyat → miktar (§H3). */
@media (max-width:640px){
  .citem{grid-template-columns:var(--thumb-sm) minmax(0,1fr);
    row-gap:var(--space-3);padding-inline:var(--space-4)}
  .citem .rt{grid-column:2;justify-items:stretch;
    grid-auto-flow:column;justify-content:space-between;align-items:center}
  /* width DEĞİL min-width: kısa etiketlerde hiza için sabit taban, uzun etiketlerde
   ("2 demet") kutunun büyümesine izin. Sabit genişlik etiketi kırıyordu. */
.citem .rt .stepper{min-width:calc(var(--control-h) * 3)}
}
.panel--flush{padding:0;overflow:hidden}
.panel-head{padding:var(--space-4) var(--space-6);background:var(--primary);color:var(--on-primary);
  display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:var(--space-2)}
.panel-head small{color:var(--pine-100);font-weight:var(--w-semibold)}
/* Panel başlığı sayfanın h1'i olabilir; semantik başlık, görünüm ölçülü.

   [DÜZELTİLDİ 2026-08-22 · denetim O1] Punto `--text-body` (16) idi ve gerekçesi "görünüm kalın
   gövde metni"ydi. Ölçüldü: sepette sayfa başlığı 16 px, ürün adları da 16 px — ikisini ayıran
   tek şey panel başlığının YEŞİL zemini kalıyordu. §R3.2: "İki kademe aynı puntodaysa kademe
   DEĞİLDİR"; §R3.3: "Kademe RENKLE değil önce BOYUTLA kurulur." Yani hiyerarşi işaretlemede
   vardı, ekranda yoktu.
   Bir kademe yukarı: `--text-h3` (20 px, ölçekte "alt başlık"). 31 px'e çıkarılmadı — başlık
   bir şeridin içinde duruyor, sayfanın tepesinde değil; 20 px ürün adlarının üstüne gerçek bir
   basamak koyuyor ve şeridi kalınlaştırmıyor. Sınıf yalnız burada kullanılıyor (tek çağrı yeri
   `Cart/_Body.cshtml`), yani değişiklik başka yüzeye sızmıyor. */
.panel-title{font-size:var(--text-h3);font-weight:var(--w-bold);letter-spacing:var(--tr-h3);
  line-height:var(--lh-snug)}
/* .check içindeki açıklama: <span> içinde <div> geçersizdi, blok gösterimi CSS'ten gelir */
.check .fine,.rw--split .fine{display:block}
.panel-head--quiet{background:var(--quiet);color:var(--text)}
.order-head{justify-content:space-between;margin-bottom:var(--space-6)}
.center{text-align:center} .center-items{justify-items:center}
.start{text-align:left} .start-items{justify-items:start}
.rw--center{justify-content:center}
.gap-block--lg{margin-block:var(--space-16)}
.gap-block{margin-block:var(--space-8)}
.linkbtn{font:inherit;font-weight:var(--w-bold);color:var(--primary-pressed);background:none;border:0;
  cursor:pointer;padding:0;text-decoration:underline;text-underline-offset:var(--space-1)}
.sums{display:grid;gap:var(--space-2);padding:var(--space-6);background:var(--quiet)}
/* engellenen checkout adımı — eksik olan yerinde işaretlenir */
.panel[data-blocked]{box-shadow:0 0 0 var(--border-emphasis) var(--danger),var(--elev-card)}
.step-msg{margin-bottom:var(--space-3)}
.step-msg[hidden]{display:none}

.sums-note{display:flex;gap:var(--space-3);align-items:flex-start;
  padding:var(--space-3) var(--space-6) var(--space-4);background:var(--accent-soft);
  color:var(--accent-ink);font-size:var(--text-caption);line-height:var(--lh-snug)}
.sums-note svg{width:var(--icon-sm);height:var(--icon-sm);flex:none;margin-top:var(--space-1)}
/* Onay özeti — "nereye / ne zaman" satırları. Uyarı bandı değil KAYIT: nötr yüzey,
   etiket soluk, değer kalın; göz değere gider. */
.recap{display:grid;gap:var(--space-3);margin:0;padding:var(--space-4) var(--space-6);
  background:var(--quiet);border-radius:var(--radius-lg)}
.recap>div{display:grid;grid-template-columns:minmax(0,auto) minmax(0,1fr);
  gap:var(--space-2) var(--space-4);align-items:baseline}
.recap dt{display:flex;align-items:center;gap:var(--space-2);
  font-size:var(--text-caption);color:var(--text-2);font-weight:var(--w-semibold);white-space:nowrap}
.recap dt svg{width:var(--icon-sm);height:var(--icon-sm);color:var(--text-2)}
.recap dd{margin:0;font-size:var(--text-label);min-width:0}
@media (max-width:640px){.recap>div{grid-template-columns:1fr;gap:var(--space-1)}}
.sums-note .linkbtn{color:var(--accent-ink)}
.sl{display:flex;justify-content:space-between;gap:var(--space-4);font-size:var(--text-label)}
.sl span:last-child{font-variant-numeric:tabular-nums;font-weight:var(--w-semibold)}
.sl small{color:var(--text-2);font-weight:var(--w-regular)}
.sl--disc span:last-child{color:var(--primary)}
/* Adsız indirim (sipariş makbuzunda kampanya adı saklanmıyor) boş bir <small> basar; boş etiket
   kendinden önceki boşlukla birlikte satırda ölü bir aralık bırakır. Görünüm koşullu, İŞARETLEME
   değil — koşulu Razor'a taşımak `@if`in düz metne yapışmasına ve kodun ekrana basılmasına yol
   açmıştı (bkz. Views/Cart/_Totals.cshtml notu, 2026-08-22). */
.sl--disc small:empty{display:none}
.sl--total{border-top:var(--border-emphasis) solid var(--divider);margin-top:var(--space-2);
  padding-top:var(--space-3);font-size:var(--text-h3);font-weight:var(--w-black);
  letter-spacing:var(--tr-h3)}
.two{display:grid;grid-template-columns:minmax(0,1fr) var(--rail-w);gap:var(--space-6);
  align-items:start}
@media (max-width:1024px){.two{grid-template-columns:1fr}}
/* Ofset ÖLÇÜLEN yığından türer. Sabit 76 px yazılıydı; üst çubuk + durum şeridi
   128 px olunca panelin 52 px'i çubuğun altında kayboluyordu. */
.sticky{position:sticky;top:calc(var(--topbar-h) + var(--space-2))}
/* [KUSUR 2026-08-14 · derin tarama] ÖDEME SAYFASINDA YAPIŞKANLIK ÖLÜYDU.
   Sepette `.sticky` doğrudan `.two`'nun çocuğu, yani ızgara ÖĞESİ: `align-items:start` kutuyu
   kısaltsa da yapışkanın kapsayan bloğu ızgara ALANI (satır yüksekliği) olduğu için yol alıyor.
   Ödemede araya `#checkout-summary` giriyor — parça tazelemenin hedefi, kaldırılamaz. O zaman
   ızgara öğesi sarmalayıcı oluyor ve `align-items:start` onu 439 px'e kısaltıyor; içerideki
   `.sticky`'nin kapsayan bloğu artık o 439 px. Yol = 0, yani yapışkan hiç kaymıyor.
   Ölçüldü: sayfanın altında (onay kutusunun olduğu yerde) "Siparişi tamamla" düğmesi ekranın
   606 px yukarısında kalıyor ve sağ sütun 600 px boş görünüyordu — ödeme sayfasının EN KRİTİK
   anında ödeme düğmesi ekranda değildi.
   `stretch` sarmalayıcıyı satır yüksekliğine çıkarır; kutu görünmez (zeminsiz), yalnız içindeki
   yapışkana yol açar. */
#checkout-summary{align-self:stretch}
/* Sepet aksiyon doku — geniş ekranda özetin akışında, ≤960'ta ekranın altında sabit.
   Aksiyon mantığı (kapalı / eşik altı / hazır) TEK yerde üretilir; yalnız konumu değişir. */
/* AKSİYON SATIRI: solda tutar, sağda düğme.
   [DEĞİŞTİ 2026-08-14 · Eyüp: "altlı üstlü kötü duruyor"] Masaüstünde dok bir SÜTUNDU ve tam
   genişlik bir düğme basıyordu; hemen üstündeki döküm de "Toplam" satırıyla bitiyordu. Yani
   ekranda alt alta iki blok vardı ve ikisi aynı şeyi anlatıyordu: ödenecek tutar ve onu ödeme
   aksiyonu. Tek satıra alındılar — tutar kararın girdisi, düğme kararın kendisi; yan yana
   durunca göz bir kez duruyor.
   Dökümdeki "Toplam" satırı bu sayfada artık BASILMIYOR (bkz. `_Totals` · HideGrandTotal),
   yoksa aynı sayı 40 px arayla iki kez yazardı. */
.cta-dock{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  flex-wrap:wrap}
.cta-dock .dock-sum{display:flex;align-items:baseline;gap:var(--space-2);
  font-size:var(--text-label);color:var(--text-2)}
.cta-dock .dock-sum b{font-size:var(--text-h2);font-weight:var(--w-black);color:var(--text);
  letter-spacing:var(--tr-h2);font-variant-numeric:tabular-nums}
/* Düğme içeriği kadar; `btn--block` kalksa da dar ekranda tam genişliğe döner (aşağıda). */
.cta-dock form{flex:none}
/* Engelli/eşik altı hâlleri düğme + açıklama taşıyor: onlar sütun kalır, çünkü açıklama
   düğmenin ALTINA aittir — yan yana konursa satır uzayıp okunmaz olur. */
.cta-dock .stack--tight{flex:1 1 100%}
/* Dok yalnız GERÇEK bir aksiyon varken sabitlenir. Teslimat kapalıyken blok üç
   satır (pasif başlık + açıklama + "başka adres") = 206 px; ekranın dörtte birini
   tıklanacak bir şeyi olmayan bir kutuya vermek §H1'i tersine çevirir. O durumda
   akışta kalır, kullanıcı okuyup geçer. */
@media (max-width:1024px){
  .cta-dock[data-dock="blocked"]{position:static}
  .cta-dock{position:fixed;left:0;right:0;bottom:var(--consent-h);z-index:45;
    background:var(--surface);border-top:var(--border-hairline) solid var(--divider);
    box-shadow:var(--elev-bar);padding:var(--space-3) var(--grid-margin);
    padding-bottom:calc(var(--space-3) + env(safe-area-inset-bottom, 0px))}
  /* Dar ekranda dok sabit bir çubuk: tutar ve düğme yine yan yana ama düğme kalan yeri
     doldurur — başparmak bölgesindeki birincil aksiyon dar olmamalı (§H1). */
  .cta-dock form{flex:1 1 auto}
  .cta-dock .btn{width:100%}
  .cta-dock .dock-sum b{font-size:var(--text-h3);letter-spacing:var(--tr-h3)}
  /* Dokta ikinci/üçüncü satır (açıklama, "başka adres") yer kaplar; kısa tutulur. */
  .cta-dock .fine{margin:0}
}
.solo{width:min(var(--field-w),100%);margin-inline:auto}

/* ---------- takip ---------- */
/* ---- canlı kurye haritası (sipariş detayı, yalnız "Yolda") ----------------
   Şeridin hemen altında durur. Boyu SABİT: harita geç yüklenen bir bileşen ve yüksekliği
   içeriğe bıraksaydık, kutu kurulduğu anda altındaki döküm aşağı zıplardı.
   Tüm renk/aralık token'lardan; harita kendi görselini zaten getiriyor, kap sessiz kalmalı. */
.track-map{margin-top:var(--space-6);display:grid;gap:var(--space-2)}
.track-map-canvas{height:220px;border-radius:var(--radius-lg);overflow:hidden;
  background:var(--quiet);border:var(--border-hairline) solid var(--divider)}
/* Kanvas ancak harita KURULUNCA görünür — boş gri bir dikdörtgen "bozuk" okunur. */
.track-map:not([data-ready]) .track-map-canvas{display:none}
.track-map-wait,.track-map-stale{display:flex;align-items:center;gap:var(--space-2);
  color:var(--text-2);font-size:var(--text-caption)}
.track-map-wait svg,.track-map-stale svg{width:var(--icon-md);height:var(--icon-md);flex:none}
/* Konum bayatladı: uyarı rengi DEĞİL — bu bir arıza değil, bilgi. Kurye tünelde olabilir. */
.track-map-stale{color:var(--text-2)}
/* Kurye pini: marka yeşili, beyaz halka ile zeminden ayrılır. Adres pini nötr koyu —
   iki pin aynı ağırlıkta olsaydı "hangisi ben" sorusu doğardı. */
/* [DÜZELTİLDİ 2026-08-22 · denetim O5] Kural üç ham değer taşıyordu: `18px` (4'ün katı değil,
   §0.3 m.1), `3px` kenarlık ve tokensiz bir gölge (`0 1px 4px rgb(0 0 0 / .35)`).
   · Ölçü ikon ölçeğine alındı: 20 px (`--icon-md`). Küçülten yön seçilmedi — pin harita
     üstünde okunmalı, 16'ya inmek görünürlüğü düşürürdü.
   · Kenarlık `--border-focus` (3 px): DEĞER aynı, artık ölçekten geliyor.
   · Gölge KALDIRILDI, token eklenmedi. İşlevi zeminden ayırmaktı ve beyaz halka bunu zaten
     yapıyor; yalnız bu bileşen için yedinci bir yükseklik token'ı açmak §B9'un tavanını
     ("üç seviye yeter") daha da aşardı. */
.gc-pin{width:var(--icon-md);height:var(--icon-md);border-radius:var(--radius-pill);
  border:var(--border-focus) solid var(--neutral-000)}
.gc-pin--courier{background:var(--primary)}
.gc-pin--dest{background:var(--neutral-900)}

.track{display:grid;gap:0}
.step{display:grid;grid-template-columns:var(--icon-lg) 1fr;gap:var(--space-4);
  padding-bottom:var(--space-6);position:relative}
.step:last-child{padding-bottom:0}
.step::before{content:"";position:absolute;
  left:calc(var(--icon-lg)/2 - var(--border-hairline));top:var(--icon-lg);
  bottom:0;width:var(--border-emphasis);background:var(--divider)}
.step:last-child::before{display:none}
.step .dot{width:var(--icon-lg);height:var(--icon-lg);border-radius:var(--radius-pill);
  background:var(--divider);color:var(--text-2);display:grid;place-items:center;z-index:1}
.step .dot svg{width:var(--icon-sm);height:var(--icon-sm)}
.step[data-on="1"] .dot{background:var(--primary);color:var(--on-primary)}
.step[data-now="1"] .dot{background:var(--primary);color:var(--on-primary);
  animation:pulse 1.6s ease infinite}
.step .tx b{display:block;font-size:var(--text-label);font-weight:var(--w-bold)}
.step .tx span{font-size:var(--text-caption);color:var(--text-2)}
.step[data-on="0"] .tx b{color:var(--text-2)}
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 var(--pulse-from)}
                 50%{box-shadow:0 0 0 var(--space-2) var(--pulse-to)}}

/* ---------- İSKELET (§A4) ----------
   Düz gri kutu YASAK (dolunca zıplar). İskelet gerçek bileşenin sınıflarıyla kurulur;
   yükseklik elle verilmez, yapıdan gelir → dolduğunda hiçbir şey oynamaz (A4.1). */
/* ---------- beklemedeki kontrol ----------
   `busy()` JS'te aria-busy yazıyordu ama hiçbir kural onu GÖRÜNÜR kılmıyordu: kullanıcı basıyor,
   ekranda hiçbir şey değişmiyordu. Kılavuz §A1'e göre 400 ms–1 sn arası bekleme ÖĞE DÜZEYİNDE
   durum ister; §A4'e göre bir İŞLEM beklenirken iskelet değil buton-içi durum doğrudur.

   `disabled` KULLANILMIYOR (§0.3 madde 12b): kilitli düğme sebebini söylemez ve odağı kaybettirir.
   aria-busy hem ekran okuyucuya doğru şeyi söyler hem çift gönderimi JS tarafında zaten yutuluyor.
   Animasyon yok, yalnız opaklık — hareket bilgi taşımıyorsa gecikmedir (§A6.1). */
[aria-busy="true"]{cursor:progress}
/* Kaplama iskeleti: YER tutar, görünmez başlar. §A4 400 ms altındaki beklemede gösterge
   yasaklıyor (titreme), §A4.1 ise yüksekliğin yapıdan gelmesini istiyor — ikisi ancak
   `visibility` ile birlikte sağlanır. `display:none` olsaydı kutu üç kez boyut değiştirirdi. */
/* MODAL AÇIKKEN ARKA PLAN KAYMAZ.
   [KUSUR 2026-08-10 · denetim E4] §E'nin "Modal sözleşmesi (istisnasız)" 5. maddesi hiçbir
   katmanda yoktu: miktar penceresi açıkken sayfa 185→585, çekmece açıkken 0→400 kaydı (ölçüldü).
   `overscroll-behavior:contain` (panellerde var) yalnız panelin İÇİNDEN başlayan kaydırmayı
   kesiyor; panelin DIŞINDA, perdenin üstünde dönen tekerleği durdurmuyor.

   `:has(dialog[open])` tek kuralla bütün modalleri kapsıyor — açılan her yeni pencere için ayrı
   bir JS bayrağı tutmak, bir gün birinin unutulması demekti.
   `scrollbar-gutter` ŞART: kaydırma çubuğu kaybolunca sayfa 15 px genişleyip zıplıyordu. */
html{scrollbar-gutter:stable}
html:has(dialog[open]){overflow:hidden}

[data-overlay-skeleton],[data-skeleton]{visibility:hidden}
[data-overlay-skeleton][data-shown],[data-skeleton][data-shown]{visibility:visible}
/* Kaplama TAZELENİRKEN eski içerik ekranda kalır (bayat göstermek, boş göstermekten iyidir —
   lazy yükleme deseninin kuralı). Ama beklemede olduğu görünmeli: ikinci açılışta hiçbir işaret
   yoktu, kullanıcı eski listeye bakıp güncel sanıyordu. Sayı ve satır yerinde kalır, tazeliği
   soluklaşır (§A5.2: otoriter değer optimistik gösterilmez). */
[data-area-mount][aria-busy="true"] > :not([data-overlay-skeleton]),
[data-cart-drawer-mount][aria-busy="true"] > :not([data-overlay-skeleton]),
[data-consent-mount][aria-busy="true"] > :not([data-overlay-skeleton]){opacity:.45;
  transition:opacity var(--dur-micro) var(--ease-out)}
/* KURAL SINIFA DEĞİL DURUMA BAĞLI. [KUSUR 2026-08-21 · Eyüp] Seçici `.btn[aria-busy]` idi, oysa
   `MNV.busy` durumu HANGİ öğeye basıldıysa ona yazıyor. Sonuç: `.btn` olmayan her gönderici —
   kod ekranındaki "Tekrar gönder", hassas işlem doğrulamasındaki "Kod gelmedi mi?", üst çubuktaki
   "Çıkış yap" — basılıyor, sunucuya gidiliyor, ekranda HİÇBİR ŞEY değişmiyordu. Bir davranışı
   görünür kılan kuralı sunuma (sınıfa) bağlamak, davranışın kapsamıyla sunumun kapsamının bir gün
   ayrışması demekti; ayrışmıştı. Kaplar hariç tutuluyor: liste/parça tazelenirken solması gereken
   kutuların kendi kuralları var (yukarıda). */
button[aria-busy="true"],a[aria-busy="true"]{opacity:.55;pointer-events:none}

/* KATALOG TAZELENİRKEN. [KUSUR 2026-08-10] catalog-nav.js `aria-busy` yazıyordu ve kendi yorumunda
   "beklemede olduğu görünür" diyordu — ama onu görünür kılan TEK kural `cursor:progress`'ti, yani
   dokunmatikte HİÇBİR geri bildirim yoktu. Kullanıcının anlattığı şey buydu: çipe basılıyor, bir
   iki saniye hiçbir şey olmuyor, sonra blok birden değişiyor. Tepkisiz bekleme + ani değişim,
   kullanıcı gözünde tam olarak "postback" demek.

   Gecikme 400 ms (§A4): hızlı dönen istekte hiçbir şey titremesin. Geri dönüşte gecikme YOK —
   temel kuraldaki geçiş devreye girer, içerik anında netleşir.

   Eski liste EKRANDA KALIR (§A4.2): elimizdeki veriyi atıp yerine boşluk koymak, bekleyişi
   uzatmaktan başka bir işe yaramaz. Tıklama kapatılır çünkü gelen cevap zaten bu isteğe ait. */
[data-catalog-results]{transition:opacity var(--dur-micro) var(--ease-out)}
[data-catalog-loading] [data-catalog-results]{opacity:.5;pointer-events:none;transition-delay:var(--dur-wait-gate)}
/* İnce çubuk: soluklaşma "bir şey oluyor" der, çubuk "SÜRÜYOR" der. Çipin hemen altında, yani
   tıklamadan sonra gözün zaten durduğu yerde. Aynı deyim sepette de kullanılıyor (.cart-wait) —
   iki ayrı bekleme dili tutmuyoruz. Yer TUTAR (height sabit), yalnız opaklığı değişir: sonradan
   belirip listeyi aşağı itseydi kendisi bir zıplama kaynağı olurdu (§A4.1). */
.cat-wait{display:block;height:2px;margin-bottom:var(--space-4);border-radius:var(--radius-pill);
  background:transparent;overflow:hidden;opacity:0;
  transition:opacity var(--dur-micro) var(--ease-out)}
[data-catalog-loading] .cat-wait{background:var(--divider);opacity:1;transition-delay:var(--dur-wait-gate)}
.cat-wait::after{content:"";display:block;width:40%;height:100%;border-radius:var(--radius-pill);
  background:var(--primary);animation:cartwait 1.1s ease-in-out infinite}
@media (prefers-reduced-motion:reduce){.cat-wait::after{animation:none;width:100%;opacity:.5}}

/* Miktar değişirken PARA yeniden hesaplanıyor. Sayı ekranda kalır (boşalt-doldur yok, §A4.2) ama
   beklemede olduğu görünür — çünkü otoriter değer optimistik gösterilmez (§A5.2). */
[data-cart-form][aria-busy="true"] .price,
[data-cart-form][aria-busy="true"] .q{opacity:.45}

/* ---------- bekleme UZARSA: ikinci kademe ----------
   Soluklaşma §A1'in "400 ms–1 sn → öğe düzeyinde durum" katmanının karşılığı ve o katmanda
   doğru. Ama bu ortamda sepet mutasyonu ~2,3 sn sürüyor (ölçüldü 2026-08-09: /sepet/cikar
   2335 ms, /sepet/guncelle 2361 ms) ve orada kural değişiyor: 1–10 sn arası BELİRSİZ ilerleme
   ister. Soluk bir satır o kadar süre boyunca "donmuş" okunuyor — kullanıcı tekrar tıklıyor.

   İki kademe, çünkü tek kademe iki latansta birden doğru olamaz: canlıda istek 200 ms sürerse
   çubuk hiç görünmez (yanıp sönme yok), 2 sn sürerse görünür. Eşik JS'te 1 sn.
   Çubuk BELİRSİZ: yüzde bilmiyoruz ve bilmediğimiz bir yüzdeyi çizmek yalan olur. */
[data-cart-form][data-slow] .cart-wait{display:block}
.cart-wait{display:none;height:2px;margin-top:var(--space-2);border-radius:var(--radius-pill);
  background:var(--divider);overflow:hidden}
.cart-wait::after{content:"";display:block;width:40%;height:100%;border-radius:var(--radius-pill);
  background:var(--primary);animation:cartwait 1.1s ease-in-out infinite}
@keyframes cartwait{0%{transform:translateX(-100%)}100%{transform:translateX(250%)}}
/* Hareket bir TERCİH değil erişilebilirlik ayarı (§0.3 m.3): kapalıysa çubuk sabit durur ama
   yine görünür — "bir şey oluyor" bilgisi kaybolmaz, yalnız hareketi kaybolur. */
@media (prefers-reduced-motion:reduce){
  .cart-wait::after{animation:none;width:100%;opacity:.5}
}

/* İskeletin KENDİ token'ları var, yüzey token'ları ödünç alınmıyor. Rolleri farklı: --quiet bir
   ZEMİN (üstüne metin gelir, bu yüzden bilerek soluk), iskelet çubuğu ise ŞEKİL — görülmesi
   işinin tamamı. Ödünç alınan --neutral-050 beyaza karşı 1,14:1 ölçüldü; çubuklar basılıyordu
   ama ekranda beyaz boşluktan ayırt edilmiyordu (2026-08-09 tarayıcı ölçümü: 3 çubuk, 114 px
   yükseklik, hepsi görünmez). Görünmeyen iskelet bekleme durumu değildir (§A4).
   Yeni taban 1,43:1 — şekil okunur, ama içerik sanılacak kadar koyu değil. */
.sk{display:block;border-radius:var(--radius-sm);
  background:linear-gradient(90deg,var(--skeleton) 25%,var(--skeleton-shine) 37%,
    var(--skeleton) 63%);
  background-size:400% 100%;animation:shim 1.4s ease infinite}
@keyframes shim{0%{background-position:100% 0}100%{background-position:0 0}}
@media (prefers-reduced-motion:reduce){.sk{animation:none;background:var(--skeleton)}}

/* Yükseklikler gerçek metnin token'ından TÜRETİLİR; "yaklaşık" değer verilmez —
   6 px'lik sapma bile dolduğunda görünür zıplama yapar (A4.1). */
.sk--line{height:calc(var(--text-body) * var(--lh-none))}
.sk--price{height:calc(var(--text-h2) * var(--lh-none));width:calc(var(--control-h) * 2)}
.sk--price-sm{height:calc(var(--text-h3) * var(--lh-none));width:calc(var(--control-h) * 1.6)}
@media (max-width:640px){          /* mobilde kart fiyatı --text-h3'e iner, iskelet de inmeli */
  .pcard--skel .sk--price{height:calc(var(--text-h3) * var(--lh-none))}
}
.sk--btn{height:var(--control-h);border-radius:var(--radius-lg)}
.sk--thumb{width:var(--thumb-sm);height:var(--thumb-sm);border-radius:var(--radius-lg)}
.sk--70{width:70%} .sk--60{width:60%} .sk--40{width:40%}

.pcard--skel .name{display:grid;gap:var(--space-1);align-content:start}
.pcard--skel .art{background:var(--neutral-050)}

/* Yenileme: eski içerik EKRANDA KALIR, üstüne yeni gelir (A4.2). Boşalt-doldur yok. */
[data-busy-region="1"]{position:relative;opacity:.55;pointer-events:none;
  transition:opacity var(--dur-micro) var(--ease-out)}

/* ---------- boş durum ---------- */
/* ---------- durum sayfası (404) ---------- */
/* SAYFANIN TAMAMI MESAJ — ama kart değil, kutu değil: sayfanın kendisi.
   Boş durumdan (`.empty`) farkı, burada bir liste boş değil; kullanıcı YANLIŞ YERDE. O yüzden
   blok yalnız "yok" demiyor, yol veriyor: arama + reyonlar + çıkış.
   Sol eksende duruyor (§R6.5) — sitenin geri kalanıyla aynı hizada. Ortalamak bir seçenekti ama
   içindeki reyon rayı yatay kaydırılabilir bir şerit; onu ortalamak, şeridin sayfayla hizasını
   bozardı. */
/* Alt pay YOK: altında "Bugün tezgâhta" bölümü var ve `.section` kendi üst payını taşıyor —
   ikisini birden vermek 96 px'lik bir kopukluk üretiyordu. Öneri bloğu hiç basılmazsa
   (katalog boş) `main.wrap`ın alt payı devrede. */
/* ORTALANIR (2026-08-17 · Eyüp: "içerik ortalanmamış, sağ taraf boş" · ölçüldü).
   Sola yaslıyken 1280 px'lik tuvalde görünen en sağ nokta 686 px'ti — yani %55'i boş.
   §R6.5'in "tek sol kenar" kuralı burada geçerli değil: bu sayfanın ALTINDA tam genişlikte bir
   ürün rayı var, yani ortalanmış giriş + tam genişlik içerik = klasik editoryal kalıp, kayık
   sayfa değil. Kuralın kendi notu da bunu söylüyor: hiza bir sayfayı hizalar, DOLDURMAZ. */
.state{display:grid;justify-items:center;text-align:center;gap:var(--space-4);
  padding-block:var(--space-16) 0}
@media (max-width:640px){.state{padding-block:var(--space-8) 0}}
/* Başlık `.page-head`in deyimiyle aynı: display ölçüsü, h1 harf aralığı, dar ekranda bir
   kademe iner. Yeni sayı uydurulmuyor — 404 bir karşılama ekranı, başlık sayfayı taşımalı. */
.state h1{font-size:var(--text-display);letter-spacing:var(--tr-h1)}
@media (max-width:640px){.state h1{font-size:var(--text-h1)}}
/* Çipler de ortalanır. `safe` ŞART: ray `overflow-x:auto` ve düz `center`, içerik taştığında
   başlangıcı kırpar — ilk çipe hiç erişilemez. `safe center` taşma anında `start`a düşer. */
.state-aisles .catbar .in{justify-content:safe center}
/* "Hata 404" — mikro etiket. Kullanıcının tanıdığı işaret ama sayfanın SÖYLEDİĞİ şey değil;
   asıl cümle h1. `.lbl`in dilini kullanır, kendi puntosunu icat etmez. */
.state-code{font-size:var(--text-micro);font-weight:var(--w-bold);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--text-2)}
.state-lead{font-size:var(--text-h3);line-height:var(--lh-snug);color:var(--text-2);
  max-width:34rem}
/* İstenen adres: cümle değil, veri. Sarılabilir çünkü kırık bağlantılar uzun olabiliyor ve
   `overflow-wrap` olmadan tek bir uzun yol sayfayı yatay kaydırtır. */
.state-path{font-size:var(--text-caption);color:var(--text-2);max-width:100%}
.state-path code{font-family:inherit;background:var(--quiet);border-radius:var(--radius-sm);
  padding:var(--space-1) var(--space-2);overflow-wrap:anywhere}
.state-aisles{display:grid;gap:var(--space-3);width:100%;min-width:0}
/* Ray kendi alt payını taşıyor (`.catbar{margin-bottom}`); burada boşluğu ızgara veriyor. */
.state-aisles .catbar{margin-bottom:0}

/* ÜRÜN RAYI — TEK SIRA, YATAY.

   [KARAR 2026-08-17 · Eyüp] 404'te öneriler `.grid` ile basılıyordu ve ızgara 4 sütun: 5 ürün
   → ikinci satırda TEK kart, yanında üç boş yuva. Ürün sayısını ayarlamak (8 → 4) çözüm DEĞİL,
   çünkü artık her kırılımda başka: 4 sütunda 1, 3 sütunda 2, 2 sütunda 1. Ray kusuru yapısal
   olarak kaldırıyor — sırada kaç kart olursa olsun "yetim satır" diye bir şey yok.
   Gerekçe ayrıca doğru: burası bir ürün listeleme sayfası değil, iki-üç satır ürün basmamalı.

   DEYİM YENİ DEĞİL: `.bnr-slot--rail` (kampanya şeridi) ve `.seg` aynı kalıbı kullanıyor —
   `grid-auto-flow:column` + `grid-auto-columns:minmax(...,1fr)` + `overflow-x:auto` + snap.
   O iki bileşenin öğrendiği iki dersi de taşıyor:

   (1) ODAK HALKASI KIRPILMAZ (`.seg` · 2026-08-14, Eyüp yakalamıştı). `overflow:auto` kabı,
       içindeki odaklanmış öğenin halkasını keser; karttaki "Sepete ekle" odaklanabilir. Pay
       halkanın ölçüsünde veriliyor (3 px halka + 2 px offset → ölçekten 8 px) ve DIŞARI negatif
       marjinle geri alınıyor: kutu nefes alıyor, yerleşimdeki ritim değişmiyor.
   (2) KAYDIRILABİLİRLİK GÖRÜNÜR OLMALI (`--bnr-min` notu): sonraki kartın kenarı görünmezse ray
       tek karttan ibaret sanılır (§H4). Taban `--card-min` — 1280'de ~5,2 kart, 390'da ~2,2 kart
       görünüyor, ikisinde de sonraki kart kenarı sırıtıyor.

   `1fr` AZ ÜRÜNDE DE DOĞRU: kart sayısı satırı doldurmuyorsa kartlar esneyip yeri paylaşır —
   ne yetim kalır ne sağda boşluk. `--card-min` zaten "akışkan yardımcıların tabanı" olarak
   tanımlı (katalog ızgarası onu kullanmaz), yani burada kendi işini yapıyor.

   PAY NEDEN ASİMETRİK: `.seg`in 8 px'i buraya yetmiyor çünkü ürün kartı çipten fazlasını
   taşıyor — `--elev-product-hi` gölgesi `0 16px 36px` (kutunun ~52 px altına, ~20 px üstüne
   uzanır) ve `:hover` kartı 4 px yukarı kaldırıyor. `overflow-x:auto` varken `overflow-y`
   görünür bırakılamaz (tarayıcı onu da `auto`ya çevirir), yani tek çare pay.
   [ÖLÇÜLDÜ 2026-08-17 · ekranda yakınlaştırılarak] İlk yazımda dikey pay 16 px'ti ve YETMİYORDU:
   kartların altında gölgenin DÜZ BİR ÇİZGİYLE kesildiği çıplak gözle görünüyordu. Gerekli pay
   gölgenin gerçek uzanımından hesaplanır, göz kararıyla değil:
     dinlenme  `0 10px 26px` → kutunun 36 px altına, 16 px üstüne
     hover     `0 16px 36px` → kutunun 52 px altına, 20 px üstüne · üstüne 4 px hover kalkması
   Yani alt 48, üst 24. Pay kadar negatif marjin verilmiyor, FARKI kadar veriliyor: pay gölgeye
   boya alanı açar, negatif marjin o alanın YERLEŞİMDEN çaldığı yeri geri verir. Net görsel
   boşluk ikisinde de 16 px — yani ritim ilk hâliyle aynı, değişen tek şey gölgenin nefes alması.
   YATAYDA negatif marjin 8 px'i GEÇEMEZ: dar ekranda sayfa kenar payı 16 px (`--grid-margin`),
   daha büyük bir negatif değer rayı viewport dışına taşırıp yatay kaydırma açardı (§R8: taşma 0). */
.rail{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(var(--card-min),1fr);
  gap:var(--grid-gutter);
  overflow-x:auto;overflow-y:hidden;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scrollbar-width:none;
  padding:var(--space-6) var(--space-2) var(--space-12);
  margin:calc(var(--space-2) * -1) calc(var(--space-2) * -1) calc(var(--space-8) * -1)}
.rail::-webkit-scrollbar{display:none}
.rail > *{scroll-snap-align:start}

/* BOŞ DURUM — KART DEĞİL.

   [DEĞİŞTİ 2026-08-16 · Eyüp: "empty state'deki card yapısı kötü"] Blok beyaz zeminli, gölgeli,
   yuvarlatılmış bir KARTTI. İki ayrı sebeple yanlıştı:

   (1) Kart bir ŞEYİ taşır. Boş durumun taşıyacağı şey yoktur — yokluğu ilan etmek için kutu
       çizmek, sayfaya var olmayan bir nesneyi işaret eden gerçek bir nesne koyar.
   (2) Hesap sayfalarında liste satırlarının kendisi de beyaz-gölgeli kart (`.rec`, `.orow`).
       Boş durum onlarla AYNI kabuğu giyince "listenin tek satırı" gibi okunuyordu; oysa
       söylediği şey listenin boş olduğu. Yani kabuk, mesajın tersini söylüyordu.

   Artık zeminsiz: sayfanın kendi zemininde duran sessiz bir blok. Ölçü `--field-w`den geliyor,
   yani satır okunabilir kalıyor ve blok sayfanın EKSENİNDE başlıyor (§R6.5) — `.solo`ya gerek
   kalmıyor.

   [GEÇERSİZ KALDI 2026-08-17] Burada bir de "`.empty` sola yaslı / `.empty.solo` ortalı" ayrımı
   yazılıydı. Aşağıdaki düzeltme `.empty`yi zaten ortaladığı için ayrım kalmadı: `.solo` artık
   bu bileşende hiçbir şey eklemiyor (ikisi de 520 + `margin-inline:auto`). Sekiz görünümde
   duran `.empty solo` yazımı zararsız ama gereksiz — temizliği `docs/TODO.md`'de. */
/* [DÜZELTME 2026-08-17 · Eyüp: "içerikleri ortalamamışsın, sol yaslı, sağları bomboş"]
   Kart kaldırıldı ama blok sola yaslı ve kısa bırakılmıştı: 1016 px'lik hesap sütununda 520 px
   kullanıyor, sağı boş kalıyor ve altında footer'a kadar uzanan bir boşluk duruyordu. Yani kutu
   gitti, kutunun bıraktığı delik kaldı.

   KÖK NEDEN, hizalama tercihi değil SINIFLANDIRMA hatasıydı: boş durum bir "içerik başlangıcı"
   gibi ele alınmıştı (sola yaslı, yukarıdan akan). Oysa söylediği şey "BU BÖLGE BOŞ" — yani bir
   bölge ifadesidir ve bölgesini sahiplenmelidir. Bu yüzden hem yatay hem dikey ortalanıyor ve
   `min-height` ile bölgeye gövde veriyor: boşluk artık sahipsiz değil, bloğun kendisi.

   §R6.5'İN İSTİSNASI VE GEREKÇESİ: o kural "bir sayfada tek sol kenar" diyor ve burada
   çiğneniyor (başlık solda, blok ortada). Kural SAYFA BLOKLARI için yazıldı; boş durum bir sayfa
   bloğu değil, bir bölgenin yer tutucusu. Bölge içinde ortalanmak eksen kayması üretmez çünkü
   blok bir komşuyla değil, KENDİ BÖLGESİYLE hizalanıyor. Kılavuzda da bu istisna yazılı. */
.empty{display:grid;gap:var(--space-3);justify-items:center;text-align:center;
  place-content:center;max-width:var(--field-w);margin-inline:auto;
  padding-block:var(--space-8)}
/* GÖVDE YALNIZ BÖLGE GERÇEKTEN BOŞSA.
   `min-height`i koşulsuz vermek, altında içeriği OLAN boş durumları da 352 px'e şişirirdi:
   sonuçsuz aramada ve boş sepette bloğun altında ürün rafı var (`.section` kardeşi) ve orada
   bölge boş değil — yalnız liste boş. O sayfalarda blok kısa kalmalı ki raf katlamanın üstünde
   dursun.
   `:has()` bu dosyada zaten kullanılıyor (bkz. `.topbar .in:not(:has(.searchbox--top))`). */
.empty:not(:has(~ .section)){min-height:22rem}
/* BÖLÜM İÇİNDE ORTALANMAZ — bölgenin ekseni neyse o.
   [KUSUR 2026-08-19 · ölçüldü] `.empty` "bölgesini sahiplenir, bölgesinde ortalanır" kuralıyla
   yazılmıştı. `.page-sec` ise SOLDA BAŞLIK / SAĞDA İÇERİK düzeni: orada bölgenin ekseni sol
   kenardır, ortası değil. Sonuç /davet'te görüldü — "Davet ettiklerin" başlığı L=116'da, boş
   durum L=694'te ortalanmış, altında 352 px delik: blok kendi başlığından kopmuş duruyordu.
   O bölümde diğer her çocuk (paragraf, ızgara) sütunun sol kenarından başlıyor; boş durum da
   öyle başlar. Gövde de gerekmiyor: burada boş olan SAYFA değil, bölümün listesi. */
.page-sec .empty{margin-inline:0;justify-items:start;text-align:left;min-height:0}
/* İkon `.rec-lead` DEĞİL. O, liste satırının 44 px'lik renkli kurşunu — boş durumu tam da
   "bir satır" gibi gösteren şeydi. Burada tek başına duruyor: susturulmuş renk, bir kademe
   büyük ikon. Dikkat çekmesi değil, bloğun ne hakkında olduğunu bir bakışta söylemesi isteniyor. */
.empty-ico{color:var(--text-2)}
.empty-ico svg{width:var(--icon-xl);height:var(--icon-xl)}
/* Açıklama GÖVDE ölçüsünde, `.fine` (caption) değil: boş durum bir dipnot değil, sayfanın o
   andaki TEK içeriği. Caption puntosu onu "önemsiz not" diye okutuyordu.
   `font-size` AÇIKÇA yazılıyor: on altı boş durumun bir kısmı paragrafına `.fine` veriyor ve o
   sınıf punto taşıyor. Seçici daha güçlü (0,1,1 > 0,1,0), yani ölçü işaretlemeden bağımsız
   tutarlı kalıyor — hangi sayfada `.fine` yazıldığını hatırlamak gerekmiyor. Sınıf, dokunulan
   görünümlerde ayrıca temizleniyor. */
.empty p{font-size:var(--text-body);color:var(--text-2);line-height:var(--lh-body)}
.empty .btn{margin-top:var(--space-2)}
.crumb{font-size:var(--text-caption);color:var(--text-2);padding-block:var(--space-4);
  display:flex;gap:var(--space-2);flex-wrap:wrap}
.crumb a{text-decoration:none;color:var(--text-2);position:relative}
/* [KUSUR 2026-08-12 · ölçüldü] Kırıntı yolu linkleri 21 px yüksekliğindeydi — kılavuzun 24 px
   tabanının altında. Yazının KENDİSİ bilerek küçük (kırıntı yolu bir konum işaretidir, bir çağrı
   değil); büyüyen tıklama ALANI. `.term-btn` · `.btn--sm` ile aynı deyim.

   Genişletme YALNIZ DİKEY (`-12px 0`): linkler yatayda 8 px aralıkla yan yana duruyor, yatay
   genişletme komşularla çakışırdı — çakışan hedef, küçük hedeften kötüdür çünkü kullanıcı
   bastığını sandığı linki değil komşusunu açar. Dikeyde komşu yok, 21+24 = 45 px. */
.crumb a::before{content:"";position:absolute;inset:-12px 0}
.crumb a:hover{color:var(--primary)}

/* ---------- hesap sayfası ---------- */
.acct-layout{display:grid;grid-template-columns:var(--acct-rail) minmax(0,1fr);
  gap:var(--space-6);align-items:start;padding-bottom:var(--space-16)}
@media (max-width:1024px){.acct-layout{grid-template-columns:1fr}}
/* Hesap içeriği sütunu. .acct-layout ızgarayı kuruyor; ikinci hücrenin kendi akışı olmalı,
   yoksa iç bölümler arasındaki boşluk sayfadan sayfaya değişiyor. */
.acct-main{display:grid;gap:var(--space-6);align-content:start;min-width:0}
/* FORM SAYFASI YERLEŞİMİ (Bilgilerim).

   [KUSUR 2026-08-21 · Eyüp: "inputlar neden yarım"] Hesap sütunu 1016 px, panel içeriği 968 px,
   girdi 520 px: panelin %46'sı ölü boşluktu. Aynı his ödeme adımında bir kez ölçülmüştü
   (`.rw--cardrow`) ama kural panel ölçeğine taşınmamıştı.

   Girdiyi panele kadar germek çözüm değil — 968 px'lik bir "Ad" kutusu içeriğiyle orantısız kalır
   (§B4) ve tek kolon kuralı (§F) da bozulmaz. Sol sütun formun ölçüsünde KAPANIYOR, artan yer
   ikincil panellere gidiyor.

   1280 altında tek sütun: sütun tavanı `--form-col` olarak KALIR, yoksa yarım girdi dar ekranda
   geri gelirdi. */
.acct-split{display:grid;gap:var(--space-6);align-items:start;
  grid-template-columns:minmax(0,var(--form-col))}
.acct-col,.acct-form{display:grid;gap:var(--space-6);align-content:start;min-width:0}
/* İkinci sütun ölçekteki 1280 kırılımında açılıyor (ölçüldü: orada hesap sütunu 952 px, yani
   568 + 24 + 360 — yan sütun hâlâ diyalog ailesinin genişliğinde). Altında TEK sütun: 1025–1240
   arasında yan sütun 300 px'in altına inerdi ve 1024'te ray yukarı çıkıp sütun yeniden genişlediği
   için düzen pencere daralırken iki kez şekil değiştirirdi (B10.5'teki monotonluk kuralı). */
@media (min-width:1280px){
  .acct-split{grid-template-columns:minmax(0,var(--form-col)) minmax(0,1fr)}
}
/* İkincil paneli OLMAYAN form sayfası (Hoş geldin, adres formu, kimlik doğrulama): ikinci sütuna
   koyacak bir şey yok, gereken yalnız tavan — sütun değil. Uyarı satırları da bu kabın içinde,
   böylece sayfa tek sağ kenarda kapanır. */
.acct-form{max-width:var(--form-col)}
.acct-nav{display:grid;gap:var(--space-1);background:var(--surface);border-radius:var(--radius-xl);
  box-shadow:var(--elev-card);padding:var(--space-2);position:sticky;
  top:calc(var(--tap-min) + var(--space-8))}
@media (max-width:1024px){.acct-nav{position:static;grid-auto-flow:column;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none}.acct-nav::-webkit-scrollbar{display:none}}
.acct-nav a{display:flex;align-items:center;gap:var(--space-3);text-decoration:none;
  font-size:var(--text-label);font-weight:var(--w-semibold);color:var(--text);
  padding:var(--space-3);border-radius:var(--radius-md);min-height:var(--control-h);
  line-height:var(--lh-snug);transition:background var(--dur-micro) var(--ease-out)}
.acct-nav a svg{flex:none}
@media (min-width:1025px){.acct-nav a{white-space:normal}}  /* ölçek: 1024'ün üstü */
@media (max-width:1024px){.acct-nav a{white-space:nowrap}}   /* yatay rayda sarmasın */
.acct-nav a:hover{background:var(--quiet)}
.acct-nav a[aria-current="page"]{background:var(--primary-soft);color:var(--primary-pressed);
  font-weight:var(--w-bold)}
.acct-nav svg{color:var(--text-2)}
.acct-nav a[aria-current="page"] svg{color:var(--primary)}
/* kayıt kartı — adres / kart / sipariş satırı */
.rec{background:var(--surface);border-radius:var(--radius-xl);box-shadow:var(--elev-card);
  padding:var(--space-4) var(--space-6);display:flex;gap:var(--space-4);align-items:flex-start;
  flex-wrap:wrap}
.rec-main{flex:1;min-width:calc(var(--card-min) - var(--space-4));display:grid;gap:var(--space-1)}
.rec-title{display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;
  font-weight:var(--w-bold)}
.rec-acts{display:flex;gap:var(--space-2);flex-wrap:wrap;align-items:center}
.rec-lead{display:grid;place-items:center;width:var(--tap-min);height:var(--tap-min);flex:none;
  border-radius:var(--radius-lg);background:var(--primary-soft);color:var(--primary)}
.rec-lead svg{width:var(--icon-lg);height:var(--icon-lg)}
/* sipariş geçmişi satırı */
.orow{display:grid;grid-template-columns:1fr auto;gap:var(--space-4) var(--space-6);
  align-items:center;background:var(--surface);border-radius:var(--radius-xl);
  box-shadow:var(--elev-card);padding:var(--space-4) var(--space-6)}
@media (max-width:640px){.orow{grid-template-columns:1fr}}
.orow .meta{display:flex;gap:var(--space-3);flex-wrap:wrap;align-items:center;
  font-size:var(--text-caption);color:var(--text-2)}
.othumbs{display:flex;gap:var(--space-1);margin-top:var(--space-2)}
/* KIRPMA YASAĞI (2026-08-12 · Eyüp) — ürün/banner görseli kesilmez; bkz. `.pcard .art img`. */
.othumbs img{width:var(--icon-xl);height:var(--icon-xl);border-radius:var(--radius-md);
  object-fit:contain;background:var(--primary-soft)}
.othumbs .more{width:var(--icon-xl);height:var(--icon-xl);border-radius:var(--radius-md);
  background:var(--quiet);color:var(--text-2);display:grid;place-items:center;
  font-size:var(--text-caption);font-weight:var(--w-semibold)}

/* ---------- yasal metin okuma tipografisi ----------
   Uzun metin ürün arayüzü gibi dizilmez: satır uzunluğu 60–75 karakterde tutulur (§B4),
   satır yüksekliği gövde ölçüsüne çıkar, başlıklar arası ritim belirginleşir. */
/* Yasal sayfa: başlık bloğu ile metin arasında nefes payı. Ölçümde 0 px'di — sürüm satırı
   sözleşmenin ilk başlığına yapışıyordu ve ikisi tek blok gibi okunuyordu. */
/* ---------- ürün sayfası üst bloğu ----------
   Sayfanın kimlik bloğu ÖNCE miktar penceresinin başlığından (.sheet-top) ödünç alınmıştı; orada
   görsel 88 px'e sabit çünkü pencerede fotoğraf bir teyittir, kullanıcı ürünü zaten seçmiştir.
   Sayfada işi farklı: §J19'a göre sayfanın görevi "ikna değil güven ve keşif" ve tazeliğe
   88 px'lik bir görselden karar verilemez. Bu yüzden kendi bileşeni var.

   Oran ürün kartıyla AYNI (1/.82): ızgarada gördüğün kırpma sayfada da aynı, ürün iki yerde
   farklı görünmüyor. .prod-media SARMALAYICI — oranı o tutar, görseli `.prod-media img` kaplar. */
/* [KUSUR 2026-08-14 · ölçüldü] Bilgi sütunu `1fr` idi: 1280 px'e yayılıyor ama içerik 628 px'te
   bitiyordu — sütunun %51'i ölü. Satın alma kararının verildiği sayfada ekranın yarısı boştu.
   Sütun İÇERİĞİ KADAR yer alıyor (`max-content` tavanı okuma ölçüsüyle sınırlı) ve ızgara sola
   yaslanıyor; artan yer görselle bilgi arasındaki boşluğa değil, sayfanın kenarına gidiyor. */
.prod-hero{display:grid;gap:var(--space-12);align-items:start;justify-content:start;
  grid-template-columns:minmax(0,var(--prod-media)) minmax(0,34rem)}
/* Kart ile AYNI oran (kare = kaynak görselin oranı): ızgarada gördüğün kadraj sayfada da o.
   İkisi ayrışsaydı aynı ürün iki yüzeyde farklı kırpılırdı. */
.prod-media{display:block;aspect-ratio:1/1;border-radius:var(--radius-2xl);overflow:hidden;
  background:var(--primary-soft);box-shadow:var(--elev-card)}
/* KIRPMA YASAĞI (2026-08-12 · Eyüp) — ürün/banner görseli kesilmez; bkz. `.pcard .art img`. */
.prod-media img{width:100%;height:100%;object-fit:contain;display:block}
/* Dar ekranda fotoğraf üstte tam genişlik; iki sütun sıkışınca ikisi de okunmaz oluyor. */
@media (max-width:1024px){
  .prod-hero{grid-template-columns:1fr}
}

/* ---------- İÇERİK SAYFASI İSKELETİ (Hakkımızda · İletişim · Davet) ----------

   [YENİDEN 2026-08-14 · Eyüp: "bu tasarımı nasıl okey verdin"] İlk denememde okuma ölçüsünü
   (34rem) uyguladım ama KOMPOZİSYONU kurmadım ve sonuç daha kötü oldu: metin blokları 544 px'te
   sola çakılı dururken altlarındaki kart ızgarası 1700 px'e yayılıyordu. Aynı sayfada iki farklı
   genişlik — ekranın sağ yarısı "çizilmemiş" gibi duruyordu.

   Ders şu: geniş ekranda okuma ölçüsünü korumanın yolu metni daraltıp ORTADA BIRAKMAK değil,
   sayfaya BANT ve SÜTUN vermek. İki araç kullanılıyor, ikisi de mevcut token'larla:

     1) `.page-head` bir BANT: kabın tamamını kaplayan marka-yumuşağı yüzey. Metin içinde okuma
        ölçüsünde kalıyor ama boşluk artık "eksik içerik" değil, bandın nefesi.
     2) `.page-sec` İKİ SÜTUN: solda başlık, sağda içerik. Editoryal sayfaların klasik kalıbı —
        başlık kenarda bir işaret gibi durur, içerik kendi ölçüsünde akar ve tuval boş kalmaz.

   Dar ekranda ikisi de tek sütuna iner: orada zaten genişlik sorunu yok. */
.page{display:grid;gap:var(--space-16);padding-block:var(--space-6) var(--space-24)}
/* TEK RİTİM KAYNAĞI: `.page`in `gap`i.

   [KUSUR 2026-08-19 · Eyüp: "hâlâ ciddi boşluklar var" · ölçüldü] `.page` çocuklarını 64 px ile
   ayırıyor, `.section` ise ayrıca 48 px üst pay taşıyor. İkisi aynı sayfada buluşunca her bölüm
   sınırı 112 px'e, manşetten sonrası 160 px'e çıkıyordu — sayfa "içeriği az" değil, ARALARI
   fazla açık olduğu için seyrek görünüyordu.
   Kural YALNIZ bu birlikteliği hedefliyor: `.section`ın kendi payı katalog/liste sayfalarında
   (orada `.page` yok) aynen duruyor. Tarandı — `.page` içinde `.section` kullanan tek görünüm
   kampanya detayı. */
.page > .section{padding-block:0}
/* Alt payı `main.wrap` zaten veriyor (64 px); ikisi birlikte son bloğu altbilgiden 160 px
   uzağa itiyordu. */
.page--campaign{padding-bottom:0}
@media (max-width:640px){.page{gap:var(--space-12);padding-block:var(--space-4) var(--space-16)}}

/* BAŞLIK BANDI — sayfanın girişi. TEK BANT, İKİ DOLGU.
   Geniş ekranda İKİ SÜTUN: solda iddia, sağda ikinci sütun. Tek sütunda başlık ve açıklama bandın
   sol yarısına yığılıyor, sağ yarısı boş kalıyordu — bant genişledikçe boşluk da büyüyordu.
   İki sütun hem bandı dolduruyor hem okuma ölçüsünü koruyor: metin kendi sütununda 34rem'i
   geçmiyor. Alt hizalama (`align-items:end`) taban çizgilerini yakınlaştırıyor.

   [BİRLEŞTİ 2026-08-21] Burada `.hero2` diye İKİNCİ bir bant vardı ve yalnız /hakkimizda
   kullanıyordu. İkisi aynı banttı: aynı `--primary-soft` zemin, aynı `--radius-2xl`, aynı
   1,1fr/1fr ızgara, aynı display başlık. Fark yalnız İKİNCİ SÜTUNUN DOLGUSUYDU — birinde
   açıklama metni, öbüründe fotoğraf. Aynı şeyin iki adı, bir gün ikisinin ayrışması demekti:
   nitekim ayrışmışlardı bile (bantın `p` rengi `--primary-pressed`, hero2'ninki `--text`).
   Şimdi tek kural + `--art` değiştiricisi; ölçü ve renk tek yerden geliyor. */
.page-head{background:var(--primary-soft);border-radius:var(--radius-2xl);
  padding:var(--space-16) var(--space-12);display:grid;gap:var(--space-4)}
@media (min-width:1025px){
  .page-head{grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);
    gap:var(--space-12);align-items:end}
}
/* Başlık ve açıklama doğrudan bandın çocuğu OLABİLİR (iki sütun = h1 + p) ya da `--art`ta olduğu
   gibi tek sütuna toplanabilir. Seçici ikisini de kapsıyor; punto tek yerde tanımlı. */
.page-head h1,.page-head-tx h1{font-size:var(--text-display);font-weight:var(--w-black);
  letter-spacing:var(--tr-h1);line-height:var(--lh-tight)}
/* Açıklama GÖVDEDEN BÜYÜK: sayfanın vaadini o taşıyor. Eskiden 13 px'ti — yani sayfanın en
   önemli cümlesi, en küçük puntosuydu. */
.page-head p,.page-head-tx p{font-size:var(--text-h3);line-height:var(--lh-snug);
  color:var(--primary-pressed);max-width:34rem}
@media (max-width:640px){
  .page-head{padding:var(--space-8) var(--space-6);border-radius:var(--radius-xl)}
  .page-head h1,.page-head-tx h1{font-size:var(--text-h1);max-width:none}
  .page-head p,.page-head-tx p{font-size:var(--text-body)}
}

/* AÇILIŞ DOLGUSU — solda söz, sağda ürün fotoğrafı.
   [2026-08-14] Bu sayfaların asıl eksiği yerleşim değil MALZEMEYDİ: ölçüldü, `/iletisim`de
   sıfır görsel vardı. Manav markasının tazelik iddiası tipografiyle değil ürünle anlatılır.
   Fotoğraf metinle aynı hizada değil ORTASINDA duruyor (`center`): kutunun boyu metnin değil
   oranın kararı, alta yaslamak bandın üstünde boşluk bırakıyordu. */
.page-head--art{align-items:center;gap:var(--space-8);
  padding:var(--space-12);overflow:hidden}
@media (min-width:1025px){.page-head--art{gap:var(--space-12);align-items:center}}
/* Metin sütunu: başlık + açıklama + düğmeler tek yığında. `justify-items:start` düğmelerin
   sütunu germesini engelliyor. */
.page-head-tx{display:grid;gap:var(--space-6);justify-items:start}
.page-head-art{width:100%;height:auto;display:block;border-radius:var(--radius-xl);
  aspect-ratio:4 / 3;object-fit:cover;box-shadow:var(--elev-product)}
@media (max-width:1024px){.page-head-art{aspect-ratio:2 / 1}}
@media (max-width:640px){
  .page-head--art{padding:var(--space-6);border-radius:var(--radius-xl);gap:var(--space-6)}
}

/* DAVET KODU PANELİ — tek fikir, tek kap.
   [2026-08-14] Önceki hâlde aynı iş üç ayrı kapta anlatılıyordu: dolu yeşil düğme, yeşil kod
   çipi, gri monospace URL kutusu. Üç geometri, üç renk mantığı, biri başka yazı ailesi — göz
   hangisinin asıl olduğunu bulamıyordu. Hepsi tek panelde toplandı ve KOD sayfanın en büyük
   öğesi oldu: paylaşılacak şey odur. */
.ref-hero{background:var(--primary-soft);border-radius:var(--radius-2xl);padding:var(--space-12)}
@media (max-width:640px){.ref-hero{padding:var(--space-6);border-radius:var(--radius-xl)}}
.ref-hero-tx{display:grid;gap:var(--space-4);justify-items:start}
.ref-hero-lbl{font-size:var(--text-label);font-weight:var(--w-bold);color:var(--primary-pressed);
  letter-spacing:var(--tr-label);text-transform:uppercase}
/* Kod: sayfanın en büyük öğesi. Harf aralığı açık — kod OKUNUR ve SÖYLENİR bir şeydir,
   telefonda karşıya tarif edilir; sıkışık harfler 0/O ve 1/I ayrımını zorlaştırır. */
.ref-hero-code{font-size:var(--text-display);font-weight:var(--w-black);color:var(--text);
  letter-spacing:.06em;line-height:var(--lh-none);word-break:break-all}
@media (max-width:640px){.ref-hero-code{font-size:var(--text-h1)}}
/* Link satırı: kopyalanabilir ama sessiz. Monospace BURADA doğru — adres karakter karakter
   okunur; ama kendi kutusu yok, panelin içinde bir satır. */
.ref-hero-link{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;
  padding-top:var(--space-2)}
.ref-hero-link code{font-size:var(--text-caption);color:var(--text-2);word-break:break-all}

/* KANAL KARTLARI (iletişim). Kartın tamamı hedef; değer büyük ve okunur, açıklama sönük. */
.chan{display:grid;gap:var(--space-4);
  grid-template-columns:repeat(auto-fit,minmax(var(--camp-min),1fr))}
.chan-i{display:grid;gap:var(--space-2);align-content:start;text-decoration:none;color:var(--text);
  background:var(--surface);border-radius:var(--radius-xl);padding:var(--space-6);
  box-shadow:var(--elev-card);
  transition:transform var(--dur-micro) var(--ease-out),box-shadow var(--dur-micro) var(--ease-out)}
a.chan-i:hover{transform:translateY(calc(var(--space-1) * -1));box-shadow:var(--elev-product)}
/* Tıklanamayan kart hover ALMAZ: hareket, tıklanabilirlik vaadidir. */
.chan-i--flat{cursor:default}
.chan-i svg{width:var(--icon-lg);height:var(--icon-lg);color:var(--primary)}
.chan-i b{font-size:var(--text-label);font-weight:var(--w-bold);color:var(--text-2);
  letter-spacing:var(--tr-label);text-transform:uppercase}
.chan-v{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3);
  color:var(--primary-pressed);word-break:break-word}
.chan-h{color:var(--text-2);line-height:var(--lh-snug)}

/* KÜNYE — etiket/değer hizalı. Düz liste ("Telefon: 0850…") gözü her satırda yeniden
   hizalamaya zorluyordu; sabit etiket sütunu bunu bitiriyor. */
.idcard{margin:0;background:var(--surface);border-radius:var(--radius-xl);
  box-shadow:var(--elev-card);overflow:hidden}
.idcard > div{display:grid;grid-template-columns:minmax(0,var(--camp-term-lbl)) minmax(0,1fr);
  gap:var(--space-4);padding:var(--space-4) var(--space-6);
  border-bottom:var(--border-hairline) solid var(--divider)}
.idcard > div:last-child{border-bottom:0}
.idcard dt{color:var(--text-2);font-size:var(--text-label)}
.idcard dt small{font-size:var(--text-micro);display:block}
.idcard dd{margin:0;font-weight:var(--w-semibold);word-break:break-word}
@media (max-width:640px){
  .idcard > div{grid-template-columns:1fr;gap:var(--space-1)}
}
.idcard-note{margin-top:var(--space-4);max-width:44rem}

/* BÖLÜM — solda başlık, sağda içerik. Başlık sütunu sabit; içerik kalan yeri alır. */
.page-sec{display:grid;grid-template-columns:var(--acct-rail) minmax(0,1fr);
  gap:var(--space-8);align-items:start}
.page-sec > h2{font-size:var(--text-h2);font-weight:var(--w-black);letter-spacing:var(--tr-h2);
  line-height:var(--lh-tight)}
.page-sec > p,.page-sec > .lead{max-width:34rem;line-height:var(--lh-body)}
/* Giriş paragrafı bir kademe büyük: bölümün özeti, ayrıntısı değil. */
.page-sec > .lead{font-size:var(--text-h3);line-height:var(--lh-snug);color:var(--text)}
@media (max-width:1024px){
  .page-sec{grid-template-columns:1fr;gap:var(--space-4)}
}
/* [KALDIRILDI 2026-08-19] Burada `.page-sec--note` vardı: kampanya dipnotunu bölümlerin içerik
   sütununa hizalamak için boş bir `::before` başlık hücresi basıyordu. Kampanya sayfası tam
   genişlik bölümlere geçince dipnot da sayfanın eksenine alındı ve değişken tek kullanıcısını
   kaybetti. Ölçüyü artık `.camp-foot` kendi taşıyor. */
/* [DEĞİŞTİ 2026-08-19 · dış inceleme] Metin `.fine` (13 px) idi; "ikincil bilgi olması
   okunamayacak kadar küçük olması demek değil". Punto bir kademe yükseldi, satır aralığı gövde
   ritmine alındı. Rengi ikincil kalıyor — hiyerarşideki yeri değil okunabilirliği değişti. */
.camp-foot{max-width:34rem;font-size:var(--text-label);line-height:var(--lh-body)}

/* ÖZELLİK IZGARASI — madde listesinin yerine.
   Altı özellik alt alta madde işaretiyle dizilince tek bir metin bloğuna eziliyordu; oysa
   bunlar birbirinden bağımsız altı vaat. Izgara onları taranabilir kılıyor. */
.feat{display:grid;gap:var(--space-4);
  grid-template-columns:repeat(auto-fit,minmax(var(--card-min),1fr))}
.feat-i{display:grid;gap:var(--space-2);align-content:start;
  background:var(--surface);border-radius:var(--radius-xl);padding:var(--space-6);
  box-shadow:var(--elev-card)}
.feat-i svg{width:var(--icon-lg);height:var(--icon-lg);color:var(--primary)}
.feat-i b{font-size:var(--text-body);font-weight:var(--w-bold)}
.feat-i span{color:var(--text-2);line-height:var(--lh-snug)}

/* SÜREÇ — yatay adımlar. Numara görsel çapa; alt alta üç madde süreci "uzun" gösteriyordu. */
.steps{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-6);
  grid-template-columns:repeat(auto-fit,minmax(var(--card-min),1fr))}
/* ADIMLAR BİR AKIŞ, ÜÇ BAĞIMSIZ BLOK DEĞİL.
   [KUSUR 2026-08-19 · dış inceleme] Her adımın kendi üst çizgisi vardı ve çizgiler birbirine
   değmiyordu: ekranda "üç kolonlu ızgara" gibi duruyordu, süreç gibi değil. Çizgi artık rozetin
   ORTA HİZASINDAN geçip komşuya uzanıyor; son adımda kesiliyor (bir yere bağlanmayan çizgi,
   olmayan bir dördüncü adımı vaat eder). Dar ekranda adımlar alt alta indiği için çizgi de
   kalkıyor — dikeyde yatay bağ anlamsız.
   Rozet bir kademe büyüdü: inceleme "sayılar ince ve küçük kalıyor" diyordu. */
.steps li{display:grid;gap:var(--space-3);align-content:start;position:relative;
  padding-top:var(--space-4)}
.steps li::before{content:"";position:absolute;left:var(--icon-xl);right:0;
  top:calc(var(--space-4) + var(--icon-xl) / 2);height:var(--border-emphasis);
  background:var(--primary-soft)}
.steps li:last-child::before{display:none}
@media (max-width:640px){.steps li::before{display:none}}
.steps-n{display:grid;place-items:center;width:var(--icon-xl);height:var(--icon-xl);
  border-radius:var(--radius-pill);background:var(--primary-soft);color:var(--primary-pressed);
  font-weight:var(--w-black);font-size:var(--text-h3);position:relative;z-index:1}
.steps li b{font-size:var(--text-body);font-weight:var(--w-bold)}
.steps li span:last-child{color:var(--text-2);line-height:var(--lh-snug)}

/* KAPANIŞ — sayfa okuyanı boşluğa bırakmaz. */
.page-cta{display:flex;align-items:center;justify-content:space-between;gap:var(--space-6);
  flex-wrap:wrap;background:var(--quiet);border-radius:var(--radius-2xl);padding:var(--space-8)}
.page-cta > div:first-child{display:grid;gap:var(--space-1);max-width:34rem}
.page-cta b{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3)}
.page-cta span{color:var(--text-2)}

/* OKUMA ÖLÇÜSÜ PANELDE DEĞİL SATIRDA.

   EKSEN KURALI (bu dosyada zaten yazılıydı, 2026-08-16'dan beri uygulanıyor da): "farklı
   genişlikte kutular ortalanınca sol kenarları ayrışır ve sayfa kayık görünür" — bir sayfadaki
   her blok TEK eksende başlar. Yasal belge düzeninin ortalanması (bkz. `.legal-layout`ın
   silindiği yer) tam olarak bu kuralı çiğniyordu.

   [DEĞİŞTİ 2026-08-16] Tavan buradaydı ve `.legal-body` PANELİN KENDİ sınıfı
   (`<article class="panel legal-body">`), yani 34rem metni değil PANELİ daraltıyordu. Düzen
   sayfanın standart sütununa (1016) alınınca bu kural satırı da 1016'ya çıkarırdı. Tavan
   çocuklara taşındı: panel sütunu doldurur, paragraf okuma ölçüsünde kalır.

   TABLO MUAF: çerez politikasında sütunlu bir tablo var; 544 px'e sıkıştırılırsa hücreler
   okunmaz olur. Masaüstünde tablo 968 px çiziliyor ve 1016'lık panele sığıyor.
   [AÇIK KUSUR · benim DEĞİL, ölçüldü 2026-08-16] ≤390 px'te bu sayfa yatay taşıyor: tablonun
   min-content genişliği 446, panel 494, belge 510 > 390. Muafiyet KALDIRILSA DA taşma sürüyor —
   `max-width` bir tabloyu min-content'in altına indirmez. Eski kurallar iframe'de geri konup
   ölçüldü: rakamlar birebir aynı (panel 494, scrollW 510), yani kusur bu turdan önce de vardı.
   `Legal/Document.cshtml`teki not bunun `.acct-main{min-width:0}` ile çözüldüğünü söylüyor;
   o düzeltme IZGARA HÜCRESİNİ kurtarmış, tablonun paneli aşmasını değil. Çözümü ayrı bir iş
   (tablo kendi kabında kaydırmalı) — `docs/TODO.md` · Web · açık borç.

   [SİLİNDİ 2026-08-16] Burada bir yorum bloğu daha vardı: "METİN SAYFASI — SÜTUN ORTALANIR
   (Hakkımızda · İletişim)". Arkasında KURAL YOKTU — dosyadaki bütün `margin-inline:auto`
   bildirimleri tarandı, o iki sayfayı ortalayan hiçbir şey yok; ölçüm de sola hizalı çıkıyor
   (`.page-sec` L=116, W=1280). Bir refactor'dan sağ kalmış, anlattığı davranışı olmayan yorum;
   sonraki okuru yanıltmaktan başka iş görmüyordu.

   Ölçü REM cinsinden, `ch` değil (§B4.1: "~33rem, asla 40rem'i geçmez").
   [KUSUR 2026-08-10 · denetim J7] `68ch` Manrope'ta 616 px ölçüldü — tavanın altında ama hedefin
   çok üstünde. `ch` birimi "0" rakamının genişliği; yazı tipi değişince ölçü sessizce kayar ve
   kuralla aynı dili konuşmaz. Kural rem yazıyorsa CSS de rem yazar. */
/* [KALDIRILDI 2026-08-18] Burada `.legal-body > *{max-width:34rem}` (ve tabloyu muaf tutan
   kardeşi) vardı. Satırı 544 px'de kesiyordu ama panel 1016 px olduğu için beyaz sayfanın içinde
   424 px ölü alan bırakıyordu — Eyüp'ün "legal-body'yi kaldırınca düzeliyor" dediği şey buydu.
   Ölçü artık panelin GENİŞLİĞİNDEN geliyor (`.legal-layout` · 640 px panel → 592 px satır), yani
   metin kutusunu dolduruyor ve tavan yine §B4 içinde kalıyor. Çocuklara ayrı tavan gerekmiyor;
   tablo muafiyeti de kendiliğinden gereksizleşti. */
/* `min-width:0` ŞART — ve gerekçesi `.acct-main`inkiyle AYNI, yalnız bir kat aşağıda.
   [KUSUR 2026-08-18 · ölçüldü] Panel bir IZGARA ÖĞESİ (`.acct-main{display:grid}`), dolayısıyla
   `min-width:auto` taşıyor: içindeki çerez tablosunun min-content'i (446 px) paneli 494 px'e
   zorluyor ve panel 358 px'lik sütunu aşıyordu — 390 px'te sayfa yana kayıyordu (§R8: taşma 0).
   Dar ekran için yazılmış `table{display:block;overflow-x:auto}` kuralı bu yüzden hiç
   çalışamıyordu: tablo kaydırılacağına kabını itiyordu. Ders `Document.cshtml`de zaten yazılıydı
   ama bir kat yukarıya (`.acct-main`) uygulanmıştı; ızgara öğesi olan HER kap onu istiyor. */
.legal-body{min-width:0;line-height:var(--lh-body);color:var(--text)}
/* BAŞLIK MERDİVENİ: 31 → 25 → 20 → 16.
   [KUSUR 2026-08-14 · ölçüldü] h2 20 px, h3 ise 16 px — yani madde başlığı GÖVDE METNİYLE
   BİREBİR AYNI boydaydı; ayrım yalnız kalınlıktı. Sözleşme gibi uzun bir belgede bu, "sıkışık"
   hissinin doğrudan sebebi: göz tarayarak madde bulamıyor, her şey aynı düzlemde akıyor.
   Bir kademe yukarı alındılar; sayfa başlığıyla (31) birlikte dört basamaklı gerçek bir
   merdiven oluyor ve ölçek dışına çıkılmıyor. */
.legal-body h2{font-size:var(--text-h2);font-weight:var(--w-black);letter-spacing:var(--tr-h2);
  margin-top:var(--space-8);margin-bottom:var(--space-3)}
.legal-body h3{font-size:var(--text-h3);font-weight:var(--w-black);letter-spacing:var(--tr-h3);
  margin-top:var(--space-6);margin-bottom:var(--space-2)}
.legal-body h2:first-child,.legal-body h3:first-child{margin-top:0}
/* [KUSUR 2026-08-18 · ölçüldü] Üstteki kural ilk çocuğun payını sıfırlıyordu ama SONUNCUNUNKİ
   duruyordu: panelin üstünde 24 px (yalnız iç pay), altında 40 px (iç pay + son bloğun
   `margin-bottom`u) vardı. Kutunun altı üstünden 16 px açık duruyordu ve içerik DB'den geldiği
   için son öğenin ne olacağı (p/ul/table) belli değil — hepsini kapsayan tek kural. */
.legal-body > *:last-child{margin-bottom:0}
.legal-body p{margin-bottom:var(--space-4)}
.legal-body ul,.legal-body ol{margin-bottom:var(--space-4);padding-left:var(--space-6);
  display:grid;gap:var(--space-2)}
.legal-body li{line-height:var(--lh-body)}
.legal-body b,.legal-body strong{font-weight:var(--w-bold)}
.legal-body .alert{margin-top:var(--space-6)}
/* Dar ekranda 4 sütunlu çerez tablosu 390 px'e sığmıyor ve SAYFAYI yana kaydırıyordu (ölçüm:
   120 px). İçerik DB'den geldiği için işaretlemeye kaydırma kabı ekleyemeyiz; tablo kendi
   kabında kayar. Masaüstünde table-layout bozulmasın diye bilinçli olarak media query içinde. */
@media (max-width:640px){
  .legal-body table{display:block;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}
}
.legal-body table{width:100%;border-collapse:collapse;margin-bottom:var(--space-4);
  font-size:var(--text-label)}
.legal-body th,.legal-body td{text-align:left;padding:var(--space-2) var(--space-3);
  border-bottom:var(--border-hairline) solid var(--divider);vertical-align:top}
.legal-body th{font-weight:var(--w-semibold);color:var(--text-2)}
/* sipariş anında dolacak alan — boş bırakmak yerine ne geleceğini söyler */
.tok{display:inline-block;background:var(--quiet);color:var(--text-2);
  border:var(--border-hairline) dashed var(--control-border);border-radius:var(--radius-sm);
  padding:0 var(--space-2);font-size:var(--text-caption);font-weight:var(--w-semibold);
  white-space:nowrap}

/* görsel yüklenemezse — ürün adı zaten kartın gövdesinde, burada tekrar edilmez */
.pcard .art.noimg::after{content:"";position:absolute;inset:0;z-index:2;
  background:radial-gradient(circle at 50% 45%,var(--pine-100),var(--primary-soft))}

/* küçük görseller (sepet satırı, sipariş kalemi) aynı davranışı alır */
/* [KUSUR 2026-08-13] Üçlü kural EKSİKTİ: gizleme adımı (`[data-fade]{opacity:1→0}`) hiç
   yazılmamış, yalnız açma adımı vardı. Yani bayrak yazılsa bile küçük görsel hiç gizlenmiyordu.
   Sıra da anlamlı: önce görünürlük ŞARTI (betik yoksa görsel var), sonra opt-in gizleme. */
img.thumb{transition:opacity var(--dur-enter) var(--ease-out);background:var(--skeleton)}
img.thumb{opacity:1}
img.thumb[data-fade]{opacity:0}
img.thumb[data-fade][data-ready]{opacity:1}

/* ---------- ÇEREZ / ONAY BANDI (§K3) ----------
   ALT BAND — modal/tam ekran değil (o fiilen onay duvarı olur, §K2 yasak).
   Yükseklik viewport'un %25'ini (mobilde %30) geçmez; ürün/fiyat/arama/sepet görünür kalır.
   Mobilde sabit sepet çubuğunun ÜSTÜNDE durur, onu ezmez. */
.consent{position:fixed;left:0;right:0;bottom:0;z-index:46;
  background:var(--surface);border-top:var(--border-emphasis) solid var(--primary);
  box-shadow:var(--elev-bar);max-height:25vh;overflow-y:auto;
  animation:consent-in var(--dur-enter) var(--ease-out)}
@keyframes consent-in{from{transform:translateY(100%)}to{transform:none}}
@media (prefers-reduced-motion:reduce){.consent{animation:none}}
.consent-in{display:flex;align-items:center;gap:var(--space-6);flex-wrap:wrap;
  padding-block:var(--space-4)}
.consent-tx{flex:1;min-width:var(--measure);font-size:var(--text-label);
  line-height:var(--lh-snug);color:var(--text)}
/* K2 SİMETRİ — Kabul ve Reddet aynı sınıf, aynı ızgara hücresi, aynı genişlik.
   Hiçbiri dolgulu/vurgulu değil; rıza oranı optimizasyon hedefi DEĞİL (K6). */
/* min-width yetmez: etiket uzunlukları farklı olduğu için içerik genişliği kazanıyor
   ve "aynı boyut" kuralı sessizce ihlal oluyordu. Genişlik SABİTLENİR. */
.consent-acts{display:grid;grid-auto-flow:column;gap:var(--space-3);align-items:center}
.consent-acts .btn--secondary{width:var(--consent-btn-w);flex:none}
@media (max-width:640px){
  .consent{max-height:30vh;bottom:0}
  .consent-in{gap:var(--space-3);padding-block:var(--space-3)}
  .consent-tx{min-width:0}
  /* İki simetrik düğme, tek satır. [ÖLÜ KURAL SİLİNDİ 2026-08-12] Burada
     `.consent-acts .btn--ghost{grid-column:1/-1}` vardı: üçüncü kontrolün iki sütunu birden
     kaplaması için yazılmış ama işaretlemedeki "Ayarlar" `btn--secondary` idi — kural HİÇ
     tutmuyordu ve düğme yanında boş sütun bırakarak alt satıra düşüyordu. Ayarlar artık metnin
     içinde gerçek bir link (bkz. CookieConsent görünümü); geriye iki düğme kaldı. */
  .consent-acts{grid-auto-flow:row;grid-template-columns:1fr 1fr;width:100%}
  /* SABİT 168 px × 2 + 12 px boşluk = 348 px; 360 px ekranda 32 px kenar payıyla
     birlikte 10 px taşıyordu. Simetri (§K2) "aynı piksel" değil "aynı hücre"dir —
     1fr 1fr zaten eşitliği garanti eder, sabit genişlik burada gereksiz. */
  .consent-acts .btn--secondary{width:auto;min-width:0}
  /* sepet çubuğu varsa bandın üstünde kalır, ezilmez */
  .cart-bar{bottom:var(--consent-h)}
}
/* ---- ALT YERLEŞİM: TEK BİLDİRİM ----
   Sayfanın altına iki şey yapışabilir: çerez bandı ve (mobilde) sepet çubuğu.
   İkisi AYNI ANDA görünebiliyor, o yüzden TEK toplamda hesaplanır. Önceki hâlde
   üç ayrı bildirim vardı ve medya-dışı olanlar ≤640 bloğunu eziyordu: toast
   sepet çubuğunun ALTINDA kalıp "Sepete git"i örtüyor, odak kaydırması 72 px'i
   unutuyordu (WCAG 2.4.11 için yazılan kural ölüydü).
   --bar-live ile --bottom-inset AYNI öğede (html) tanımlı: özel değer ikamesi
   kademelenmeden SONRA yapıldığı için medya sorgusundaki --bar-live kazanır. */
html{--bottom-inset:calc(var(--consent-h) + var(--bar-live));
  scroll-padding-bottom:calc(var(--bottom-inset) + var(--space-4));
  /* [KUSUR 2026-08-10 · denetim E5] Alt çubuk için pay VARDI, üst çubuk için YOKTU. Üst çubuk
     yapışkan ve mobilde 120 px: klavyeyle bir alana atlandığında hedef onun ALTINDA kalıyordu.
     WCAG 2.4.11 iki kenarı da istiyor. */
  scroll-padding-top:calc(var(--topbar-h) + var(--space-4))}
body{padding-bottom:var(--bottom-inset)}
.toast-host{bottom:calc(var(--bottom-inset) + var(--space-4))}

/* WhatsApp destek düğmesi — sağ alt köşe.
   Alt kenar `--bottom-inset`ten: mobil sepet çubuğu ve çerez şeridi de oradan hesaplanıyor,
   yoksa düğme "Sepete git"in üstüne oturuyordu. z-index sepet çubuğunun (45) ALTINDA:
   çakışma olursa kaybeden taraf destek düğmesi olmalı, satın alma yolu değil.
   Renk WhatsApp'ın kendi yeşili DEĞİL, markanınki: sağ altta yabancı bir marka rengi,
   üçüncü parti bir widget yapıştırılmış izlenimi veriyordu. */
.wa-fab{position:fixed;right:var(--space-4);z-index:44;
  bottom:calc(var(--bottom-inset) + var(--space-4));
  width:calc(var(--tap-min) + var(--space-3));height:calc(var(--tap-min) + var(--space-3));border-radius:50%;
  display:grid;place-items:center;background:var(--primary);color:var(--on-primary);
  box-shadow:var(--elev-float);text-decoration:none;
  transition:background var(--dur-micro) var(--ease-out),transform var(--dur-press) var(--ease-out)}
.wa-fab:hover{background:var(--primary-hover)}
.wa-fab:active{transform:scale(.94)}
.wa-fab svg{width:var(--icon-lg);height:var(--icon-lg)}

/* ---- ayarlar katmanı: kategoriler ---- */
.modal--wide{width:min(var(--sheet-w),calc(100vw - var(--space-8)))}
/* ---------- GİRİŞ / OTP ---------- */
/* Giriş SAYFASI — modalın sayfa karşılığı. Aynı formu taşır; JS kapalıyken tek yol burasıdır.
   Genişlik dialog ile aynı: kullanıcı modaldan sayfaya düşerse tanıdık bir yere düşsün. */
.auth-page{display:grid;place-items:start center;padding-block:var(--space-12)}
.auth-panel{width:min(var(--dialog-w),100%);display:grid;gap:var(--space-6)}
.auth-modal{width:min(var(--dialog-w),calc(100vw - var(--space-8)))}
.auth-brand{display:flex;align-items:center;justify-content:space-between;
  padding:var(--space-4) var(--space-4) 0 var(--space-6);flex:none}
.auth-brand .logo img{height:var(--logo-h-xs)}
.auth-modal .bd{gap:var(--space-6);padding-top:var(--space-4)}
.auth-head{display:grid;gap:var(--space-2)}
.auth-head .fine{line-height:var(--lh-snug)}
.auth-form{display:grid;gap:var(--space-4)}
.auth-form .field{max-width:none}
.auth-resend{font-size:var(--text-caption);color:var(--text-2);text-align:center;
  min-height:var(--space-6)}
.auth-resend b{color:var(--text);font-variant-numeric:tabular-nums}

/* telefon alanı — ülke kodu alanın İÇİNDE, ayrı bir kutu değil */
.telfield{display:flex;align-items:center;height:var(--control-h);
  background:var(--surface);border:var(--border-hairline) solid var(--control-border);
  border-radius:var(--radius-lg);overflow:hidden;
  transition:border-color var(--dur-micro) var(--ease-out)}
.telfield:focus-within{outline:var(--border-focus) solid var(--focus);outline-offset:var(--border-hairline);
  border-color:var(--primary)}
.telfield.is-invalid{border-color:var(--danger);border-width:var(--border-control)}
.telfield-cc{padding-inline:var(--space-4);font-weight:var(--w-semibold);color:var(--text-2);
  border-right:var(--border-hairline) solid var(--divider);line-height:var(--control-h);
  font-variant-numeric:tabular-nums}
.telfield-in{flex:1;min-width:0;border:0;outline:0;background:none;font:inherit;
  font-size:var(--text-body);padding-inline:var(--space-4);color:var(--text);
  font-variant-numeric:tabular-nums;letter-spacing:.02em}

/* OTP — altı hücre, tek kod. Kutular tek yüzey; formun bağlı alanı gizli input. */
.otp + .err,.otp ~ .err{display:block}
.field .lbl{color:var(--text);font-size:var(--text-label);
  font-weight:var(--w-bold);letter-spacing:normal;text-transform:none}
.otp{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--space-2)}
.otp-cell{width:100%;height:calc(var(--control-h) + var(--space-3));text-align:center;
  font:inherit;font-size:var(--text-h3);font-weight:var(--w-black);
  font-variant-numeric:tabular-nums;color:var(--text);
  background:var(--surface);border:var(--border-control) solid var(--divider);
  border-radius:var(--radius-lg);
  transition:border-color var(--dur-micro) var(--ease-out),
    background var(--dur-micro) var(--ease-out)}
/* [KUSUR 2026-08-10 · denetim E6] `outline:0` telafisiz kaldırılmıştı: yerine konan kenarlık
   DOLMUŞ hücrenin rengiyle aynı (bir alt satır), geriye yalnız ~1,08:1'lik zemin farkı kalıyordu
   (eşik 3:1) — yani klavye kullanıcısı hangi hücrede olduğunu göremiyordu. Ayrıca `:focus`
   fareyle tıklayanda da halka çiziyordu. Aynı dosyada `.searchbox` ve `.telfield` bunu doğru
   çözmüş; `.otp` o düzeltmeden pay almamış (§0.3 md.11, §E, WCAG 2.4.7). */
.otp-cell:focus-visible{outline:var(--border-emphasis) solid var(--primary);outline-offset:2px;
  background:var(--primary-soft)}
.otp-cell[data-filled]{border-color:var(--primary);background:var(--surface)}
.otp.is-invalid .otp-cell{border-color:var(--danger)}
@media (max-width:640px){.otp{gap:var(--space-1)}}
.ccat{display:grid;gap:var(--space-2);padding:var(--space-4);border-radius:var(--radius-lg);
  background:var(--quiet)}
.ccat-hd{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4)}
.ccat-hd b{font-size:var(--text-body)}
.ccat-meta{display:grid;grid-template-columns:auto 1fr;gap:var(--space-1) var(--space-3);
  margin:0;font-size:var(--text-caption)}
.ccat-meta dt{color:var(--text-2);font-weight:var(--w-semibold)}
.ccat-meta dd{margin:0;color:var(--text)}
/* Simetri kuralı ayarlar katmanında da geçerli — kabul/reddet aynı sabit genişlik */
.consent-ft{justify-content:space-between}
.consent-ft .btn--secondary{width:var(--consent-btn-w);flex:none}
@media (max-width:640px){.consent-ft .btn--secondary{width:auto;min-width:0}}
@media (max-width:640px){
  .consent-ft{display:grid;grid-template-columns:1fr 1fr}
  .consent-ft .btn--secondary{width:auto}
  .consent-ft .btn--primary{grid-column:1/-1}
}

/* anahtar (switch) — kapalı doğar, kendiliğinden açılmaz (K4.1) */
.switch{position:relative;display:inline-flex;align-items:center;cursor:pointer;flex:none}
.switch input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.switch .track{display:block;box-sizing:content-box;width:var(--space-12);height:var(--space-6);
  border-radius:var(--radius-pill);background:var(--control-border);
  transition:background var(--dur-micro) var(--ease-out)}
.switch .knob{display:block;width:var(--space-6);height:var(--space-6);border-radius:var(--radius-pill);
  background:var(--surface);box-shadow:var(--elev-card);
  transition:transform var(--dur-micro) var(--ease-out)}
.switch input:checked+.track{background:var(--primary)}
.switch input:checked+.track .knob{transform:translateX(var(--space-6))}
.switch input:focus-visible+.track{outline:var(--border-focus) solid var(--focus);
  outline-offset:var(--border-emphasis)}

/* `.foot-btn` KALDIRILDI 2026-08-13: taşıdığı tek öğe ("Çerez tercihleri") alt bandın yasal
   akışına indi ve orada diğer bağlantılarla aynı görünüyor — zaten öyle görünmesi isteniyordu,
   ayrı bir sınıfla aynı görünümü ikinci kez tarif etmenin karşılığı kalmadı.
   Karşılığı olmayan sınıf bırakılmıyor (§6.3b). */

/* Satır içi rozet: .badge kart köşesi için mutlak konumlu tanımlı; liste satırında
   akışta durması gerekiyor. Global tanıma dokunmadan bu bağlamda geri alınır. */
.btn--row .badge{position:static;white-space:nowrap;flex:none}

/* ---------- KAPALI EKRANI ----------
   Katalog yerine geçer. Arkadaki ızgara dekoratiftir ve ANİMASYONSUZDUR:
   kıpırdayan iskelet "yükleniyor" demek olurdu. Aşağı doğru maskeyle silinir —
   sayfanın orada bitmediğini, tezgâhın kapalı olduğunu anlatır. */
.shut{display:grid;gap:var(--space-8);margin-block:var(--space-8) var(--space-16);
  --shut-tone:var(--accent-ink);--shut-tone-soft:var(--accent-soft)}
.shut[data-kind="uncovered"]{--shut-tone:var(--danger);--shut-tone-soft:var(--danger-soft)}
/* KUTU YOK — hiyerarşiyi tipografi ve boşluk kurar. Kart, mesajı sayfadan koparıp
   "bir bildirim" gibi gösteriyordu; oysa bu ekranın kendisi sayfanın içeriği. */
.shut-body{display:grid;justify-items:center;gap:var(--space-4);
  text-align:center;max-width:var(--shut-w);margin-inline:auto;
  padding-block:var(--space-16) var(--space-8)}

.shut-badge{display:inline-flex;align-items:center;gap:var(--space-2);
  font-size:var(--text-micro);font-weight:var(--w-bold);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--shut-tone)}
.shut-badge svg{width:var(--icon-sm);height:var(--icon-sm)}

.shut-body h2{font-size:var(--text-display);letter-spacing:var(--tr-h1);
  font-weight:var(--w-black);line-height:var(--lh-tight);text-wrap:balance;margin:0}

/* Sorunun cevabı sayfanın en büyük öğesi: "ne zaman" ya da "nerede". */
.shut-fact{display:grid;justify-items:center;gap:var(--space-2);width:100%;
  margin:var(--space-4) 0 0}
.shut-fact-lbl{font-size:var(--text-caption);color:var(--text-2);
  letter-spacing:var(--tr-micro)}
.shut-time{font-size:var(--shut-time);font-weight:var(--w-black);letter-spacing:var(--tr-h1);
  line-height:var(--lh-none);font-variant-numeric:tabular-nums;color:var(--shut-tone)}
.shut-fact-sub{font-size:var(--text-label);color:var(--text-2)}
/* Sepette teslimat bilgisi — seçici değil, bilgi satırı */
.slot-info{display:flex;gap:var(--space-3);align-items:flex-start;margin:0;
  font-size:var(--text-label);line-height:var(--lh-snug)}
.slot-info svg{width:var(--icon-md);height:var(--icon-md);flex:none;color:var(--primary)}
.slot-info small{color:var(--text-2)}

/* Ödeme adımında seçili adres — salt okunur, tek kaynak */
.addr-read{background:var(--ground);border-radius:var(--radius-lg);padding:var(--space-3) var(--space-4)}
.addr-read-line{font-size:var(--text-label);font-weight:var(--w-semibold)}

/* Seçili adres — kapsam dışında "cevap" bir saat değil, hangi adresten söz ettiğimiz.
   Kutu değil: pin + iki satır, sayfanın akışında durur. */
.shut-fact--addr{display:flex;align-items:center;justify-content:center;
  gap:var(--space-3);width:auto;text-align:left}
.shut-fact--addr svg{width:var(--icon-lg);height:var(--icon-lg);flex:none;color:var(--shut-tone)}
.shut-fact--addr span{display:grid;gap:var(--space-1);min-width:0}
.shut-fact--addr b{font-size:var(--text-h3);font-weight:var(--w-bold);
  letter-spacing:var(--tr-h3);line-height:var(--lh-snug)}
.shut-fact--addr small{font-size:var(--text-label);color:var(--text-2)}
.shut-body p{margin:0;color:var(--text-2);line-height:var(--lh-body);max-width:var(--measure);
  font-size:var(--text-label)}
.shut-acts{display:flex;gap:var(--space-3);flex-wrap:wrap;justify-content:center;
  margin-top:var(--space-4)}

/* dekoratif tezgâh — kartın arkasından aşağı doğru siliniyor */
/* Tezgâh kartın ALTINDA akar ve aşağı doğru silinir: "burada bir tezgâh var, şu an
   erişemiyorsun" der. Kartın arkasına yerleştirilince maskeye sıkışıp kayboluyordu. */
.shut-grid{display:grid;gap:var(--space-4);
  grid-template-columns:repeat(auto-fill,minmax(var(--card-min),1fr));
  max-height:var(--shut-grid-h);overflow:hidden;opacity:.65;pointer-events:none;
  -webkit-mask-image:linear-gradient(to bottom,#000 0,#000 35%,transparent 100%);
  mask-image:linear-gradient(to bottom,#000 0,#000 35%,transparent 100%)}
.shut-tile{background:var(--surface);border-radius:var(--radius-xl);padding:var(--space-4);
  display:grid;gap:var(--space-3);align-content:start;height:var(--shut-tile-h)}
.shut-art{display:block;aspect-ratio:1/.82;border-radius:var(--radius-lg);background:var(--quiet)}
.shut-l{display:block;height:var(--space-3);border-radius:var(--radius-sm);background:var(--quiet)}
.shut-l--name{width:70%}
.shut-l--price{width:40%}
@media (max-width:640px){
  :root{--shut-time:60px}
  .shut-body{padding-block:var(--space-12) var(--space-6)}
  .shut-body h2{font-size:var(--text-h1);letter-spacing:var(--tr-h1)}
  .shut-grid{display:none}   /* dar ekranda ızgara mesajın altında ezik duruyordu */
}

/* ---------- TESLİMAT DURUM ŞERİDİ ----------
   Dört durumun tek yüzeyi. Renk gerçek sinyaldir: bilinmiyor nötr, kapalı/duraklatıldı
   uyarı, kapsam dışı hata. Alışveriş açıkken şerit HİÇ basılmaz. */
.state-strip{font-size:var(--text-label);line-height:var(--lh-snug)}
.state-strip-in{display:flex;align-items:center;gap:var(--space-3);
  padding-block:var(--space-3)}
.state-strip-in svg{width:var(--icon-md);height:var(--icon-md);flex:none}
.state-strip-in>span{flex:1;min-width:0}
.state-strip b{font-weight:var(--w-bold)}
.state-strip-in .btn{flex:none}
.state-strip[data-kind="unknown"]{background:var(--quiet);color:var(--text)}
.state-strip[data-kind="closed"],
.state-strip[data-kind="paused"]{background:var(--accent-soft);color:var(--accent-ink)}
.state-strip[data-kind="uncovered"]{background:var(--danger-soft);color:var(--danger)}

/* TESLİMAT SÖZÜ — şeridin AÇIK hâli (bkz. DeliveryStatus/Promise.cshtml).
   Kardeşlerinden (kapalı/duraklatıldı/kapsam dışı) ayrı bir ses: onlar uyarı, bu bilgi. O yüzden
   `--accent-soft`/`--danger-soft` gibi bir alarm zemini değil, katalogun kendi yüzeyi + ince bir
   alt kenarlık — kategori rayıyla aynı deyim (§B9.1: gölge yerine kenarlık + zemin farkı). */
.state-strip--promise{background:var(--surface);color:var(--text);
  border-bottom:var(--border-hairline) solid var(--divider)}
/* Maddeler içerikleri kadar yer kaplar (ortak kural `>span{flex:1}` üçünü eşit üçe bölüyordu;
   teslimat sözü en uzun, ücret en kısa madde — eşit sütun ikisini de yanlış gösteriyordu).

   [KUSUR 2026-08-14 · denetimde ölçüldü] Şerit SOLA PAKETLİYDİ: üç madde 116'da başlayıp
   1012'de bitiyor, sağda 268 px boşluk kalıyordu. Aynı sayfada aynı desenin ikinci örneği —
   footer'ın güven bandı — kenardan kenara yayılıyor ve araları eşit. İki bant birbirine
   benziyor ama farklı davranınca göz bunu ritim değil özensizlik olarak okuyor.
   Artık ikisi de `space-between`: ilk madde içerik kenarına, sonuncusu sağ kenara yaslanıyor.
   `gap` TABAN olarak kalıyor — sarma olduğunda maddeler birbirine yapışmasın. */
.state-strip--promise .state-strip-in{gap:var(--space-8);flex-wrap:wrap;
  justify-content:space-between}
.state-strip--promise .state-strip-in>span{flex:0 1 auto}
.promise-item{display:inline-flex;align-items:center;gap:var(--space-2);min-width:0}
/* İkon marka renginde, metin nötr: şerit bir sinyal değil bilgi satırı, ama ikonlar onu
   taranabilir kılıyor (üç madde tek bakışta ayrışıyor). */
.promise-item svg{color:var(--primary)}
@media (max-width:640px){
  /* Telefonda üç madde tek satıra sığmıyor. Alt alta diziliyorlar ve boşluk küçülüyor —
     yatay kaydırma YOK: ilk ekranda kaydırılması gereken bir bilgi, okunmayan bilgidir. */
  .state-strip--promise .state-strip-in{gap:var(--space-2);
    flex-direction:column;align-items:flex-start}
  .state-strip--promise{font-size:var(--text-caption)}
}
@media (max-width:640px){
  .state-strip{flex-wrap:wrap;padding-inline:var(--space-4)}
  .state-strip-in>span{flex:1 1 100%;order:2}
  .state-strip-in .btn{order:3;margin-left:auto}
}

/* ---------- GİRİŞ KAPISI ----------
   Kilitli kontrol devre dışı DEĞİL: aynı yükseklik, aynı tıklanabilirlik, farklı vaat. */
/* giriş penceresinde "neden soruyoruz" satırı — kapı sessiz açılmaz */
.auth-why{margin:0;padding:var(--space-3) var(--space-6) 0;
  font-size:var(--text-label);font-weight:var(--w-bold);color:var(--primary)}

/* ---------- KAMPANYA / DAVET ---------- */
.camp-lead{color:var(--text-2);font-size:var(--text-body);max-width:60ch;
  margin:0 0 var(--space-6)}
/* align-items:start — kapaksız kart, kapaklı komşusunun yüksekliğine uzayıp
   altında boş alan bırakıyordu. */
/* DAVET/KAMPANYA BÖLÜM BAŞLIĞI — 11 px mikro etiket DEĞİL.
   [KUSUR 2026-08-14 · ölçüldü] Davet sayfasının dört bölümü de (`Davet kodun · Kazancın ·
   Kademeler · Davet ettiklerin`) `.lbl` ile basılıyordu: 11 px, büyük harf. Sayfanın bütün
   iskeleti, sayfadaki en küçük puntoya emanetti. Ölçekte bir üst basamak ve normal yazım. */

.camp-grid{display:grid;gap:var(--space-4);align-items:start;justify-content:start;
  grid-template-columns:repeat(auto-fit,minmax(var(--camp-min),var(--camp-max)))}

.camp-card{display:grid;grid-template-rows:auto 1fr;background:var(--surface);
  border-radius:var(--radius-xl);overflow:hidden;text-decoration:none;color:var(--text);
  box-shadow:var(--elev-card);
  transition:transform var(--dur-micro) var(--ease-out),box-shadow var(--dur-micro) var(--ease-out)}
.camp-card:hover{transform:translateY(calc(var(--space-1) * -1));box-shadow:var(--elev-product)}
/* .bnr dinlenirken gölgesiz; hover'da kart seviyesine çıkar — kendi bir üst basamağı. */
/* KAPAK ORANI = MANŞET SÖZLEŞMESİ (2:1).
   [KUSUR 2026-08-14 · Eyüp: "kampanyalar berbat" · ölçüldü] Kutu 2,2:1, görsel ise `contain` ile
   yerleştiriliyordu: 383×174'lük kutuda afişin etrafında soluk yeşil bantlar kalıyor, kart
   "yüklenememiş" gibi duruyordu. `contain` kırpmamak için seçilmişti ama bedeli letterbox'tı.
   13 Ağustos'ta manşet 2:1 + `cover` sözleşmesine geçti ve afişler artık o orana üretiliyor;
   kampanya kartı da aynı sözleşmeyi kullanınca hem bant kalkıyor hem iki yüzey aynı dili
   konuşuyor. Oranında üretilmiş afişte kırpma OLMAZ — kutu ile görsel birebir. */
.camp-cover{display:block;aspect-ratio:2/1;background:var(--quiet);overflow:hidden}
.camp-cover img{width:100%;height:100%;object-fit:cover;display:block}
/* kapak görseli olmayan kampanya: boş gri kutu yerine marka zemini + simge */
.camp-body{display:grid;gap:var(--space-2);padding:var(--space-4);align-content:start}
.camp-body b{font-size:var(--text-h3);font-weight:var(--w-bold);letter-spacing:var(--tr-h3);
  line-height:var(--lh-snug)}
.camp-reward{font-size:var(--text-label);font-weight:var(--w-bold);color:var(--primary)}
.camp-meta{display:flex;align-items:center;gap:var(--space-2);
  font-size:var(--text-caption);color:var(--text-2)}
.camp-meta svg{width:var(--icon-sm);height:var(--icon-sm)}
/* geniş kart — davet gibi tek başına duran giriş */
.camp-card--wide{grid-template-columns:minmax(0,var(--camp-wide)) minmax(0,1fr);
  grid-template-rows:none;align-items:stretch}
.camp-card--wide .camp-cover{aspect-ratio:auto;height:100%}
@media (max-width:640px){
  .camp-card--wide{grid-template-columns:1fr;grid-template-rows:auto 1fr}
}

/* uygunluk üç durumlu: hesaplandı-uygun / hesaplandı-değil / misafir (hesaplanmadı) */
.camp-elig{font-size:var(--text-caption);font-weight:var(--w-semibold)}
/* [DEĞİŞTİ 2026-08-19] "yes" hâli `--primary` (yeşil) idi ve "Sepetine otomatik uygulanır"
   cümlesi ekranda BAĞLANTI gibi duruyordu — tıklanabilir sanılıyor, değil. Renk burada bir
   sinyal taşımıyor; taşıdığı tek şey yanlış bir çağrı (`feedback_restrained_color_usage`).
   Üç hâl de nötr: cümlenin kendisi zaten olumlu ya da olumsuz. */
.camp-elig[data-elig="yes"]{color:var(--text-2)}
.camp-elig[data-elig="no"]{color:var(--text-2)}
.camp-elig[data-elig="guest"]{color:var(--text-2)}
.camp-elig--lg{font-size:var(--text-label)}

/* MANŞET ARTIK KIRPMIYOR — İKİ SÜTUN.

   [KÖKTEN ÇÖZÜLDÜ 2026-08-19 · Eyüp: "görsel bu şekilde kötü duruyor"]
   Bu kusur bu dosyada 2026-08-09'da ZATEN ÖLÇÜLMÜŞTÜ ve notu duruyordu: "kutu 3.00:1 iken görsel
   1536×1024 (1.50:1), 'İndirim!' alttan yarılmış, 'Sana Özel' rozeti üstten kesilmişti. Düzeltme
   manşete inmiş, DETAY SAYFALARINA İNMEMİŞTİ." 08-14'te oran 2:1'e çekilip `max-height:55vh`
   eklendi — kırpma azaldı ama bitmedi. Son ölçüm (08-19): kutu 1280×435, görsel 1280×853'e
   ölçekleniyor, DİKEY KIRPMA 418 px = posterin %49'u. Manşetin kendi yazısı yine kesiliyordu.

   ÜÇÜNCÜ KEZ ORAN AYARLAMIYORUM, çünkü sorun oranda değil YÖNTEMDE: 3:2 üretilmiş, İÇİNDE METİN
   OLAN bir posteri geniş bir şeride `cover` ile oturtmanın kayıpsız bir yolu yok. Projenin kendi
   kuralı da bunu söylüyor — `.prod-media img` üstünde, Eyüp'ün koyduğu hâliyle:
   "KIRPMA YASAĞI (2026-08-12) — ürün/banner görseli kesilmez". Kampanya manşeti bu kuralın
   dışında kalmıştı.

   Çözüm ürün sayfasının DENENMİŞ kompozisyonu (`.prod-hero`): solda görsel, sağda metin. Böylece
   üç şey birden düzeliyor —
     · görsel `contain` ile TAM görünüyor (kırpma sıfır),
     · poster ilk ekranı yemiyor (640 px genişlikte 3:2 → 427 px),
     · sağdaki sütun boş kalmıyor; başlık, ödül ve aksiyon oraya geçiyor.
   Farklı oranda bir kapak yüklenirse `contain` onu kırpmaz, `--primary-soft` zeminde ortalar:
   eksik bir kadraj, kesilmiş bir vaatten iyidir. */
/* Alt pay YOK: ritmi `.page`in `gap`i veriyor. İkisini birden vermek 48+64 = 112 px'lik bir
   kopukluk üretiyordu (ölçüldü 2026-08-19). */
.camp-hero{display:grid;gap:var(--space-12);align-items:start;
  grid-template-columns:minmax(0,var(--camp-media)) minmax(0,34rem)}
/* Kutu oranı 3:2 — yönetimden yüklenen kapakların gerçek oranı (ölçüldü: 1536×1024). Doğru
   oranda yüklenen görselde `contain` hiç boşluk bırakmaz, yanlış oranda ise kırpmak yerine
   çerçeveler. */
.camp-media{display:block;aspect-ratio:3 / 2;border-radius:var(--radius-2xl);overflow:hidden;
  background:var(--primary-soft);box-shadow:var(--elev-card)}
.camp-media img{width:100%;height:100%;object-fit:contain;display:block}
/* Dar ekranda görsel üstte tam genişlik — iki sütun sıkışınca ikisi de okunmaz oluyor
   (`.prod-hero` ile aynı kırılım, aynı sebep). */
@media (max-width:1024px){
  .camp-hero{grid-template-columns:1fr;gap:var(--space-8)}
}
/* Kapağı OLMAYAN kampanyada iki sütun KURULMAZ: tek çocuk 640 px'lik ilk sütuna düşer ve
   başlık/ödül bloğu, yanında bomboş bir sütunla yarı genişlikte kalırdı. Aynı karar ürün
   sayfasında da var (`heroClass`) — orada da kanıtlanmış. */
.camp-hero--nomedia{grid-template-columns:minmax(0,34rem)}
/* Ölçü artık kendisinden değil BULUNDUĞU SÜTUNDAN geliyor (`.camp-hero` 2. sütun · 34rem).
   Alt payı da kalktı: iki sütunlu ızgarada boşluğu `gap` veriyor. */
.camp-head{display:grid;gap:var(--space-3);justify-items:start}
.camp-type{font-size:var(--text-micro);font-weight:var(--w-semibold);letter-spacing:var(--tr-label);
  text-transform:uppercase;color:var(--primary);background:var(--primary-soft);
  padding:var(--space-1) var(--space-3);border-radius:var(--radius-pill)}
.camp-head h1{font-size:var(--text-h1);letter-spacing:var(--tr-h1);line-height:var(--lh-tight);
  font-weight:var(--w-black);text-wrap:balance}
/* Açıklama admin'de çok satırlı yazılıyor. Razor metni kaçırdığı için \n'ler HTML'de boşluğa
   düşüyor ve paragraf tek satır oluyordu; pre-line yazarın satır sonlarına saygı duyar. */
.camp-desc{color:var(--text-2);line-height:var(--lh-body);margin:0;white-space:pre-line}
.camp-acts{display:flex;flex-wrap:wrap;gap:var(--space-3);margin-top:var(--space-2)}

/* ÖDÜL — SAYFANIN CEVABI, TABLONUN SATIRI DEĞİL.

   [KUSUR 2026-08-19 · Eyüp: "sayfa kötü duruyor"] Kampanya sayfasına gelen tek bir soru soruyor:
   "ne kazanacağım". Cevap (100,00 ₺) koşullar tablosunun BEŞ satırından biriydi ve tipografik
   ağırlığı "En az sepet tutarı" ile birebir aynıydı — yani sayfanın cevabı, sayfanın en sıradan
   yerinde duruyordu. Vaat yukarı, aksiyonun yanına alındı.

   Tablodan ÇIKARILDI, kopyalanmadı: §R7 madde 5 "aynı bilgiyi aynı sayfada iki kez söylemek"
   yasak. Karar sunucuda (`CampaignController` · RewardHeadline), görünüm yalnız basıyor. */
/* Ad `.camp-prize`, `.camp-reward` DEĞİL: o ad kampanya LİSTESİNDE satır-içi bir ödül metni
   olarak zaten kullanılıyor (Campaign/Index.cshtml). Aynı adı vermek listedeki satırları
   zeminli bloklara çevirirdi — iki farklı iş, iki farklı ad. */
/* TEKLİF KARTI — sağ sütun tek bir kütle.
   [DEĞİŞTİ 2026-08-19 · iki dış tasarım incelemesi] Sağ sütunda dört ayrı öğe (başlık, açıklama,
   ödül, düğme) tek tek havada duruyordu; incelemelerin deyimiyle "kart bile değil". Ödül, durum
   cümlesi ve aksiyon TEK kutuda toplandı — kütle buradan geliyor.
   Kütleyi ARTIRMAK İÇİN buraya "min. sepet 450 ₺" gibi olgular EKLENMEDİ (inceleme öneriyordu):
   onlar hemen aşağıdaki koşul ızgarasında yazıyor ve §R7 m.5 aynı bilgiyi iki kez söylemeyi
   yasaklıyor. Kütle tekrardan değil kompozisyondan gelir. */
/* `width:100%` ŞART: kart `.camp-head` ızgarasının çocuğu ve orası `justify-items:start` —
   onsuz kutu içeriğine büzülüyor (ölçüldü: 544 px'lik sütunda 390 px) ve "kart" hissi
   kayboluyordu. */
.camp-offer{display:grid;gap:var(--space-4);justify-items:start;width:100%;
  background:var(--surface);border-radius:var(--radius-2xl);box-shadow:var(--elev-card);
  padding:var(--space-6)}
.camp-offer .camp-acts{margin-top:0}
.camp-prize{display:grid;gap:var(--space-1);padding:var(--space-4) var(--space-6);
  background:var(--primary-soft);border-radius:var(--radius-xl);justify-items:start;
  width:100%}
.camp-prize .lbl{margin-bottom:0}
.camp-prize b{font-size:var(--text-display);font-weight:var(--w-black);
  letter-spacing:var(--tr-h1);line-height:var(--lh-tight);color:var(--primary-pressed)}
@media (max-width:640px){.camp-prize b{font-size:var(--text-h1)}}

/* KAPANIŞ — sayfa okuyanı boşlukta bırakmaz.
   [KUSUR 2026-08-19] Dipnottan sonra footer'a kadar hiçbir şey yoktu: kampanya ilgisini
   çekmediyse gidecek yer de yoktu. §J7 (çıkmaz sokak yok) ve denetim B9'un aynısı. */
/* `margin-top` YOK: ayrımı `.page`in `gap`i yapıyor, çizginin nefesini `padding-top` veriyor.
   Üçü birden verilince blok sayfadan 144 px kopuyordu. */
.camp-next{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;
  padding-top:var(--space-8);border-top:var(--border-hairline) solid var(--divider)}
.camp-next .fine{margin-right:auto}
/* KAPANIŞ — başka kampanya yokken. Çizgi + yalnız düğme yerine gerçek bir bitiş: sayfa
   "yüklenmemiş" değil, "burada bitti ve yolun şurası" der. Ortalanıyor çünkü sayfanın son
   bloğu ve tek bir çağrı taşıyor; §R6.5'in tek-blok istisnası. */
.camp-close{display:grid;gap:var(--space-3);justify-items:center;text-align:center;
  padding-block:var(--space-12);border-top:var(--border-hairline) solid var(--divider)}
.camp-close p{color:var(--text-2);max-width:34rem}

/* koşullar: "şartlar geçerlidir" yerine satır satır okunur liste */
/* BÖLÜM BAŞLIKLARI ETİKET DEĞİL BAŞLIKTIR.
   [KUSUR 2026-08-14 · ölçüldü] "Koşullar" ve "Kademeler" `.lbl` ile basılıyordu: 11 px, büyük
   harf. Sayfanın TEK iki bölüm başlığı, sayfadaki en küçük puntoydu — yapıyı mikro etikete
   emanet etmek, kurumsal görünmenin tam tersi. Ölçekte bir üst basamak (20 px) ve normal
   yazım; üstteki h1 (31) ile birlikte gerçek bir merdiven. */

/* Koşullar ve dipnot OKUMA ÖLÇÜSÜNDE kalır. 1181 px'lik satırda "100,00 ₺ indirim" değeri
   etiketinden 900 px uzağa düşüyordu; dipnot ise tek satırda ~150 karakter oluyordu (okunabilir
   ölçünün iki katı). Blok kabın tamamını değil, okunabilir genişliği kullanır. */
/* [DEĞİŞTİ 2026-08-16] Listede `.camp-foot` de vardı. Dipnot başlıksız bölümün içine alınınca
   `.page-sec > p` (34rem) devreye giriyor ve seçici daha güçlü (0,1,1 > 0,1,0) — buradaki 44rem
   ölü bildirime dönüşmüştü. Dipnot artık bölümün DÜZYAZI ölçüsünde, /hakkimizda ve /iletisim'in
   paragraflarıyla aynı: 544 px. Tablolar 44rem'de kalır, onlar düzyazı değil. */
.camp-terms,.camp-tiers{max-width:44rem}
/* KOŞULLAR — TABLO DEĞİL KART IZGARASI.

   [YENİDEN KURULDU 2026-08-19 · iki dış tasarım incelemesi] Koşullar dar bir etiket/değer
   tablosuydu ve `.page-sec`in içinde duruyordu: solda tek başına "Koşullar" başlığı, sağda 704
   px'lik bir tablo, sağında ~300 px boşluk. İncelemelerin ortak teşhisi: "başlık bir bölüm
   başlığı gibi davranmıyor, sayfada unutulmuş bir etiket gibi duruyor" ve "tablo yatay alanı
   kullanmıyor". Kompozisyon dengesizdi — ölçüldü: tablo L=432, sayfa içeriği L=116'da başlıyor.

   Artık bölüm tam genişlikte ve koşullar `auto-fit` kartlar: geniş ekranda üç kart yan yana,
   dar ekranda alt alta. Her kart TEK bir olgu taşıyor, göz etiketten değere 900 px yol
   yürümüyor (Gestalt yakınlık — incelemenin de işaret ettiği ihlal).
   Birleşme kuralı bu ızgaraya GİRMİYOR: o bir cümle, ötekiler olgu (bkz. `.camp-note`). */
.camp-terms{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:var(--space-4);margin:0;max-width:none}
.camp-terms>div{display:grid;gap:var(--space-2);align-content:start;
  background:var(--surface);border-radius:var(--radius-xl);box-shadow:var(--elev-card);
  padding:var(--space-6)}
/* AĞIRLIK DEĞERDE, ETİKETTE DEĞİL.
   [KUSUR 2026-08-19 · dış inceleme] Etiket 11 px ama BÜYÜK HARF + kalın + harf aralığıyla
   değerden fazla ağırlık taşıyordu; göz önce "EN AZ SEPET TUTARI"nı görüyordu, "450,00 ₺"yi
   sonra. Oysa kampanyanın bilgisi değerin kendisi. Etiket bir kademe susturuldu (kalın→yarı
   kalın), değer bir kademe yükseltildi (20→25 px). */
.camp-terms dt{color:var(--text-2);font-size:var(--text-micro);font-weight:var(--w-semibold);
  letter-spacing:var(--tr-label);text-transform:uppercase}
.camp-terms dd{margin:0;font-size:var(--text-h2);font-weight:var(--w-black);
  letter-spacing:var(--tr-h2);line-height:var(--lh-tight);color:var(--text)}
/* Kartın içindeki kısa gerekçe — değer kısa kalsın diye. */
.camp-term-note{margin:0;font-size:var(--text-caption);color:var(--text-2);
  line-height:var(--lh-snug)}
/* [KALDIRILDI 2026-08-19] `.camp-note` buradaydı: birleşme kuralını ızgaranın ALTINDA ayrı bir
   paragraf olarak basıyordu. Dış inceleme haklıydı — "kart genişliklerinden bağımsız, sahipsiz
   ortada kalmış". Kural artık dördüncü kartın içinde (`.camp-term-note`). */
/* [KALDIRILDI 2026-08-19] Dar ekranda satırı tek sütuna indiren kural buradaydı; kartlar
   `auto-fit` olduğu için ızgara zaten kendiliğinden tek sütuna iniyor. */

.camp-tiers{width:100%;border-collapse:collapse;background:var(--surface);
  border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--elev-card);
  font-variant-numeric:tabular-nums}
.camp-tiers th,.camp-tiers td{text-align:left;padding:var(--space-3) var(--space-4);
  border-bottom:var(--border-hairline) solid var(--divider);font-size:var(--text-label)}
.camp-tiers th{color:var(--text-2);font-weight:var(--w-semibold);font-size:var(--text-caption)}
.camp-tiers tr:last-child td{border-bottom:0}
.camp-tiers td:first-child{font-weight:var(--w-semibold)}

/* davet kodu — okunması ve kopyalanması gereken tek şey, en yüksek kontrast */
.ref-code{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.ref-code-lbl{font-size:var(--text-caption);color:var(--text-2)}
.ref-code{margin-top:var(--space-4)}
.ref-code b{font-size:var(--text-h3);font-weight:var(--w-bold);letter-spacing:var(--tr-label);
  background:var(--primary-soft);color:var(--pine-700);
  padding:var(--space-2) var(--space-4);border-radius:var(--radius-lg)}


.ref-stats{display:grid;gap:var(--space-3);
  grid-template-columns:repeat(auto-fit,minmax(var(--ref-stat-min),1fr))}
.ref-stat{background:var(--surface);border-radius:var(--radius-xl);padding:var(--space-4);
  box-shadow:var(--elev-card);display:flex;align-items:center;gap:var(--space-3)}
.ref-stat-tx{display:grid;gap:var(--space-1);min-width:0;flex:1}
.ref-stat-ico{display:grid;place-items:center;width:var(--icon-xl);height:var(--icon-xl);
  flex:none;border-radius:var(--radius-pill);background:var(--primary-soft);color:var(--primary)}
.ref-stat-ico svg{width:var(--icon-md);height:var(--icon-md)}
.ref-stat b{font-size:var(--text-h2);font-weight:var(--w-bold);letter-spacing:var(--tr-h2);
  font-variant-numeric:tabular-nums;line-height:var(--lh-none)}
.ref-stat small{font-size:var(--text-caption);color:var(--text-2)}

.ref-list{list-style:none;margin:0;padding:0;background:var(--surface);
  border-radius:var(--radius-xl);box-shadow:var(--elev-card);overflow:hidden}
.ref-list li{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:var(--space-4);
  align-items:center;padding:var(--space-3) var(--space-4);
  border-bottom:var(--border-hairline) solid var(--divider)}
.ref-list li:last-child{border-bottom:0}
.ref-who{display:grid;gap:var(--space-1);min-width:0}
.ref-who b{font-size:var(--text-label);font-weight:var(--w-bold)}
.ref-who small{font-size:var(--text-caption);color:var(--text-2)}
.ref-state{font-size:var(--text-caption);font-weight:var(--w-semibold);
  padding:var(--space-1) var(--space-3);border-radius:var(--radius-pill)}
.ref-state[data-state="ok"]{background:var(--primary-soft);color:var(--primary)}
.ref-state[data-state="wait"]{background:var(--quiet);color:var(--text-2)}
.ref-earn{font-weight:var(--w-black);font-variant-numeric:tabular-nums;
  min-width:var(--money-w);text-align:right}
@media (max-width:640px){
  .ref-list li{grid-template-columns:minmax(0,1fr) auto;row-gap:var(--space-2)}
  .ref-state{grid-column:1;justify-self:start}
}

/* ---------- MANŞET (hero slider) ----------

   Kampanyanın durduğu geniş alan. İçerik SADECE GÖRSEL: başlık, alt metin ve çağrı afişin
   içinde tasarlanır (Eyüp, 2026-08-12). Bu bölümün tek işi, afişi doğru oranda ve ilk ekranı
   yemeden göstermek.

   [YENİDEN ÖLÇÜLDÜ 2026-08-12 · Eyüp: "slider tarafı çok amatörce duruyor"]
   Eski hâlinin ölçümü (1512×785): manşet bloğu 592 px — üst çubukla birlikte ilk ekranın %86'sı,
   ilk ürün kartı 943 px'de, yani katlamanın 158 px ALTINDA. Manav sitesinin ilk ekranında ne
   ürün, ne fiyat, ne sepet vardı. İki şey düzeldi ve ikisi de ÇERÇEVEDE:

     1. ORAN. Kutu 2:1 idi (536 px) ve afişleri kırpıyordu: 1,78:1'lik afişten %11, 1,50:1'likten
        %25. Metin görselin İÇİNDE olduğu için kırpılan şey doğrudan kampanyanın sözü oluyordu.
        Yeni oran 3:1 — bu sayı burada YENİ DEĞİL, bu dosyada zaten "doğru çözüm görselleri 3:1
        üretmek (1600×534)" diye yazılıydı; o gün gelene kadar CSS esnetiliyordu. Artık çerçeve
        doğru oranı İLAN EDİYOR ve afiş ona göre üretiliyor.

     2. KONTROL KÜMESİ. Çerçevenin ALTINDA, ortada, iki yuvarlak okun arasında bir nokta satırı
        vardı — 44 px yer yiyordu ve manşeti tarihli gösteren şey büyük ölçüde oydu. Noktalar
        görselin üstüne, kendi perdeli hapının içine alındı; oklar kalktı.

   Sonuç: 592 → 357 px, ilk ürün kartı katlamanın içinde.

   [ÜRETİM ÖLÇÜSÜ — afişi hazırlayan için]
     masaüstü 1800×600 (3:1) · mobil 1080×540 (2:1)
   Bu ölçülerde HİÇBİR ŞEY KIRPILMAZ. Başka oranda gelen afiş ortadan kırpılır (`cover`):
   bugünkü iki afiş 3:1'de dikeyde %41 ve %50 kaybediyor — yenileri gelene kadarki bedel bu.
*/
.hero{margin-top:var(--space-4);margin-bottom:var(--space-6)}
@media (max-width:640px){.hero{margin-bottom:var(--space-4)}}
/* Katalog manşetin hemen ardında: `.section`ın 48 px'lik üst payı burada tekrar ediyordu. */
#catalog{padding-top:var(--space-6)}

/* ---------- manşet: TEK DEV AFİŞ DEĞİL, ÇOK KARTLI RAY ----------

   [YAPI DEĞİŞTİ 2026-08-13 · Eyüp · rakip incelemesi] Manşet tek slayttı: bir kampanya ekranın
   tamamını kaplıyor, ikincisi 8 px'lik noktaların arkasında saklı kalıyordu. Ölçülen üç sonuç:
     · 16:9 bir afiş 1152 px'lik kapta 648 px yükseliyordu — üst çubukla birlikte 1440×900 bir
       ekranda ilk görüntünün %86'sı. Kılavuz §J14.3 sınırı: yarısını geçemez.
     · Masaüstünde ray tekerleğe kapalı, kendiliğinden ilerleme yok → 2. kampanyayı kimse görmüyor.
     · Afişin yüksekliği bizim değil, afişi ÜRETENİN kararıydı.

   Getir'de ölçtüğümüz çözüm: kampanya sayısını YÜKSEKLİKLE değil GENİŞLİKLE karşılamak.
   12 kampanya, 400×200'lük kartlar, aynı anda üçü ekranda, toplam 200 px. Buradaki oran aynı
   fikrin bizim kabımıza uyarlanmışı: 1152 px içerikte üç kart (368×184) + 24 px oluk.

   ÜÇ SORUN BİRDEN KAPANIYOR: fold maliyeti 648 → 184 px · bütün kampanyalar aynı anda görünür
   (keşif sorunu ortadan kalkar) · yükseklik artık bizim kararımız.

   [KURAL DEĞİŞTİ] "Manşet görseli ASLA KIRPILMAZ" kuralı buraya kadar geçerliydi ve gerekçesi
   sağlamdı: metin afişin İÇİNDE olduğu için her kırpma kampanyanın sözünü kesiyordu. Kart artık
   SABİT 2:1 ORAN ilan ediyor, dolayısıyla orana uymayan afiş `cover` ile ortadan kırpılır.
   Bunu bilerek kabul ediyoruz çünkü artık kırpma bir sürpriz değil bir SÖZLEŞME: admin afişi
   yükleyene 2:1 (1200×600) diyor ve önizlemede kırpmayı gösteriyor. Oranında üretilen afiş hiç
   kırpılmaz — Getir'in afişleri de tam 2:1 üretiliyor (ölçüldü: 1124×562). */
/* [ARAÇ DEĞİŞTİ 2026-08-16] Kutu artık kendi kaydırmıyor. Eskiden `overflow-x:auto` +
   `scroll-snap` ile YERLİ kaydırma vardı; carousel (tek tek ilerleme + kesintisiz döngü +
   sürükleme) Embla'ya geçince hareketi kütüphane yönetiyor ve bu kutunun tek işi PENCERE olmak.
   Gerekçenin tamamı `js/_shared/hero.js` başlığında.

   YERLEŞİM KARARLARI DEĞİŞMEDİ, yalnız ızgaradan flex'e taşındı — üçü de ekranda ölçülerek
   bulunmuş kusur düzeltmeleri, kütüphane bunları devralmıyor. */
.hero-rail{overflow:hidden}

/* OLUK `gap` DEĞİL, YUVANIN İÇ PAYI.

   [KUSUR 2026-08-16 · Eyüp ekran görüntüsüyle gösterdi: "bazı görsellerin arasında boşluk
   olmuyor"] Önce şeritte `gap:var(--grid-gutter)` vardı ve döngüde TEK BİR DİKİŞTE oluk
   kayboluyordu — iki kart bitişik basıyordu. Ölçüldü:
     kart 346,66 · oluk 24 · adım 371
     Embla'nın içerik boyu (limit.length) = 2200 = 6 kart + BEŞ oluk
     kesintisiz döngü için gereken     = 2226 = 6 kart + ALTI oluk
   Sebep yapısal: `gap` olukları ARALARA koyar, sonuncunun arkasına koymaz; Embla ise içerik
   boyunu ilk slaytın solundan sonuncunun sağına ölçüyor. Başa saran slayt 24 px erken oturuyor.

   Çare: oluğu her slaytın KENDİ KUTUSUNUN İÇİNE almak. Her kart bir `.hslot` yuvasına giriyor,
   oluk yuvanın sol iç payı, şerit de bir oluk sola kayıyor ki ilk kart rayın sol kenarına
   dayansın. Böylece her yuva birebir aynı: döngü dikişi diğer aralıklardan ayırt edilemiyor.
   Ölçümle doğrulandı — içerik boyu 2224 = 6 × 371, ilk kart 0'da, üçüncü kart 1088'de biter
   (ray genişliği 1088), iki kampanyada boşluklar 185,34 / 185,34 yani hâlâ ortalı.

   `touch-action`: yatay sürüklemeyi Embla alır, DİKEY kaydırma tarayıcıda kalır. Yazılmazsa
   telefonda manşetin üstünde parmakla sayfa aşağı kaydırmak tutukluk yapıyor. */
.hero-strip{display:flex;justify-content:safe center;
  margin-left:calc(var(--grid-gutter) * -1);
  touch-action:pan-y pinch-zoom}

/* KART GENİŞLİĞİ SABİT ÜÇTE BİR — `1fr`/`auto` DEĞİL.

   [KUSUR 2026-08-14 · R8 checklist'i koşarken ölçüldü] Burada esneyen bir genişlik vardı ve
   gerekçesi şuydu: iki kampanyayla sağda boş yuva kalıyor, o yuva "kampanya yüklenemedi" diye
   okunuyor. Sorun gerçekti ama çare TERS ÇALIŞAN bir kural üretti: kart 2:1 oran ilan ettiği
   için genişleyen kart AYNI ORANDA UZUYOR.
     3 kampanya → kart 411×206
     2 kampanya → kart 628×314   ← %52 daha uzun
   Yani KAMPANYA SAYISI AZALDIKÇA MANŞET BÜYÜYOR. Bedeli ölçüldü: fazladan 108 px ve o 108 px
   ilk ürün kartını katlamanın dışına itiyordu (§R4.1 "ilk ekranda ürün ve fiyat görünür").

   BOŞ YUVA SORUNU `safe center` ile çözülüyor, esneme ile değil: kartlar şeride sığıyorsa
   ORTALANIR (simetri "böyle tasarlanmış" okunur, sağdaki tek delik "eksik" okunurdu), sığmıyorsa
   `safe` anahtar sözcüğü hizalamayı başa düşürür ve ilk kart asla kırpılmaz.

   YÜZDELER YUVAYA GÖRE, RAYA GÖRE DEĞİL: şerit bir oluk sola kaydığı için genişliği raydan bir
   oluk fazla, yani burada `100%` = ray + oluk. Üçte bir yuva (`100%/3`) tam olarak "kart +
   oluk" eder ve kart (ray - 2 oluk)/3'e oturur — eski değerin aynısı, ölçümle doğrulandı.

   `min-width:0`: flex öğesinin varsayılan `auto` en küçük boyu, `flex-basis`i içerik boyutuyla
   ezip kartı büyütebilir. */
.hslot{flex:0 0 calc(100% / 3);padding-left:var(--grid-gutter);min-width:0}

/* Zemin MARKA YEŞİLİ, soluk yeşil değil. İki işi birden yapıyor:
   · Standart dışı oranda gelen afişte `contain`in bıraktığı yan bant, afişlerin kendi koyu yeşil
     zeminiyle neredeyse birleşiyor — soluk zeminde bant "görsel yüklenmemiş" gibi okunuyordu
     (ekranda görüldü: 1,50:1'lik afişin iki yanında 75'er px açık şerit).
   · Görsel gelene kadarki bekleme hâli de markanın rengi oluyor; kart boş doğmuyor.
   Standarda (2:1) uyan afişte zemin zaten hiç görünmez — bu kural yalnız uymayan için var. */
.hslide{position:relative;display:block;
  border-radius:var(--radius-xl);overflow:hidden;background:var(--primary);
  /* Oran SÖZLEŞME ve artık burada SABİT DEĞİL: banner'ın formatından (Afiş 2:1 / Şerit 6:1)
     türeyip Razor'dan değişken olarak basılıyor. Tek kaynağı BannerFormatSpecs; CSS'in kendi
     sayısını tutması, oran değiştiğinde üç yüzeyden birinin geride kalması demekti.
     Yedek değer, değişken bir şekilde basılmazsa kartın çökmemesi için. */
  aspect-ratio:var(--gc-banner-aspect, 2 / 1)}
/* Tarayıcı varsayılanı sıfırlanmazsa tasarım sistemi delinir — `.chip` ve `.pcard .name` için
   yapılan sıfırlamanın aynısı (§6.3b). */
a.hslide{text-decoration:none;color:inherit}
.hslide picture{display:block;width:100%;height:100%}

/* ===== AFİŞ · ÜRETİM ÖLÇÜSÜ FORMATTAN GELİR =====
   Afiş 2:1 → 1200×600, Şerit 6:1 → 1200×200 (BannerFormatSpecs).

   [DEĞİŞTİ] Burada `contain` vardı ve gerekçesi sağlamdı: metin afişin İÇİNDE olduğu için
   orana uymayan bir görseli kırpmak doğrudan kampanyanın sözünü kesiyordu, `contain` ise
   kesmiyordu. Ama o gerekçe, "orana uymayan afiş" diye bir şeyin var olabildiği dünyaya aitti.
   Artık panelde görsel hedef orana KIRPILARAK yükleniyor ve sunucu oranı doğruluyor; kutuya
   tam oturan bir görselde `contain` ile `cover` birebir aynı sonucu verir.

   `cover` seçiliyor çünkü sözleşmeyi İFADE ediyor: bir gün oranı tutmayan bir görsel sızarsa
   kartın zemininde bant bırakmak yerine kırpar — bant "görsel yüklenmemiş" gibi okunurdu. */
.hslide-art{position:relative;z-index:1;width:100%;height:100%;display:block;object-fit:cover}
a.hslide:hover .hslide-art{opacity:.94}
a.hslide:hover{box-shadow:var(--elev-product)}

/* Dar ekranda tek kart + komşusundan bir parça: "yana kaydırılabilir" mesajını taşıyan şey
   kaydırma çubuğu değil, kenardan taşan kart (Getir'de de böyle). */
@media (max-width:640px){
  /* Tek kampanyada da 88%'de kalır — esneyen genişlik olsaydı kart tam genişliğe uzayıp 2:1
     oranı gereği boyunu da büyütürdü (bkz. taban kuraldaki ters-çalışan-kural notu).

     TAVAN 360 px — yine §R2.4. Yalnız `88%` yazmak yüzdeyi ekranla birlikte büyütüyor ve 2:1
     oran boyu da büyütüyordu: 390 px'te kart 315×158, 640 px'te 535×267. Yani DAR ekranda
     manşet, geniş ekrandakinden UZUN oluyordu (641 px'te iki kartlı düzen 276×138 veriyor —
     640 ile 641 arasında 267 → 138'lik ters basamak).
     Tavan keyfî değil ÜRETİM STANDARDINDAN geliyor: mobil afiş 720×360 üretiliyor, yani
     360 CSS px'ten geniş göstermek görseli büyütmek demek. Kart en fazla afişin kendi boyu.

     Ölçü YUVAYA yazılıyor (yuva = kart + oluk), o yüzden tavan da bir oluk yukarı taşındı.
     Yüzde dalı yuvaya göre ölçüldüğü için kart tasarlanandan 0,12 oluk kadar dar kalıyor —
     mobilde ~1,9 px. Sapma bilerek kabul edildi: tam ifade `min(88% - 0.88 * oluk, 360px) +
     oluk` olurdu ve 2 px için okunmaz bir satır bırakırdı. Tavan dalı tam isabetli. */
  .hslot{flex-basis:min(88%, calc(360px + var(--grid-gutter)))}
}
/* Tablet aralığında iki kart. Üç kart 768 px'te 240 px'e düşüyor ve afişin içindeki yazı
   okunmaz hâle geliyordu. */
@media (min-width:641px) and (max-width:1024px){
  /* Sabit yarım — esneyen genişlik az kartta boyu da uzatırdı (taban kuraldaki not). */
  .hslot{flex-basis:calc(100% / 2)}
}

/* OKLAR — YALNIZ FARE OLAN CİHAZDA.
   Dokunmatikte parmak zaten kaydırıyor; orada iki ok, rayın üstünde duran iki gereksiz nesne
   olurdu. Sorgu genişliğe değil GİRDİ CİHAZINA bakıyor.
   Noktalar KALDIRILDI: nokta "sayfa" anlatır, oysa bu bir ray — üç kart görünürken dördüncüyü
   nokta ile saymak, kullanıcının gördüğü şeyle uyuşmayan bir gösterge olurdu. */
@media (pointer:fine){
  .hero{position:relative}
  .hero-step{position:absolute;top:50%;translate:0 -50%;z-index:2;
    width:var(--tap-min);height:var(--tap-min);padding:0;border:0;border-radius:var(--radius-pill);
    display:grid;place-items:center;cursor:pointer;color:var(--on-dark);
    background:var(--scrim);backdrop-filter:blur(var(--scrim-blur));
    /* Sessiz duruyor, gerektiğinde beliriyor: rayın işi afişleri göstermek, kontrolünü değil.
       `visibility` de kapanıyor — yalnız `opacity:0` bırakmak, görünmeyen ama TIKLANABİLEN bir
       düğme demek (afişin üstünde iki ölü bölge). */
    opacity:0;visibility:hidden;
    transition:opacity var(--dur-enter) var(--ease-out),visibility var(--dur-enter) var(--ease-out),
      background var(--dur-micro) var(--ease-out)}
  .hero-step:hover{background:var(--scrim-hi)}
  /* Oklar rayın DIŞINA taşar: içeride dursalardı ilk ve son kartın üstünü örterlerdi. */
  .hero-step--prev{left:calc(var(--space-4) * -1);rotate:180deg}
  .hero-step--next{right:calc(var(--space-4) * -1)}
  /* [KUSUR 2026-08-13 · tarandı] Dış pay SABİT −16 px, sayfa kenar payı ise değişken: 640'ın
     altında `--grid-margin` 16'ya iniyor ve ikisi TAM BİRBİRİNİ GÖTÜRÜYOR — ok ekranın kenarına
     yapışıyor, yarısı sayfa payının dışında kalıyordu. Telefonda görünmüyor (bu blok yalnız
     `pointer:fine`), ama dar bir masaüstü penceresi tam bu hâle düşüyor.
     Yer kalmadığında ok İÇERİ alınıyor: kartın kenarını bir tık örtmek, ekrandan taşmaktan
     iyidir. Kırılım `--grid-margin`in düştüğü nokta ile aynı — iki sayı birlikte hareket eder. */
  @media (max-width:640px){
    .hero-step--prev{left:var(--space-2)}
    .hero-step--next{right:var(--space-2)}
  }
  /* Klavye YOLU AYRI: oklar yalnız hover'da açılsaydı, sekme ile gelen kullanıcı görünmez bir
     düğmeye odaklanırdı (WCAG 2.4.11). Odak da açar. */
  .hero:hover .hero-step,
  .hero-step:focus-visible{opacity:1;visibility:visible}
  /* Ray sınırında ilgili ok GİZLENİR (JS `hidden` yazar) — basılınca hiçbir şey yapmayan kontrol
     tutulmaz. Ayrı bir kural gerekmiyor: global `[hidden]{display:none!important}` bunu zaten
     yapıyor ve buraya ikinci bir gizleme yolu yazmak, bir gün ikisinin ayrışması demekti. */
}

/* ---------- BANNER / KAMPANYA ----------
   Kampanya kataloğu bastırmaz: hero tek satır yüksekliğinde, ürünler fold içinde kalır.
   Otomatik dönen carousel YOK — §A6.1 (bilgi taşımayan hareket) ve Baymard bulgusu:
   kendiliğinden dönen şeritler hem kaçırılır hem rahatsız eder. Kullanıcı kaydırır. */
.bnr-slot{display:grid;gap:var(--space-3);margin-bottom:var(--space-6)}
/* --bnr-min 320 px: 360 px ekranda ikinci kartın kenarı hiç görünmüyor, ray
   tek karttan ibaret sanılıyordu (kaydırılabilirlik göstergesi yok = §H4). */
@media (max-width:640px){:root{--bnr-min:264px}}
.bnr-slot--rail{grid-auto-flow:column;grid-auto-columns:minmax(var(--bnr-min),1fr);
  overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scrollbar-width:none;
  margin-top:var(--space-6);padding-bottom:var(--space-1);margin-bottom:var(--space-4)}
.bnr-slot--rail::-webkit-scrollbar{display:none}
.bnr-slot--rail>*{scroll-snap-align:start}

/* [KALDIRILDI] Burada `.bnr` bileşeni vardı: 56 px'lik görsel + veritabanından gelen başlık
   ve açıklama satırı. Hero dışındaki altı yerleşimi o çiziyordu, yani aynı banner kaydı sitenin
   bir yerinde "içine yazı gömülü afiş", başka yerinde "ikonlu metin satırı" oluyordu. Metin
   alanlarını hiçbir başka yüzey çizmiyordu ve afişin içindeki yazı 56 px'te okunmuyordu.
   Artık banner her yerde afiş: bu yerleşimler `BannerSlot/Single` ile `.hslide` basıyor.
   `.bnr-slot` ve `.bnr-slot--rail` KALDI — Single'ın kabı olarak kullanılıyorlar. */

/* ---------- uygulama tanıtımı ----------
   Sessiz şerit: marka rengi zemin ama hero değil, katalogdan sonra gelir.
   Yapışkan banner / tam ekran katman YOK (§H3). */
/* UYGULAMA TANITIMI — SAYFA İÇERİĞİ, footer değil.

   [KUSUR 2026-08-13 · Eyüp, iki turda] Önce blok `main.wrap` içinde 1280 px'e hapsolmuş koyu
   yeşil bir dikdörtgendi ve altındaki 1512 px'lik footer'la AYNI rengi paylaşıp ona sıfır
   boşlukla dayanıyordu: iki yanda beyaz çentik bırakan kırık bir leke ("dip dipe girmiş").
   Sonra tam kanama yapıp layout'a taşıdım — çentik gitti, bu sefer "sanki footer içeriği gibi
   duruyor" oldu. Doğruydu: aynı koyu yeşilin iki sınırsız bandı alt alta gelince, aralarındaki
   saç teli çizgiye rağmen TEK bir koyu bölge okunuyor.

   Asıl mesele renk değil SINIR. Blok chrome değil, sayfanın son içerik bloğu; o hâlde sayfa
   içeriği gibi davranmalı: kendi kutusu, yuvarlak köşesi ve etrafında açık zemin. Kart olunca
   koyu olması sorun olmaktan çıkıyor — sayfada tam kanama tek bir koyu bölge kalıyor: footer.
   Alt boşluğu `main`in alt payından geliyor (64 px, bkz. `main.wrap` notu).

   Dolgu KARTIN kendisinde: blok artık `main.wrap`ın içinde, yani girintiyi kapsayıcı zaten
   verdi. `.apppromo-in`in ikinci kez `padding-inline` uygulaması, başlığı sayfanın diğer
   başlıklarından 64 px sağa kaydırırdı — eski notun anlattığı kusur tam olarak buydu. */
.apppromo{background:var(--pine-900);color:var(--pine-100);
  border-radius:var(--radius-2xl);padding:var(--space-12);margin-top:var(--space-16)}
@media (max-width:640px){
  .apppromo{padding:var(--space-8) var(--space-6);margin-top:var(--space-8)}
}
.apppromo-in{display:grid;grid-template-columns:1.15fr .85fr;gap:var(--space-12);
  align-items:center}
@media (max-width:1024px){.apppromo-in{grid-template-columns:1fr;gap:var(--space-8)}}
.apppromo-tx{display:grid;gap:var(--space-4);max-width:52ch}
.apppromo h2{color:var(--on-dark)}
.apppromo p{line-height:var(--lh-body)}
.apppromo-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3)}
/* [BÜYÜDÜ 2026-08-13] 14 px'ti. Bölümdeki her şey — paragraf, maddeler, rozetler — aynı küçük
   puntodaydı ve blok, sayfanın geri kalanının yanında fısıldıyordu. İki madde kaldı, ikisi de
   gövde puntosunda: daha az içerik + daha büyük ölçek. */
.apppromo-list li{display:flex;align-items:center;gap:var(--space-3);
  font-size:var(--text-body);color:var(--on-dark)}
.apppromo-list svg{color:var(--pine-400);flex:none}
.apppromo .stores{margin-top:var(--space-2)}
.apppromo .store{border-color:var(--pine-700);background:var(--pine-700)}
.apppromo .store:hover{border-color:var(--pine-400);background:var(--pine-700)}

/* şematik telefon — görsel varlık gerektirmeden bildirimi anlatır */
.apppromo-art{display:grid;place-items:center}
@media (max-width:1024px){.apppromo-art{display:none}}   /* dar ekranda süs, taşımaz */
/* Yükseklik İÇERİKTEN gelir; sabit oran verince ekranın altı boş kalıyor ve
   bölüm gereğinden uzun duruyordu. */
.phone{width:var(--phone-w);border-radius:var(--space-8);
  background:var(--pine-700);padding:var(--space-3);
  box-shadow:var(--elev-phone);border:var(--border-emphasis) solid var(--pine-500)}
.phone-scr{border-radius:var(--space-6);background:var(--pine-900);
  padding:var(--space-4);display:grid;gap:var(--space-3)}
.phone-note{display:flex;gap:var(--space-3);align-items:center;background:var(--surface);
  color:var(--text);border-radius:var(--radius-lg);padding:var(--space-3);
  box-shadow:var(--elev-card)}
.phone-note svg{color:var(--primary);flex:none}
.phone-note span{display:grid;line-height:var(--lh-none);gap:var(--space-1)}
.phone-note b{font-size:var(--text-caption);font-weight:var(--w-bold)}
.phone-note small{font-size:var(--text-micro);color:var(--text-2)}
.phone-note--dim{opacity:.45}

/* ---------- site footer ---------- */
/* Tanıtım ve footer aynı koyu zemin — aralarında 208 px açık şerit dikiş gibi
   duruyordu; artık bitişik akarlar (§B11). */
/* Üst pay 64 → 48. Footer'ın üstünde ZATEN `main`in 64 px'lik alt payı var (bkz. `main.wrap`);
   ikisi üst üste binince sayfa ile altbilgi arasında 128 px'lik bir delik oluşuyordu.
   Sınırı iki kez çizmemek için: nefes dışarıda, iç pay içeride. */
/* ---------- Android uygulama şeridi ---------- */
/* Yalnız Android'de basılıyor (bileşen karar veriyor). Biçim iOS'un Smart App Banner'ına yakın:
   solda kapatma, sonra ikon, ad + tek satır gerekçe, sağda eylem. Tanıdık kalıp yeniden
   icat edilmiyor.
   Yapışkan DEĞİL: üst çubuğun üstüne binen ikinci bir kalıcı katman olurdu. Kaydırınca gider. */
.appbar{display:flex;align-items:center;gap:var(--space-3);
  padding:var(--space-2) var(--grid-margin);
  background:var(--quiet);border-bottom:var(--border-hairline) solid var(--divider)}
.appbar-x{background:none;border:0;padding:var(--space-1);cursor:pointer;color:var(--text-2);
  display:grid;place-items:center;flex:none;
  /* Görünen ikon küçük, dokunma alanı tam: şeridin en sık basılan kontrolü bu. */
  width:var(--tap-min);height:var(--tap-min);margin-inline-start:calc(var(--space-2) * -1)}
.appbar-x svg{width:var(--icon-md);height:var(--icon-md)}
.appbar-ico{border-radius:var(--radius-md);flex:none;display:block}
.appbar-tx{display:grid;min-width:0;line-height:var(--lh-snug)}
.appbar-tx b{font-size:var(--text-label);font-weight:var(--w-bold)}
/* Gerekçe tek satır ve taşarsa kırpılır: şerit iki satıra çıkarsa ilk ekranı yemeye başlar. */
.appbar-tx small{font-size:var(--text-micro);color:var(--text-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.appbar-cta{flex:none;margin-inline-start:auto}

.site-foot{background:var(--pine-900);color:var(--pine-200);
  padding-block:var(--space-12) var(--space-8);font-size:var(--text-label)}
@media (max-width:640px){.site-foot{padding-block:var(--space-8)}}

/* ASGARİ ALTBİLGİ — ödeme akışı ve hesap ekranları (bkz. SiteFooterViewComponent).
   Aynı koyu zemin, çünkü sayfanın kapanışı hâlâ o; değişen İÇERİK MİKTARI, kimlik değil.

   [KUSUR 2026-08-14 · Eyüp: "yine çok fazla yer kaplamıyor mu?" · ölçüldü, HAKLIYDI]
   Bu blok temel `.site-foot` kuralından ÖNCE duruyordu ve ikisi aynı özgüllükte olduğu için
   buradaki `padding-block` küçültmesi HİÇ UYGULANMIYORDU — kaskadta sonraki kazanır. Ölçüm:
   toplam 126 px'in 80 px'i (%63) yalnız boşluktu, içerik 46 px. Blok temel kuraldan SONRAYA
   alındı; pay da dipnota yakışan ölçüye indi (24/16).
   Ders: bir varyantı temel kuralın önüne yazmak, onu sessizce ölü bırakır.

   [İKİNCİ KUSUR · aynı gün] Taşıma sırasında yorumun KAPANIŞINDAN SONRA başıboş bir metin
   satırı kalmıştı. CSS ayrıştırıcısı geçersiz metni görünce ondan sonraki kuralı da düşürüyor —
   yani `.site-foot--min` tarayıcıya HİÇ ULAŞMIYORDU (ölçüldü: sayfada yalnız temel kural
   parse edilmiş görünüyordu). Aynı hatanın iki farklı biçimi: biri kaskadta, biri sözdiziminde. */
.site-foot--min{padding-block:var(--space-6) var(--space-4)}
.foot-min{display:flex;align-items:center;justify-content:space-between;gap:var(--space-6);
  flex-wrap:wrap;font-size:var(--text-caption)}
.foot-min-legal{display:grid;gap:var(--space-1);color:var(--pine-200)}
.foot-min-legal a{color:var(--on-dark);text-decoration:none}
.foot-min-legal a:hover{text-decoration:underline}
.foot-min-links{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);align-items:center}
/* Dokunma hedefi tam altbilgideki kuralla aynı — dipnot olması küçültmeyi haklı çıkarmaz (§E). */
.foot-min-links a{color:var(--pine-200);text-decoration:none;display:inline-flex;align-items:center;
  gap:var(--space-2);min-height:var(--tap-min)}
.foot-min-links a:hover{color:var(--on-dark)}
.foot-min-links svg{width:var(--icon-sm);height:var(--icon-sm);color:var(--pine-400)}
@media (max-width:640px){
  .foot-min{flex-direction:column;align-items:flex-start;gap:var(--space-3)}
}

/* GÜVEN BANDI — footer'ın ilk satırı (işaretlemedeki gerekçe: dört madde de doğrulanabilir).
   Dört eşit sütun: maddeler eşit ağırlıkta, çünkü aralarında hiyerarşi YOK — dördü de aynı
   soruya ("bu dükkâna güvenilir mi") aynı büyüklükte cevap veriyor. Ayrı bir kutu/zemin
   verilmiyor: bant footer'ın bir satırı, üstüne binen bir kart değil (§B9.2). */
/* [DARALDI 2026-08-13] Alt payı 48 px'ti (`--space-12`). Bant ile marka bloğu arasında bir
   ayırıcı çizgi ZATEN var; çizginin iki yanında 32+48 px boşluk tutmak, sınırı iki kez
   çizmek oluyordu. Ölçekte bir kademe aşağı. */
/* [KUSUR 2026-08-13 · Eyüp: "bu yapının tasarımı amatör duruyor" · ÖLÇÜLDÜ]
   Şema `repeat(4,1fr)` idi: dört eşit hücre, her biri 302 px. İçindeki metinler ise 115 / 130 /
   99 / 136 px — yani her hücrenin YARISI boş ve artan pay hücreden hücreye değişiyordu
   (151/136/167/130). Maddeler sola çakılı, sağ kenarları tırtıklı: dört etiket bir satıra
   saçılmış gibi duruyordu, bant gibi değil.

   `auto` sütun + `space-between`: hücre yok, maddeler metinleri kadar yer alıyor ve ARTAN BOŞLUK
   ARALARA EŞİT dağılıyor. Kazanç yalnız ritim değil, hizalama da: ilk madde içerik kenarına
   yaslanıyor (altındaki logoyla aynı hizada), sonuncusu sağ kenara ("Bize ulaş" sütunuyla aynı
   hizada). Bant böylece altındaki ızgaraya bağlanıyor — havada duran bir satır olmaktan çıkıyor. */
.foot-assure{display:grid;grid-template-columns:repeat(4,auto);justify-content:space-between;
  gap:var(--space-6);
  padding-bottom:var(--space-6);margin-bottom:var(--space-8);
  border-bottom:var(--border-hairline) solid var(--pine-700)}
/* İki sütun, tek sütun DEĞİL: dört kısa etiket alt alta dizilince footer'ın en üstünde
   gereksiz 200 px'lik bir liste oluyor ve bant "bant" olmaktan çıkıyor. */
@media (max-width:1024px){.foot-assure{grid-template-columns:repeat(2,auto);gap:var(--space-4) var(--space-6)}}
.assure{display:flex;align-items:center;gap:var(--space-3);color:var(--on-dark);
  font-weight:var(--w-semibold);line-height:var(--lh-snug)}
/* İkon pine-400'de kalır: ikon kontrast eşiği 3:1 ve bu ton onu geçiyor; METİN beyaz olduğu
   için okunurluk metinden geliyor (aynı ayrım `.foot-col svg` notunda da anlatılıyor). */
.assure svg{color:var(--pine-400);flex:none}

/* Beş blok dörde indi (bkz. işaretlemedeki "Yasal" notu): marka + üç sütun. */
/* Marka + DÖRT gezinme sütunu (3/3/5/4). Marka 1,5fr: logo, cümle ve iki mağaza rozeti
   taşıyor, bağlantı listelerinden geniş olması gerekiyor.

   BLOK SAYISI DEĞİŞİNCE ŞEMA DA DEĞİŞİR — bu dosyada aynı hataya iki kez düşüldü (üst çubukta
   arama kalkınca `1fr auto 1fr` kaldı, burada Yasal inince `1fr 1fr` kaldı ve boş hücre üretti).
   Beş blok: `1.5fr repeat(4,1fr)`.

   `align-items:start`: sütunlar birbirini GERMİYOR. Önceden hepsi en uzun sütunun yüksekliğine
   (443 px) uzuyordu; ölçüldüğünde marka %51, manavda %59, iletişim %47 boş çıkmıştı. */
/* Sütunlar genişliği EŞİT PAYLAŞIR; marka 1,5 pay (logo, cümle ve iki rozet taşıyor).

   [GERİ ALINDI 2026-08-13 · Eyüp: "ortayı bomboş yapmışsın"] Bir tur boyunca burada
   `minmax(0,1fr) repeat(4,auto)` yazdı: listeler metinleri kadar yer alsın, artan boşluğu marka
   sütunu yutsun diye. Ölçüm doğruydu (sütun kutuları içeriklerinden 84–117 px genişti) ama
   ÇIKARIM yanlıştı — o boşluk kusur değil, sütun ritminin kendisiydi. Toplayınca marka ile
   menüler arasında 350 px'lik tek bir delik açıldı ve footer ikiye bölündü.
   Sütun içindeki artan yer, satırların sola hizalı akmasını sağlayan normal payıdır; asıl
   sıkıştırılacak yer DİKEY aralıklardı (bkz. `.foot-col` ve `.foot-col a`). */
.foot-top{display:grid;grid-template-columns:1.5fr repeat(4,1fr);
  column-gap:var(--space-6);row-gap:var(--space-8);align-items:start}
/* 1024'ün altında marka ile dört liste yan yana durmuyor: marka tam satır, listeler eşit
   dörtte bir. Burada `1fr` DOĞRU — tek satırda dört liste varken içerik genişliği kullanmak
   onları sola yığar ve sağda tek bir büyük delik bırakır. */
@media (max-width:1024px){
  .foot-top{grid-template-columns:repeat(4,1fr);column-gap:var(--space-6)}
  .foot-brand{grid-column:1 / -1;margin-bottom:var(--space-6)}
}
/* [DEĞİŞTİ 2026-08-13] İki sütuna geçiş 1024'te oluyordu; o kırılım DÖRT blok içindi. Blok üçe
   inince 1024 px'lik ekranda üçü rahat sığıyor (içerik 960 → 411/274/274; "info@manavda.com"
   274 px'e tam oturuyor) ve iki sütunda kalmak, üçüncü bloğu tek başına alt satıra atıp yanında
   boş hücre bırakıyordu. Geçiş 768'e indi: orada sütun 336 px'e düşüyor ve marka bloğunun iki
   mağaza rozeti (2×128 + oluk) ancak sığıyor. */
@media (max-width:768px){.foot-top{grid-template-columns:1fr 1fr}}
/* Dar ekranda da İKİ SÜTUN — tek sütun değil.

   [ÖLÇÜLDÜ 2026-08-13] Bir ara burada `1fr` yazıyordu ve o sırada DOĞRUYDU: yasal linkler alt
   banda inmişti, geriye üç blok kalmıştı ve iki sütunda üçüncüsünün yanı boş kalıyordu.
   Linkler sütunlara dönünce blok sayısı beşe çıktı; tek sütun bu sefer footer'ı 390 px'te
   1395 px'e şişirdi — dört kısa listeyi alt alta dizmek, dördünün de yarım satır genişliğinde
   olduğu bir ekranda saf israf.
   Beş blok iki sütunda 1/2/2 diziliyor: boş hücre yok. En uzun etiket ("Pazarlama açık rızası")
   390 px'te 171 px'lik sütuna sığıyor — ölçüldü, sarma yok. */
@media (max-width:640px){
  .foot-top{gap:var(--space-6) var(--space-4)}
}
/* [KUSUR 2026-08-12 · ölçüldü] gap 4 px'ti. Linklerin KENDİSİ 44 px (aşağıda düzeltilmiş) ama
   komşu hedefler arası boşluk kılavuzun §A9 eşiğinin (≥8 px) altındaydı: yükseklik yeterli olsa
   bile bitişik iki hedef, parmakla yanlış olanı seçtirir. Taranan her sayfada aynı kusur —
   tek bileşende düzeltilip sitenin tamamına yayılıyor. */
/* [SIKILAŞTI 2026-08-13 · Eyüp: "alt üst boşlukları, iki item arasında"] Satır aralığı 38 px'ti
   (30 px kutu + 8 px oluk) ve 14 px'lik bir bağlantı listesi için fazlaydı — Getir'in aynı
   listesi 16 px. Kutu 30'du çünkü dokunma tabanı 24 px'in ÜSTÜNE bir de 4+4 dolgu biniyordu;
   dolgu kalktı, taban 24 px olduğu gibi duruyor (WCAG 2.5.8 sınırı) ve oluk komşu hedefleri
   ayırmaya devam ediyor. Satır 38 → 32.
   Başlık payı da 12 → 8: başlık listenin PARÇASI, ayrı bir bölüm değil. */
.foot-col{display:grid;gap:var(--space-2);align-content:start}
.foot-col h2{color:var(--on-dark);font-size:var(--text-caption);font-weight:var(--w-bold);
  letter-spacing:var(--tr-label);text-transform:uppercase;margin-bottom:var(--space-2)}
/* DOKUNMA HEDEFİ GİRDİ CİHAZINA BAĞLI — footer'ın yüksekliğini belirleyen kural buydu.

   [KUSUR 2026-08-13 · Eyüp: "acayip boşluklar" · ÖLÇÜLDÜ] Burada `min-height:var(--tap-min)`
   (44 px) yazıyordu ve gerekçesi kendi yorumunda duruyordu: "hele MOBİLDE footer başparmakla
   dokunulan yer". Sebep doğru, kapsam yanlıştı: kural HER genişlikte uygulanıyordu.

   Bedeli ölçüldü (1512 px): 44 px hedef + 8 px oluk = satır başına 52 px. Sekiz yasal bağlantı
   × 52 = 416 px, yani sütunun 443 px'inin tamamı. Kıyas için Getir'in aynı satırı 16 px.
   Footer 883 px'e çıkıyordu — 729 px'lik ekranın %121'i, tek başına bir sayfadan uzun.

   Fareyle gezilen bir yüzeyde 44 px hedef tutmanın karşılığı YOK: imleç piksel hassasiyetinde.
   WCAG 2.5.8'in sert tabanı 24 px ve `--tap-box` tam olarak o. Parmakla dokunulan cihazda
   (`pointer:coarse`) 44 px geri geliyor — kural mobilde neden konduysa orada duruyor.

   Sorgu GENİŞLİĞE değil GİRDİ CİHAZINA bakıyor: mesele ekranın darlığı değil, parmak olup
   olmadığı. Aynı ayrım `.hero-track`ta da kullanılıyor. */
.foot-col a{color:var(--pine-200);text-decoration:none;padding-block:0;
  min-height:var(--tap-box);
  display:flex;align-items:center;gap:var(--space-2);
  transition:color var(--dur-micro) var(--ease-out)}
@media (pointer:coarse){
  .foot-col a{padding-block:var(--space-2);min-height:var(--tap-min)}
}
.foot-col a:hover{color:var(--on-dark)}
.foot-col svg{width:var(--icon-sm);height:var(--icon-sm);color:var(--pine-400)}
/* pine-400 metinde 4.30:1 kalıyordu; ikon eşiği (3:1) için yeterli ama METİN 4.5 ister.
   Metinler pine-200'e (7.75:1), ikonlar pine-400'te kalır. */
/* `.foot-reach .hours` KALDIRILDI: destek saati güven bandına taşındı, kuralın tuttuğu öğe
   artık basılmıyor. Karşılığı olmayan sınıf bırakılmıyor (§6.3b). */
.foot-brand .logo{margin-bottom:var(--space-3)}
.foot-brand p{max-width:var(--measure);line-height:var(--lh-body);margin-bottom:var(--space-4)}
/* mağaza rozeti — düz metin kutusu değil, gerçek rozet geometrisi */
/* [DEĞİŞTİ 2026-08-13] ALT ALTA idi (`inline-grid`), iki rozet 2×47 px yer yiyordu ve marka
   sütununu gereksiz uzatıyordu. Yan yana geldiklerinde aynı bilgi tek satıra iniyor.
   `flex-wrap` şart: dar ekranda ikisi sığmazsa alt alta düşerler, taşmazlar. */
.stores{display:flex;flex-wrap:wrap;gap:var(--space-2)}
/* [KUSUR 2026-08-13 · Eyüp'e gelen iki incelemede de: "rozetler yeşilin içinde kayboluyor"]
   Kenarlık `--pine-700`dü ve footer zeminine (`--pine-900`) karşı kontrastı ÖLÇÜLDÜ: 1,65:1.
   Yani rozetin çerçevesi ekranda yok hükmündeydi; görünen tek şey içindeki beyaz yazıydı ve
   rozet "rozet" gibi durmuyordu.
   `--pine-400` bu footer'da zaten ikon rengi ve gerekçesi aşağıda yazılı: metin eşiğini (4,5)
   tutmaz ama grafik öğe eşiğini (3:1) rahat geçer — ölçüldü, 4,30:1. Yeni bir renk uydurmak
   yerine aynı işi yapan mevcut token kullanılıyor. */
.store{display:inline-flex;align-items:center;gap:var(--space-2);text-decoration:none;
  border:var(--border-hairline) solid var(--pine-400);border-radius:var(--radius-md);
  padding:var(--space-2) var(--space-3);color:var(--on-dark);
  transition:border-color var(--dur-micro) var(--ease-out),
    background var(--dur-micro) var(--ease-out)}
.store:hover{border-color:var(--pine-400);background:var(--pine-700)}
.store svg{width:var(--icon-lg);height:var(--icon-lg);color:var(--on-dark)}
.store span{display:grid;line-height:var(--lh-none);text-align:left}
.store small{font-size:var(--text-micro);color:var(--pine-200);font-weight:var(--w-semibold)}
.store b{font-size:var(--text-caption);font-weight:var(--w-bold)}
/* ALT BANT — künye + yasal metinler solda, ödeme rozeti sağda.

   [BİRLEŞTİ 2026-08-13] Burada üç ayrı kat vardı: `.foot-trust` (ödeme bandı, kendi üst VE alt
   çizgisiyle, 100 px) + `.foot-legal` (künye, 70 px) + aralarındaki 24 px. Üçü de aynı soruya
   cevap veriyor ("bu dükkân kim, neye dayanıyor") ama üst üste dizilince footer'ın dibinde
   ayrı bir bölüm açılıyordu.

   Yatay alan zaten boştu: ödeme bandı 520 px'lik bir şerit, sağındaki ~700 px kullanılmıyordu.
   Yan yana koyunca bandın yüksekliği ikisinin TOPLAMI değil BÜYÜĞÜ oluyor.

   Tek çizgi kaldı — bandın üstünde. Güven bandının altındaki çizgiyle birlikte footer'da iki
   çizgi var: üç katmanı ayıran iki sınır. `.foot-trust`un hem üst hem alt çizgisi vardı ve
   altındaki künye zaten sayfanın sonuydu; bir şeyi hiçbir şeyden ayıran çizgi süstür. */
/* Künye SOLDA, ödeme rozeti SAĞDA — tek satırlık bir kapanış bandı.
   `align-items:center`: iki öğe farklı yükseklikte (künye bir satır, rozet bant+not) ve
   ortadan hizalanınca bant tek bir çizgi gibi okunuyor. */
.foot-bottom{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-8);
  align-items:center;margin-top:var(--space-8);padding-top:var(--space-6);
  border-top:var(--border-hairline) solid var(--pine-700)}
/* Dar ekranda alt alta: künye ve rozet yan yana sıkışırsa ikisi de okunmaz. */
@media (max-width:1024px){.foot-bottom{grid-template-columns:1fr;gap:var(--space-6);
  justify-items:start}}

/* Ödeme rozeti: bant + altındaki not. Doğru ilişki dikey — not, bandın açıklaması. */
.foot-pay{display:grid;gap:var(--space-2);justify-items:start}
@media (min-width:1025px){.foot-pay{justify-items:end;text-align:right}}
/* `.trust-lbl` KALDIRILDI 2026-08-13: taşıdığı tek öğe ("GÜVENLİ ÖDEME" etiketi) güven bandına
   taşındı ve sınıf hiçbir görünümde kalmadı (tarandı). Karşılığı olmayan sınıf bırakılmıyor.

   DERSİ SAKLIYORUM, çünkü kuralı olan bir tuzak: bu etiketin rengi iki kez yanlış ayarlandı.
   Önce --pine-400'dü, ödeme adımında kontrast 4,30:1 ölçüldü (11 px metin için eşik 4,5).
   --pine-600'e çevrildi; bu sefer FOOTER'da 1,85:1 oldu — çünkü aynı sınıf iki farklı zeminde
   geçiyordu: ödemede açık yüzey, footer'da koyu yeşil. TEK SABİT RENK İKİSİNE BİRDEN YETMEZ ve
   bir sayfaya bakarak global renk değiştirmek öbürünü kırar. Doğrusu `currentColor`: öğe,
   içinde bulunduğu bloğun metin rengini devralır. Aynı tuzak `.pay-note`ta da anlatılıyor. */
/* Ödeme bandı — kart markalarının GERÇEK logoları (eski landing'den).
   Bant koyu yeşil zemine geliyor ve içindeki logolar beyaz/renkli; ayrı bir kutu ya da zemin
   verilmiyor — SVG kendi boşluğunu taşıyor. Dar ekranda küçülür ama oranı korunur; `width`/
   `height` işaretlemede yazılı olduğu için yer önceden ayrılıyor, düzen kaymıyor.
   [ESKİSİ] Buradaki `.pay-marks` düz METİN rozetleriydi (beyaz kutu içinde "Visa" yazısı).
   Kaldırıldı: ödeme rozetinin işi tanınmak, okunmak değil. */
/* [BÜYÜDÜ 2026-08-13] Tavan 444 px'ti (`--search-max + --space-16`) ve yanındaki "GÜVENLİ ÖDEME"
   etiketiyle yer paylaşıyordu. Etiket güven bandına taşınınca satır boşaldı; tavan `--field-w`
   (520 px) oldu — yeni bir sayı uydurulmadı, ölçekteki mevcut genişlik token'ı kullanıldı.
   Rozetin tek işi TANINMAK: 444 px'de dört kart markası ~11 px yüksekliğe düşüyordu. */
.pay-band{display:block;height:auto;width:100%;max-width:var(--field-w)}
/* Bandın yanındaki açıklama. `.fine` KULLANILMADI ve sebebi ölçüldü: o sınıf AÇIK yüzeyler için
   yazılmış (rgb(74,92,85)) ve koyu footer zemininde kontrast 1,79:1 çıkıyor — okunmuyor.
   Aynı tuzak `.trust-lbl` yorumunda da anlatılıyor: bir sınıf iki farklı zeminde geçiyorsa tek
   sabit renk ikisine birden yetmez. Renk bloktan devralınıyor (7,75:1, ölçüldü). */
.pay-note{color:currentColor;font-size:var(--text-caption);margin:0}
/* .socials KALDIRILDI (denetim H2): iki ölü href="#" bağlantısıydı; hesaplar açılınca
   gerçek adresleriyle geri gelir. */
/* [KONTRAST 2026-08-08] --pine-400 koyu zeminde 4.30:1 veriyordu, AA eşiği 4.5.
   Bu satırlar satıcı kimliği — mesafeli satışta okunabilir olmak zorunda.
   Hiyerarşi RENKLE değil BOYUTLA kuruluyor: punto zaten --text-caption. */
/* KÜNYE TEK SATIR — üç künye alanı yan yana, aralarında nokta ayraç.
   `flex-wrap` şart: dar ekranda üç alan sığmazsa alt alta düşerler, taşmazlar. Ayraç sözde-öğe
   ile basılıyor — işaretlemede ayraç karakteri olsaydı ekran okuyucu araya "orta nokta" okur ve
   kopyalanan metne karışırdı. Sondan sonra ayraç yok. */
.foot-legal{display:flex;flex-wrap:wrap;align-items:center;
  column-gap:var(--space-2);row-gap:var(--space-1);
  font-size:var(--text-caption);color:var(--pine-200)}
.foot-legal > span:not(:last-child)::after{content:"·";margin-left:var(--space-2);
  color:var(--pine-400)}
/* Künyedeki unvan bağlantısı. Altı çizili DEĞİL ama `currentColor`dan ayrışıyor: künye satırı
   okunmak için değil doğrulanmak için var, dolayısıyla bağlantı fark edilebilir olmalı ama
   satırın sakinliğini bozmamalı. `.foot-col a` deseninin aksine burada dokunma alanı
   büyütülmüyor — bu bir gezinme hedefi değil, künye içinde tek bir atıf. */
.foot-legal a{color:var(--on-dark);text-decoration:none}
.foot-legal a:hover{text-decoration:underline}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:1ms!important;animation-iteration-count:1!important;
    transition-duration:1ms!important}
}
