/* ──────────────────────────────────────────────────────────────
   TAM — design tokens
   Light: Apple-ish system surfaces. Dark: elegant near-black.
   Density adjusts spacing+font scale globally.
   ────────────────────────────────────────────────────────────── */

:root {
  --accent: #0a84ff;
  --accent-soft: rgba(10, 132, 255, 0.14);

  /* Bottom safe-area handle — TARAYICIDA env=0 (etkisiz). PWA standalone'da
     env(~34) değerini direkt kullanmak yerine kompakt ayara çekiyoruz. */
  --bottom-inset: env(safe-area-inset-bottom);
  /* Tabbar dikey ofseti — TEK kaynak. PWA'da --pwa-tabbar-shift olarak override
     edilir; --tabbar-shift hem @media hem .is-standalone kuralında AYNI değişkeni
     okur (önceki çakışmayı önler). Negatif = aşağı kaydır, pozitif = yukarı. */
  --pwa-tabbar-shift: 0px;     /* ← PWA için ayarlamak istediğin TEK SAYI */
  --tabbar-shift: 0px;          /* tarayıcı default */

  /* Surfaces */
  --bg: #f3f3f7;
  --bg-elev: #ffffff;
  --bg-overlay: rgba(245, 245, 247, 0.78);
  --surface-2: #ebebef;
  --surface-3: #e2e2e7;

  /* Text */
  --text: #0a0a0c;
  --text-2: #6e6e73;
  --text-3: #aeaeb2;
  --text-on-accent: #ffffff;

  /* Lines */
  --hairline: rgba(60, 60, 67, 0.12);
  --hairline-2: rgba(60, 60, 67, 0.08);

  /* Status colors */
  --green: #34c759;
  --orange: #ff9500;
  --red: #ff3b30;
  --amber: #ffcc00;
  --purple: #af52de;
  --pink: #ff2d55;
  --teal: #5ac8fa;

  /* Density (rahat by default) */
  --density: 1;            /* 1 = comfortable, 0.86 = compact */
  --r-card: 18px;
  --r-tile: 14px;
  --r-pill: 999px;
  --r-sheet: 22px;

  /* Shadows — very subtle */
  --shadow-sm: 0 1px 2px rgba(15, 15, 20, 0.05), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
  --shadow-md: 0 2px 6px rgba(15, 15, 20, 0.05), 0 8px 24px rgba(15, 15, 20, 0.06);
  --shadow-lg: 0 12px 40px rgba(15, 15, 20, 0.14), 0 2px 8px rgba(15, 15, 20, 0.06);

  /* iOS status-bar contrast */
  --status-fg: #000;

  /* ── HAREKET SÖZLÜĞÜ (tek kaynak) ───────────────────────────────
     ÖLÇÜM (2026-08-30, gerçek Chrome, kare kare, 390×844):
     panelin her yerinde kullanılan cubic-bezier(.32,.72,0,1) APPLE'IN
     TAM EKRAN yolu için tasarlanmış bir eğridir. 390px'lik bir yolda
     harika: %90'ı ilk 130ms'de gider, kalan 40px 290ms boyunca zarifçe
     oturur. Ama panelde uygulandığı yollar KISA (ekran geçişi 20px,
     alt çubuk 92px). Aynı eğri 20px'e uygulanınca:

         38ms: -20px · 113ms: -7px · 245ms: -0.8px · 396ms: 0

     yani hareketin %90'ı 130ms'de bitiyor, geriye 290ms'lik GÖRÜNMEZ
     bir alt-piksel sürünme kalıyor. Kullanıcı bunu tek bir hareket
     olarak göremiyor: önce bir seğirme, sonra (metin GPU katmanından
     çıkıp keskinleştiğinde) gecikmeli ikinci bir "oturma".
     Bildirilen şikâyet tam olarak buydu: "animasyon kendini iki kez
     tekrarlıyor, ekran ufak titriyor".

     Düzeltme: yolu eğriye uydurmaya çalışmak yerine EĞRİYİ YOLA uydur.
     --ease-glide (easeOutSine) hareketi süreye YAYAR.

     ADAY EĞRİLER SAYISAL OLARAK KIYASLANDI (bezier çözülerek; ölçüt
     "yolun yarısı ne zaman bitiyor" ve "son 1px'e varıp da hâlâ ne kadar
     animasyon kalıyor" = ölü kuyruk):

       eğri                          yarı yol   ölü kuyruk   bitiş eğimi
       cubic-bezier(.32,.72,0,1)       %20        105 ms        0
       cubic-bezier(.22,.61,.36,1)     %20        105 ms        0
       easeOutQuad (.25,.46,.45,.94)   %28         65 ms      0.109  ✘
       easeOutSine (.61,1,.88,1)       %34         62 ms        0     ✔

     easeOutQuad kuyruğu kısaltıyor ama bitiş eğimi sıfır DEĞİL: hareket
     tam dururken hâlâ hızlı, yani "yumuşak" istenirken sert bir duruş
     kazanılıyordu. easeOutSine hem yolu en dengeli yayan hem de sıfır
     hızla inen tek aday. 22px'lik ekran, 81px'lik çubuk ve 46px'lik
     kapsül yollarının ÜÇÜNDE de en iyi sonucu veriyor.

     ⚠️ --ease-decel SİLİNMEDİ: uzun yolu olan yüzeyler (sheet'in tam
     ekran yükselişi) hâlâ onu kullanır — orada doğru eğri odur. */
  --ease-glide: cubic-bezier(0.61, 1, 0.88, 1);     /* kısa yol (≤120px) */
  --ease-decel: cubic-bezier(0.32, 0.72, 0, 1);     /* uzun yol (tam ekran) */
  --dur-screen: 320ms;   /* ekran geçişi */
  --dur-bar: 300ms;      /* alt çubuk / FAB gizlen-göster */
}

[data-theme="dark"] {
  --bg: #000000;
  --bg-elev: #1c1c1e;
  --bg-overlay: rgba(20, 20, 22, 0.72);
  --surface-2: #2c2c2e;
  --surface-3: #3a3a3c;

  --text: #ffffff;
  --text-2: rgba(235, 235, 245, 0.6);
  --text-3: rgba(235, 235, 245, 0.3);

  --hairline: rgba(84, 84, 88, 0.45);
  --hairline-2: rgba(84, 84, 88, 0.25);

  --accent-soft: rgba(10, 132, 255, 0.22);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5), 0 0 0 0.5px rgba(255, 255, 255, 0.04);
  --shadow-md: 0 2px 6px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.6);

  --status-fg: #fff;
}

/* Density */
[data-density="compact"] {
  --density: 0.88;
}

/* PWA standalone: tabbar'ı viewport'un en altına yapıştır.
   --bottom-inset = 0 → padding-bottom yok → tab label'lar ekranın en altına
   konumlanır. iOS home indicator pill (~5px alt-orta) sistem-üst layer'ında
   çizilir; tabbar üzerine bindirir ama dock görsel olarak dipte oturur.
   Tarayıcı modu bu bloktan etkilenmez (env=0 zaten oradaki değer).
   Hem CSS @media hem JS-eklenen .is-standalone (iOS apple-mobile-web-app-capable
   PWA'sında media query bazen match etmediği için, JS fallback). */
@media (display-mode: standalone), (display-mode: fullscreen), (display-mode: minimal-ui) {
  :root {
    --bottom-inset: 0px;
    --tabbar-shift: var(--pwa-tabbar-shift);
  }
}
html.is-standalone {
  --bottom-inset: 0px;
  --tabbar-shift: var(--pwa-tabbar-shift);
}

/* Reset-ish */
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: #1a1a1c; font-family: 'Inter', -apple-system, system-ui, sans-serif; -webkit-font-smoothing: antialiased; }
button { font: inherit; color: inherit; background: none; border: none; padding: 0; cursor: pointer; }
input, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
::-webkit-scrollbar { display: none; width: 0; height: 0; }
* { scrollbar-width: none; -ms-overflow-style: none; }

/* App canvas inside the device frame */
.tam-root {
  width: 100%;
  height: 100%;
  position: relative;
  background: var(--bg);
  color: var(--text);
  font-family: 'Inter', -apple-system, system-ui, sans-serif;
  font-feature-settings: 'cv11', 'ss01', 'ss03';
  letter-spacing: -0.012em;
  overflow: hidden;
}

/* Scroll container per screen */
.tam-scroll {
  position: absolute; inset: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding-top: 54px;       /* status bar */
  /* Floating .navbar (bottom:22 + height:54 = ~76px) + nefes payı.
     Tarayıcıda 102px; PWA standalone'da +--bottom-inset (home indicator).
     ⚠️ BAR YÜKSEKLİĞİ DEĞİŞİRSE BURASI DA DEĞİŞİR: bu üç sayı (bar
     yüksekliği · .bottom-scrim · .fab bottom) tek bir geometriyi
     anlatır; biri kalırsa ya içerik barın altında kalır ya da ekranın
     dibinde açıklanamayan bir boşluk doğar. */
  padding-bottom: calc(102px + var(--bottom-inset));
  /* Ekran `key` ile yeniden kurulduğunda tarayıcının işi bu kutuyla SINIRLI
     kalsın: `contain` olmadan yeni ağacın düzeni sayfanın geri kalanını da
     geçersiz kılıyor. `paint` zaten overflow ile fiilen vardı, `layout`
     kazancı getiren kısım. `style`/`size` BİLİNÇLİ OLARAK YOK: size
     containment kutuyu içeriğinden bağımsız ölçer ve kaydırma yüksekliğini
     bozar (kaydırma hafızası buna bağlı). */
  contain: layout paint;
}

/* Tap feedback */
.tap {
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.18s ease;
}
/* .tap-soft standalone bir varyant (§7) — kendi transition'ı olmadan :active
   snap atıyordu; aynı süre/eğri ile pürüzsüzleştir. */
.tap-soft {
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.18s ease;
}
.tap:active { transform: scale(0.97); opacity: 0.8; }
.tap-soft:active { transform: scale(0.985); opacity: 0.9; }

/* .tap-morph — SEÇİLDİĞİNDE RENK DEĞİŞTİREN dokunma hedefleri
   (Hizmetler'deki kategori kartları gibi). `.tap-soft` yalnız basma
   tepkisini taşır; arka plan, yazı rengi ve gölge inline olarak
   değiştiği için geçişsiz kalıyor ve seçim küt sıçrıyordu. Kullanıcı
   alt çubuğun yeni his kalitesini işaret edip aynısını burada da istedi
   (2026-08-30) — bu yüzden süre ve eğri UYDURULMAZ, kapsülün sözlüğü
   birebir kullanılır (--dur-screen + --ease-glide).
   ⚠️ transition TEK bildirimdir: `.tap-soft`la birlikte kullanılırsa
   sonraki kural öncekini bütünüyle ezer, o yüzden basma tepkisi de
   burada tekrar tanımlanır ve .tap-soft'un YERİNE geçer. */
.tap-morph {
  -webkit-tap-highlight-color: transparent;
  transition: background var(--dur-screen) var(--ease-glide),
              color 220ms linear,
              box-shadow var(--dur-screen) var(--ease-glide),
              transform 0.18s cubic-bezier(0.4, 0, 0.2, 1),
              opacity 0.18s ease;
}
.tap-morph:active { transform: scale(0.985); opacity: 0.9; }

/* .rise — bölüm bazlı "oturma" KALDIRILDI.
   ESKİDEN translateY(10px)→0 idi; kalabalık panel ekranlarında transform metni
   GPU katmanında grayscale AA ile çizip bitince keskin metne "küt" snap
   yaptırıyordu (harf oturması). Opacity fade denendi ama o da içeriği geçiş
   sırasında ŞEFFAF yapıp yandan-slide'ı görünmez kılıyordu. Çözüm: .rise
   etkisiz → içerik anında, TAM OPAK; sekme/ekran geçişinde yalnız .screen-enter
   yatay slide'ı oynar ve opak içerik kaydığı için net & yumuşak görünür.
   .rise-N gecikmeleri etkisiz (animasyon yok). */
.rise { animation: none; }

/* Skeleton shimmer */
@keyframes shimmer {
  from { background-position: -200% 0; }
  to   { background-position: 200% 0; }
}
.skel {
  background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-3) 50%, var(--surface-2) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.6s infinite linear;
  border-radius: 8px;
}

/* Cross-screen transitions — yandan slide KORUNUR (kullanıcı bunu istiyor).
   "Küt" his yatay slide'dan değil, bölümlerin dikey OTURMASINDAN (.rise
   translateY) geliyordu → yalnız .rise opacity'ye alındı. Slide tüm ekranı
   tek parça kaydırır; içerik bölümleri dikey snap yapmaz.

   İKİ AYRI ANİMASYON, TEK HAREKET (2026-08-30):
   Kayma ve solma tek keyframe'e "58% { opacity: 1 }" ara adımıyla
   yazılamaz — CSS'te easing HER SEGMENTE ayrı ayrı uygulanır, yani
   transform 58%'de bir kez yavaşlayıp yeniden hızlanır ve tam da
   kaçınmaya çalıştığımız hız tümseğini üretir. Bu yüzden kayma
   (screen-in) ve solma (screen-fade) AYRI animasyonlardır.

   ⚠️ SOLMA SIFIRDAN BAŞLAMAZ (0.62 → 1, 120ms). Önce 0 → 1 / 170ms idi
   ve HIZLI cihazda güzeldi; yavaş cihazda felaket oldu. Ölçüldü (CPU 6x
   kısıtlı): ekran `key` ile yeniden kurulurken commit ~150-250ms ana
   iş parçacığını tutuyor. Kullanıcı dokunuyor, ekran donuyor, donma
   bitiyor ve içerik OPACITY 0'DA doğuyor — yani beklemenin üstüne 170ms
   daha görünmezlik biniyor. Kullanıcının gördüğü "takıldı, sonra baştan
   oynadı" hissinin yarısı buydu. 0.62'den başlamak girişi hâlâ
   yumuşatır ama içerik ilk karede OKUNABİLİR gelir.
   (Eski .rise denemesinin tuzağı da buydu: içerik geçiş boyunca şeffaf
   kalınca slide hiç görünmüyordu.)

   `translate3d` bilerek: animasyon boyunca TEK ve kararlı bir kompozit
   katman ister; 2D translateX'te Chrome katmanı geç kurup geç bırakıyor
   ve bırakma anı metinde ayrı bir keskinleşme sıçraması olarak görünüyor. */
.screen-enter {
  animation: screen-in var(--dur-screen) var(--ease-glide) both,
             screen-fade 120ms linear both;
}
.screen-enter-back {
  animation: screen-in-back var(--dur-screen) var(--ease-glide) both,
             screen-fade 120ms linear both;
}
@keyframes screen-fade { from { opacity: 0.62; } to { opacity: 1; } }
@keyframes screen-in {
  from { transform: translate3d(22px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}
@keyframes screen-in-back {
  from { transform: translate3d(-22px, 0, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* PLATFORM ZATEN OYNATTIYSA BİZ OYNATMAYIZ (.screen-enter-still)
   Donanım geri tuşu, tarayıcı geri tuşu ve iOS/Android kenar-kaydırma
   jesti sayfayı KENDİSİ hareket ettirir: parmak sayfayı sağa çeker,
   navigasyon çözülünce platform onu sola geri oturtur. Bunun üstüne
   kendi yatay kaymamızı koyunca iki hareket arka arkaya ve TERS yönde
   geliyor; kullanıcı bunu "animasyon kendini tekrarlıyor" diye
   bildirdi (2026-08-30, Müşteriler → kart → kenar jestiyle geri).

   Ölçüm bu teşhisin ikinci yarısını da verdi: canlı derlemede bizim
   animasyonumuz TEK ve DOĞRU yöndeydi (-22px → 0). Yani sorun yönü
   düzeltmekle bitmiyordu; fazla olan hareketin kendisiydi.

   ⚠️ SOLMA DA KALDIRILDI (ikinci tur, kullanıcı bildirdi):
   Önce burada yalnız `screen-fade 0.62 → 1` bırakılmıştı. Yatay hareket
   gidince geriye kalan tek şey o oldu ve kullanıcı şunu gördü: "geri
   gelindiğinde ilk an son tıklanan müşteri kartına sanki yeniden
   tıklanıyor gibi bir animasyon giriyor." Haklı: solmanın görsel imzası
   ile basma tepkisinin imzası AYNI — ikisi de kararıp normale dönmek
   (.tap-soft:active zaten opacity 0.9). Açık zeminde beyaz kartlar
   kararıp geri gelince göz bunu, o an baktığı kartın basılması sanıyor.

   Doğru davranış zaten buydu: geçişi PLATFORM yapıyorsa uygulama hiçbir
   şey yapmaz. `animation: none` — içerik yerinde, anında, tam opak gelir.
   ⛔ "Çok kısa bir solma bıraksak" denmesin: süreyi kısaltmak imzayı
   değiştirmez, yalnız zayıflatır; sorun süre değil KARARMA.

   Ekran içi geri düğmesi .screen-enter-back ile eskisi gibi kayar:
   orada platformun bir animasyonu yoktur. */
.screen-enter-still { animation: none; opacity: 1; }

/* Hareket azaltma tercihi — giriş animasyonları kapanır, içerik anında görünür
   (opacity'ye geçtik; animasyon çalışmazsa içerik görünür kalsın). */
@media (prefers-reduced-motion: reduce) {
  .rise, .screen-enter, .screen-enter-back, .screen-enter-still { animation: none; opacity: 1; }
}

/* Sheet (modal) — `forwards`: animasyon koşamazsa öğe dinlenme konumunda kalsın.
   Yol TAM EKRAN (translateY 100%) olduğu için uzun yol eğrisi (--ease-decel)
   burada DOĞRUDUR; kısa-yol eğrisine çevrilmez. */
.sheet-enter { animation: sheet-up 0.36s var(--ease-decel) forwards; }
@keyframes sheet-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0); }
}
.sheet-bg-enter { animation: fade-in 0.36s ease forwards; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* Pop (small popovers) */
.pop-enter { animation: pop 0.24s cubic-bezier(0.2, 1.6, 0.4, 1) both; transform-origin: top center; }
@keyframes pop {
  from { opacity: 0; transform: scale(0.92); }
  to   { opacity: 1; transform: scale(1); }
}

/* Primitives — buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; height: 50px; padding: 0 22px;
  border-radius: var(--r-pill); font-weight: 600;
  letter-spacing: -0.01em; font-size: 16px;
}
.btn-primary { background: var(--accent); color: var(--text-on-accent); }
.btn-secondary { background: var(--surface-2); color: var(--text); }
.btn-ghost { background: transparent; color: var(--accent); }

/* Pills / chips */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px;
  border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--text);
  font-size: 13.5px; font-weight: 540;
  letter-spacing: -0.005em;
}
.chip-active { background: var(--text); color: var(--bg-elev); }

/* Card */
.card {
  background: var(--bg-elev);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-sm);
}

/* Inset list (iOS grouped) */
.list {
  background: var(--bg-elev);
  border-radius: var(--r-card);
  overflow: hidden;
  margin: 0 16px;
}
.list-row {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; position: relative;
}
.list-row + .list-row::before {
  content: ''; position: absolute; left: 16px; right: 0; top: 0;
  height: 0.5px; background: var(--hairline);
}
.list-row.has-icon + .list-row::before { left: 60px; }

/* Section header (small uppercase) */
.section-h {
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--text-2);
  padding: 22px 22px 8px;
}

/* Subtle glass for floating overlays */
.glass {
  background: var(--bg-overlay);
  backdrop-filter: blur(24px) saturate(180%);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  border: 0.5px solid var(--hairline-2);
}

/* ==================================================================
   Floating glass bottom navigation (.navbar) — Claude Design handoff.
   Token'lar panelin :root'undakilerle BİREBİR (--accent, --accent-soft,
   --bg-overlay, --hairline-2, --text-3, --bg) → remap yok. Eski katı
   .tabbar/.tab bunun yerini aldı. Masaüstünde (≥768px) .navbar gizlenir
   (sidebar devrede) — aşağıdaki media bloğuna bak. */
/* İNCELTME (kullanıcı isteği 2026-08-29): "bottom barı biraz daha
   inceltelim, daha kibar dursun ama gene güzel olsun." 62 → 54px.
   Kapsül (.navtab) 44 → 40, ikon 24 → 23, etiket 13 → 12.5px ile
   BİRLİKTE indi: yalnız kabuğu kısaltmak kapsülü kenarlara yapıştırır
   ve çubuk incelmiş değil SIKIŞMIŞ görünür. Dolgu 4px'te kalır
   (54 − 40 = 14 → üstte/altta 7px), yani kapsül hâlâ nefes alıyor.
   ⚠️ Yükseklik değişirse .tam-scroll padding-bottom + .bottom-scrim +
   .fab bottom da değişir (aynı geometrinin üç yüzü). */
.navbar {
  position: absolute;            /* kapsayıcı (PhoneShell) position:relative */
  left: 14px; right: 14px; bottom: 22px;
  height: 54px;
  border-radius: 23px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 8px;
  z-index: 30;
  box-shadow: 0 8px 28px rgba(15, 15, 20, 0.14), 0 2px 7px rgba(15, 15, 20, 0.055);
  /* Sürükle-seç jesti: yatay sürükleme tarayıcı scroll/zoom'una kaçmasın +
     metin seçilmesin. */
  touch-action: none;
  -webkit-user-select: none; user-select: none;
  /* Scroll'da gizleme animasyonu — KISA YOL eğrisi (92px). Eskiden 0.46s
     + --ease-decel idi: yolun %90'ı 140ms'de bitip kalan 320ms alt-piksel
     sürünmeye dönüşüyordu ve bu çubuk `backdrop-filter` taşıdığı için
     her sürünme karesinde arkasındaki bulanıklık YENİDEN hesaplanıyordu.
     54px'e incelen bir camda bu, gözle görülür bir titreme demek.
     Yol da 170% → 150%: çubuğun alt kenarı zaten 22px yukarıda, 54×1.5=81px
     onu kabın dışına TAMAMEN çıkarır (76px yeterli); fazla yol yalnız
     aynı sürede daha sert bir hız üretiyordu. */
  transition: transform var(--dur-bar) var(--ease-glide), opacity 200ms linear;
  /* Katman animasyon boyunca DEĞİL, sürekli var olsun: backdrop-filter zaten
     kompozit katman kuruyor; will-change onu her gizlen-göster turunda
     yeniden kurup bırakma maliyetinden kurtarır. */
  will-change: transform, opacity;
}
[data-theme="dark"] .navbar {
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6), 0 0 0 0.5px rgba(255, 255, 255, 0.05);
}
.navbar.is-hidden {
  transform: translate3d(0, 150%, 0);
  opacity: 0;
  pointer-events: none;
}
.navbar-bg {
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: var(--bg-overlay, rgba(245, 245, 247, 0.78));
  -webkit-backdrop-filter: blur(30px) saturate(180%);
  backdrop-filter: blur(30px) saturate(180%);
  border: 0.5px solid var(--hairline-2, rgba(60, 60, 67, 0.08));
}
/* Genişleyen kapsül sekme — pasif = yalnız ikon; aktif = ikon+yazı YAN YANA
   bir accent kapsülüne açılır. Yazı açılması GRID 0fr→1fr tekniğiyle yapılır:
   max-width tahmini yok → etiket tam içeriği kadar, milimetrik ve akıcı açılır
   (easing gerçekten görünür, "boşlukta akan" snap yok). Kapsül aktif .navtab'ın
   kendi arka planıdır (kayan gösterge yok).

   SÜRE EKRAN GEÇİŞİYLE AYNI (--dur-screen). Eskiden kapsül 0.5s, ekran
   0.42s idi: sekmeye basıldığında ekran oturduktan ~80ms sonra çubuk hâlâ
   kıpırdıyordu ve göz bunu tek bir hareket değil, art arda iki olay olarak
   okuyordu. Aynı süre + aynı eğri = tek hareket.
   ⚠️ grid-template-columns DÜZEN (layout) özelliğidir: her karede çubuğun
   düzeni yeniden hesaplanır ve `backdrop-filter` yeniden bulanıklaştırılır.
   Bu yüzden süre uzatılmaz — teknik doğru, pencere kısa tutulur. */
.navtab {
  position: relative;
  z-index: 1;
  flex: 0 1 auto;
  min-width: 40px;
  height: 40px;
  padding: 0 11px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 999px;
  color: var(--text-3, #aeaeb2);
  background: transparent;
  border: none; cursor: pointer; font: inherit;
  -webkit-tap-highlight-color: transparent;
  transition: background var(--dur-screen) var(--ease-glide),
              color 220ms linear,
              transform 160ms var(--ease-glide);
}
.navtab-iconwrap {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur-screen) var(--ease-glide);
}
.navtab.is-active .navtab-iconwrap { transform: scale(1.04); }
/* Etiket: tek-sütun grid; 0fr (kapalı) ↔ 1fr (içerik genişliği). İç span
   overflow:hidden + min-width:0 ile track'e kırpılır. */
.navtab-label {
  display: grid;
  grid-template-columns: 0fr;
  opacity: 0;
  transition: grid-template-columns var(--dur-screen) var(--ease-glide),
              opacity 200ms linear;
}
.navtab-label-inner {
  overflow: hidden;
  min-width: 0;
  white-space: nowrap;
  padding-left: 7px;          /* ikon-yazı boşluğu — kapanınca yazıyla birlikte kırpılır */
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.navtab.is-active {
  background: var(--accent-soft, rgba(10, 132, 255, 0.14));
  color: var(--accent, #0a84ff);
}
.navtab.is-active .navtab-label {
  grid-template-columns: 1fr;
  opacity: 1;
}
/* 0.92 → 0.94: 40px'lik bir kapsülde %8 küçülme 3.2px'lik bir sıçrama demek
   ve parmağın altında "tık" gibi hissediliyordu. Bas-geri-bırak tepkisi
   görünür kalsın diye tamamen kaldırılmadı, yalnız yumuşatıldı. */
.navtab:not(.is-active):active { transform: scale(0.94); }
/* Sürükleme sırasında highlight parmağa daha çabuk yetişsin (daha kısa süre);
   bırakınca normal --dur-screen yumuşak oturma geri gelir. */
.navbar.is-dragging .navtab,
.navbar.is-dragging .navtab-iconwrap,
.navbar.is-dragging .navtab-label { transition-duration: 190ms; }

/* İçerik soluması (scrim) — floating bar'ın arkasındaki içerik alta yumuşar. */
.bottom-scrim {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 124px;
  z-index: 20;
  pointer-events: none;
  background: linear-gradient(to top, var(--bg, #f3f3f7) 28%, transparent 100%);
  /* Çubukla AYNI süre: scrim daha yavaş sönerse çubuk gidip perde kalıyor. */
  transition: opacity var(--dur-bar) linear;
}
.bottom-scrim.is-hidden { opacity: 0; }

/* FAB — floating bar'ın üstünde. tabbar-shift uygulanırsa FAB da onunla birlikte iner.
   ÖLÇÜLEN HATA (2026-08-24, gerçek Chrome): bottom 82px iken FAB'ın alt kenarı
   ile barın üst kenarı arasındaki boşluk −2px'ti, yani FAB fiziksel olarak
   barın İÇİNE giriyordu. Kullanıcı bunu "çok sıkışık duruyor" diye bildirdi;
   ölçüm haklı çıkardı. Nefes payı 12px'tir ve barın üst kenarından TÜRETİLİR:
   bar bottom 22 + height 54 = 76 → FAB 88px. (Bar 62px'ken bu sayı 96'ydı;
   çubuk 2026-08-29'da inceltilince birlikte indi — sabit bırakılsaydı FAB
   ile bar arasında 20px'lik açıklanamayan bir boşluk kalırdı.) */
.fab {
  position: absolute; right: 18px; bottom: calc(88px + var(--bottom-inset) + var(--tabbar-shift));
  width: 56px; height: 56px; border-radius: 18px;
  background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 30px rgba(10, 132, 255, 0.4), 0 2px 6px rgba(10, 132, 255, 0.3);
  z-index: 25;
  /* Floating bar ile birlikte scroll'da gizlenir — AYNI süre/eğri, yoksa
     iki öğe aynı jestte farklı hızlarda kayıp birbirinden kopuyor. */
  transition: transform var(--dur-bar) var(--ease-glide), opacity 200ms linear;
  will-change: transform, opacity;
}
.fab.is-hidden {
  transform: translate3d(0, 200%, 0) scale(0.92);
  opacity: 0;
  pointer-events: none;
}

/* Number / metric scale */
.metric {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
}

/* Avatar */
.avatar {
  width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 600; font-size: 14px;
  letter-spacing: -0.01em; flex-shrink: 0;
}

/* Service color dots (used a lot) */
.dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

/* ──────────────────────────────────────────────────────────────
   Ekran viewport sarmalayıcısı (app.jsx Router) — eskiden inline
   style={{position:'absolute',inset:0}} idi. Sınıfa taşındı ki masaüstünde
   sidebar için sol ofset !important'sız verilebilsin. Mobil sonuç birebir aynı.
   ────────────────────────────────────────────────────────────── */
.tam-viewport { position: absolute; inset: 0; }

/* Sheet panel temeli (ui.jsx Sheet) — pozisyon/köşe/maxHeight/gölge eskiden
   inline idi; mobil değerleri burada. Masaüstü (≥768) ortalanmış modal override'ı
   bu sınıfı temiz dövebilsin diye taşındı. < 768px: prototiple birebir alttan sheet. */
.tam-sheet-panel {
  position: absolute; left: 0; right: 0; bottom: 0;
  border-top-left-radius: var(--r-sheet);
  border-top-right-radius: var(--r-sheet);
  max-height: 94%;
  box-shadow: 0 -20px 60px rgba(0, 0, 0, 0.25);
}

/* ──────────────────────────────────────────────────────────────
   Masaüstü / tablet sol kenar çubuğu (.tam-sidenav)
   Mobilde display:none → hiç görünmez (mobil .tabbar devrede).
   ≥768px'de görünür; .tabbar/.tab/.tabbar-bg görsel dilinin DİKEY karşılığı.
   ────────────────────────────────────────────────────────────── */
.tam-sidenav {
  display: none;                 /* mobil: gizli (media query'de flex olur) */
  position: absolute; top: 0; left: 0; bottom: 0;
  width: var(--sidebar-w);
  flex-direction: column;
  padding: 22px 14px calc(18px + var(--bottom-inset));
  background: var(--bg-overlay);
  backdrop-filter: blur(28px) saturate(180%);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  border-right: 0.5px solid var(--hairline-2);
  z-index: 40;                   /* içeriğin üstü, sheet(60) altı */
}
.tam-sidenav-brand { padding: 6px 10px 18px; }
.tam-sidenav-logo {
  width: 40px; height: 40px; border-radius: 12px;
  background: linear-gradient(135deg, #0a0a0c, #1f3a2e);
  color: #fff; font-weight: 700; font-size: 15px; letter-spacing: -0.4px;
  display: flex; align-items: center; justify-content: center;
}
/* ── Şube anahtarı (zincir · migration 056) ──────────────────────
   Tek şubeli kullanıcıda bileşen HİÇ render edilmez, yani bu kurallar
   ölü kalır. Yeni bir görsel dil İCAT EDİLMEZ: .tam-sidenav-item'ın
   token'ları (yükseklik, radius, hairline, --text-2) yeniden kullanılır.
   .tam-branchsw kenar çubuğunun İÇİNDE yaşar; kenar çubuğu mobilde
   display:none olduğundan mobil görünüme hiçbir şey eklemez. */
.tam-branchsw {
  display: flex; flex-direction: column; gap: 1px;
  width: 100%; padding: 8px 10px 9px; margin: 0 0 12px;
  border-radius: var(--r-tile); text-align: left;
  background: var(--fill-1); border: 0.5px solid var(--hairline-2);
}
.tam-branchsw-group {
  font-size: 11px; font-weight: 600; letter-spacing: 0.02em;
  color: var(--text-3); text-transform: uppercase;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tam-branchsw-name {
  display: flex; align-items: center; justify-content: space-between; gap: 6px;
  font-size: 14px; font-weight: 590; color: var(--text-1); letter-spacing: -0.01em;
}
/* Mobil çip — Bugün başlığında. Küçük, sessiz; başlığın hiyerarşisini
   bozmaz (DESIGN_SYSTEM: tek birincil eylem, bu ikincil bir bağlam). */
.tam-branchchip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 9px 3px 10px; border-radius: 999px;
  background: var(--fill-1); border: 0.5px solid var(--hairline-2);
  font-size: 13px; font-weight: 560; color: var(--text-2);
  letter-spacing: -0.01em; max-width: 60vw;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Sheet içeriği — iki yüzey de aynı listeyi açar. */
.tam-branchlist { display: flex; flex-direction: column; gap: 2px; padding: 4px 0 8px; }
.tam-branchrow {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; min-height: 52px; padding: 8px 14px;
  border-radius: var(--r-tile); text-align: left; color: var(--text-1);
}
.tam-branchrow:disabled { opacity: 0.55; }
.tam-branchrow.is-active { background: var(--fill-1); }
.tam-branchrow-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tam-branchrow-name {
  font-size: 15px; font-weight: 570; letter-spacing: -0.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tam-branchrow-sub { font-size: 12.5px; color: var(--text-3); }
.tam-branchrow-mark { font-size: 15px; color: var(--text-3); }

.tam-sidenav-items { display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; }
.tam-sidenav-item {
  display: flex; align-items: center; gap: 12px;
  height: 44px; padding: 0 12px; border-radius: var(--r-tile);
  color: var(--text-2); font-size: 15px; font-weight: 540;
  letter-spacing: -0.01em; text-align: left; width: 100%;
}
.tam-sidenav-item span { flex: 1; min-width: 0; }
.tam-sidenav-item.is-active { color: var(--accent); background: var(--accent-soft); font-weight: 600; }
.tam-sidenav-footer { padding-top: 12px; }
.tam-sidenav-new {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 46px; border-radius: var(--r-pill);
  background: var(--accent); color: #fff;
  font-size: 15px; font-weight: 600; letter-spacing: -0.01em;
  box-shadow: 0 8px 24px color-mix(in oklab, var(--accent), transparent 64%);
}

/* ──────────────────────────────────────────────────────────────
   EKİP ERİŞİMİ GEÇİDİ — "Sahne" (screen-panel-gate.jsx · PanelGate)

   Panel açılmadan ÖNCEKİ tek ekran: "Kim giriş yapıyor?". Sekme çubuğu,
   başlık, kaydırma yok → bu bir uygulama ekranı değil, bir SAHNE.
   Bu yüzden panelin liste/kart diline değil kendi diline sahiptir:
   tam-ekran zemin, büyük dokunma hedefleri, tek soru.

   Akrabası /personel (CRM): yuvarlak-KARE avatar (panelin dairesi değil),
   hairline kart, tabular rakam. Ama rengi panelindir — sahibin seçtiği
   --accent hâlesi zemine düşer, böylece her işletmenin sahnesi kendine
   benzer. Tema (açık/koyu) kullanıcının tercihidir; sahne ikisinde de
   birinci sınıf çizilir, koyu tema "zorla karartılmaz".

   ERİŞİLEBİLİRLİK: tuş takımı fiziksel klavyeyi DIŞLAMAZ (JSX'te keydown);
   hareket azaltma tercihine uyulur; her hedef ≥44px.
   ────────────────────────────────────────────────────────────── */
/* Dikey ortalama `justify-content:center` ile DEĞİL çocuğun `margin:auto`'su ile
   yapılır: kalabalık bir ekipte (8+ profil) içerik ekranı aşınca justify-content
   taşan üst kısmı kaydırma dışında bırakır ve başlık ULAŞILAMAZ olur. */
.gate-stage {
  position: absolute; inset: 0;
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column;
  background: var(--bg); color: var(--text);
  padding: 20px 20px 0;
  padding-top: max(44px, calc(env(safe-area-inset-top) + 16px));
  padding-bottom: max(28px, calc(env(safe-area-inset-bottom) + 20px));
  --gate-ease: cubic-bezier(0.32, 0.72, 0, 1);
  --gate-tile: 92px;
}

/* Zemindeki aksan hâlesi — DEKORATİF (aria-hidden). Tek renk yerine iki
   yumuşak daire: üstte marka aksanı, altta nötr derinlik. */
.gate-aura {
  position: absolute; inset: 0; pointer-events: none; z-index: 0;
  background:
    radial-gradient(58% 42% at 50% -6%, color-mix(in oklab, var(--accent), transparent 84%), transparent 70%),
    radial-gradient(46% 34% at 50% 108%, color-mix(in oklab, var(--accent), transparent 92%), transparent 72%);
}
[data-theme="dark"] .gate-aura {
  background:
    radial-gradient(58% 42% at 50% -6%, color-mix(in oklab, var(--accent), transparent 74%), transparent 70%),
    radial-gradient(46% 34% at 50% 108%, color-mix(in oklab, var(--accent), transparent 88%), transparent 72%);
}

.gate-inner {
  position: relative; z-index: 1;
  width: 100%; max-width: 520px; margin: auto;
  display: flex; flex-direction: column;
}

/* ── Marka + işletme adı ─────────────────────────────────────── */
.gate-brand { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: 22px; }
.gate-seal {
  width: 52px; height: 52px; border-radius: 15px;
  background: linear-gradient(135deg, #0a0a0c, #1f3a2e);
  color: #fff; font-weight: 700; font-size: 19px; letter-spacing: -0.5px;
  display: flex; align-items: center; justify-content: center;
  box-shadow: var(--shadow-md);
}
/* İşletme adı — kiracı verisi, çevrilmez. Sahneyi "bu senin salonun" yapar. */
.gate-biz {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-3);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.gate-head { text-align: center; margin-bottom: 26px; }
.gate-title { font-size: 26px; font-weight: 700; letter-spacing: -0.035em; }
.gate-sub { font-size: 14px; color: var(--text-2); margin-top: 5px; line-height: 1.45; }

/* ── Profil ızgarası ─────────────────────────────────────────── */
.gate-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--gate-tile), 1fr));
  gap: 20px 14px;
  justify-content: center;
}
/* 1–2 profil varsa auto-fit ızgarayı geresin diye kolon sayısı sabitlenir
   (aksi halde tek profil tüm satırı kaplayıp devasa görünürdü). */
.gate-grid[data-count="1"] { grid-template-columns: var(--gate-tile); }
.gate-grid[data-count="2"] { grid-template-columns: repeat(2, var(--gate-tile)); }

.gate-card {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  width: 100%; padding: 0; background: none;
  -webkit-tap-highlight-color: transparent;
  animation: gate-fade 0.34s var(--gate-ease) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.gate-card:focus-visible { outline: none; }
.gate-card:focus-visible .gate-tile { box-shadow: 0 0 0 3px var(--bg), 0 0 0 6px var(--accent); }

/* Kare değil YUVARLAK KARE: /personel avatarının büyütülmüş hâli. Panelin
   dairesel .avatar'ından bilinçli olarak ayrışır — burası panel değil. */
.gate-tile {
  position: relative;
  width: var(--gate-tile); height: var(--gate-tile);
  border-radius: calc(var(--gate-tile) * 0.28);
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-size: calc(var(--gate-tile) * 0.3); font-weight: 650;
  letter-spacing: -0.02em;
  background-size: cover; background-position: center;
  box-shadow: var(--shadow-md);
  transition: transform 0.22s var(--gate-ease), box-shadow 0.22s ease, filter 0.22s ease;
}
.gate-card:active .gate-tile { transform: scale(0.955); }

/* Rol işareti — bağırmaz. Sahip: taç. Yönetici: aksan noktası. Personel: yok. */
.gate-mark {
  position: absolute; right: -3px; bottom: -3px;
  width: 26px; height: 26px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-elev); color: var(--text-2);
  box-shadow: 0 0 0 2.5px var(--bg), var(--shadow-sm);
}
.gate-mark.is-owner { color: var(--amber); }
.gate-mark.is-admin { color: var(--accent); }

/* Kilitli profil: karartılır ama GİZLENMEZ — kişi kendi kartını görmeli,
   yoksa "profilim silindi mi?" paniği olur. Dokunuşta süre bilgisi verilir. */
.gate-card.is-locked .gate-tile { filter: grayscale(0.85) brightness(0.72); }
.gate-lock {
  position: absolute; inset: 0; border-radius: inherit;
  display: flex; align-items: center; justify-content: center;
  background: rgba(10, 10, 12, 0.42); color: #fff;
}

.gate-name {
  font-size: 14px; font-weight: 560; letter-spacing: -0.01em;
  color: var(--text-2); text-align: center; line-height: 1.25;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color 0.18s ease;
}
.gate-role { font-size: 11.5px; font-weight: 500; color: var(--text-3); margin-top: -6px; }

/* ── PIN adımı ───────────────────────────────────────────────── */
.gate-hero { display: flex; flex-direction: column; align-items: center; gap: 12px; margin-bottom: 20px; }
.gate-hero .gate-tile { --gate-tile: 76px; width: 76px; height: 76px; border-radius: 22px; font-size: 23px; }
.gate-hero-name { font-size: 20px; font-weight: 680; letter-spacing: -0.03em; }
.gate-hero-sub { font-size: 13.5px; color: var(--text-2); margin-top: -8px; }

/* Nokta yuvaları: ilk 4 dolu çerçeve (zorunlu), son 2 kesik (opsiyonel).
   PIN uzunluğu kişiden kişiye değişir; yuvalar bunu yalan söylemeden anlatır. */
.gate-dots { display: flex; align-items: center; justify-content: center; gap: 12px; margin: 4px 0 20px; }
.gate-dot {
  width: 14px; height: 14px; border-radius: 50%;
  border: 1.5px solid var(--hairline); background: transparent;
  transition: transform 0.16s var(--gate-ease), background-color 0.16s ease, border-color 0.16s ease;
}
.gate-dot.is-optional { border-style: dashed; opacity: 0.55; }
.gate-dot.is-on {
  background: var(--accent); border-color: var(--accent);
  transform: scale(1.14); opacity: 1;
}
.gate-dots.is-error { animation: gate-shake 0.42s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }
.gate-dots.is-error .gate-dot { border-color: var(--red); }
.gate-dots.is-error .gate-dot.is-on { background: var(--red); }

/* Tuş takımı — kasa/POS mantığı. Salon tezgâhındaki tablette parmakla
   girilecek; sistem klavyesini çağırıp ekranın yarısını kaplamaz. */
.gate-keys {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 10px; max-width: 300px; width: 100%; margin: 0 auto;
}
.gate-key {
  height: 62px; border-radius: var(--r-tile);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-elev); color: var(--text);
  font-size: 24px; font-weight: 520; font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  box-shadow: inset 0 0 0 0.5px var(--hairline-2), var(--shadow-sm);
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.14s var(--gate-ease), background-color 0.14s ease;
}
.gate-key:active { transform: scale(0.94); background: var(--surface-2); }
.gate-key.is-quiet { background: transparent; box-shadow: none; color: var(--text-2); font-size: 15px; font-weight: 560; }
.gate-key.is-quiet:active { background: var(--surface-2); }
.gate-key[disabled] { opacity: 0.35; }

/* "Beni hatırla" — tuş takımının altında duran ikincil karar. Birincil
   eylemle (PIN) yarışmaz: dolgu yok, yalnız kutu + iki satır metin.
   İşaretliyken kutu aksana döner; metin rengi DEĞİŞMEZ (renk tek başına
   durumu anlatmaz, alt satır zaten yazıyor). */
.gate-remember { margin-top: 14px; display: flex; justify-content: center; }
.gate-remember-btn {
  display: flex; align-items: center; gap: 12px;
  width: 100%; max-width: 300px; min-height: 44px;
  padding: 8px 10px; border-radius: var(--r-tile);
  background: transparent; text-align: left;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.16s ease, opacity 0.18s ease;
}
.gate-remember-btn:active { background: var(--surface-2); }
.gate-remember-btn[disabled] { opacity: 0.4; }
.gate-remember-box {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 7px;
  display: flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--hairline); color: #fff;
  transition: background-color 0.16s ease, border-color 0.16s ease;
}
.gate-remember-btn.is-on .gate-remember-box { background: var(--accent); border-color: var(--accent); }
/* Tek satır (kullanıcı isteği 2026-08). Alt açıklama satırı kaldırıldı;
   .gate-remember-text sarmalayıcısı da gereksizleşti. */
.gate-remember-title { font-size: 14.5px; font-weight: 560; letter-spacing: -0.01em; min-width: 0; }

/* ── Ortak: hata, bilgi, çıkış kapısı ────────────────────────── */
.gate-msg { font-size: 13.5px; font-weight: 500; text-align: center; margin-top: 16px; min-height: 18px; line-height: 1.45; }
.gate-msg.is-error { color: var(--red); }
.gate-msg.is-note  { color: var(--text-2); }

.gate-foot { margin-top: 24px; text-align: center; }
.gate-exit {
  padding: 12px 16px; min-height: 44px;
  font-size: 13.5px; font-weight: 500; color: var(--text-2);
  border-radius: var(--r-pill);
  transition: opacity 0.18s ease, background-color 0.18s ease;
}
.gate-exit[disabled] { opacity: 0.5; }

/* Yalnız ekran okuyucu — görsel akışa hiç girmez (clip-path yerine 1px kutu:
   eski WebKit'lerde de güvenli). */
.gate-sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%);
}

/* Bootstrap (ilk kurulum) alan satırları — panelin .list dilini korur. */
.gate-field { display: flex; flex-direction: column; gap: 0; padding: 6px 16px; }
.gate-field-label { font-size: 12px; color: var(--text-2); font-weight: 500; padding-top: 10px; }
.gate-field-input {
  width: 100%; min-height: 28px; padding: 6px 0 12px;
  background: transparent; border: none; outline: none;
  font-size: 16px; font-weight: 500; color: var(--text); letter-spacing: -0.2px;
}

@keyframes gate-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes gate-shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}
@media (prefers-reduced-motion: reduce) {
  .gate-card { animation: none; }
  .gate-dots.is-error { animation: none; }
  .gate-tile, .gate-dot, .gate-key { transition: none; }
}

/* ── Zaman planı anlatımı (SvcTimeStorySheet) ────────────────────────
   Adım METNİ yalnız OPACITY ile geçer. Panelin kuralı: metin taşıyan
   katmana transform verilmez (`.rise`'ın kapatılma sebebi; transform
   metinde AA-snap yapıp küt bir sıçrama üretiyor). Çubuk parçalarının
   kendisi metin taşımaz, onlar JSX'te scaleX ile açılır.
   Mevcut `ob-fade` kare dizisi yeniden kullanılır; yeni easing/animasyon
   UYDURULMAZ (DESIGN_SYSTEM §8 süre skalası). */
.svc-story-step { animation: ob-fade 260ms cubic-bezier(0.32, 0.72, 0, 1) both; }
@media (prefers-reduced-motion: reduce) {
  .svc-story-step { animation: none; }
}

/* ── KISA EKRAN: sahne kendini toplar (yükseklik kapılı) ─────────────
   ÖLÇÜLEN HATA (gerçek Chrome, 2026-08-24): PIN fazının içeriği 780–811px.
   Tarayıcı adres/araç çubuğu açıkken görünür alan çok daha küçük:
     iPhone 14 tarayıcı  730px → 81px kayma
     Pixel     tarayıcı  780px → 31px kayma
     SE        PWA       667px → 120px kayma
     SE        tarayıcı  560px → 227px kayma
   Tuş takımı ekrana sabit duran bir hedef olduğu için bu kaydırma
   kullanıcıyı rahatsız ediyordu (kullanıcı bildirdi: "sayfa aşağı yukarı
   kaydırma yapılacak kadar boşluğu olmasın").

   Çözüm tek bir sayıyı kısmak DEĞİL, sahneyi yüksekliğe DUYARLI yapmak:
   alan daraldıkça nefes payları ve dekoratif ölçüler kademeli küçülür.
   Dokunma hedefleri 44px tabanının ALTINA İNMEZ (erişilebilirlik sözü).
   Nöbetçi: tests/gate-lobby.test.mjs + scratch ölçümü. */
@media (max-height: 800px) {
  .gate-stage {
    padding-top: max(24px, calc(env(safe-area-inset-top) + 10px));
    padding-bottom: max(16px, calc(env(safe-area-inset-bottom) + 12px));
  }
  .gate-brand { margin-bottom: 12px; }
  .gate-seal { width: 44px; height: 44px; border-radius: 13px; font-size: 16px; }
  .gate-head { margin-bottom: 16px; }
  .gate-hero { gap: 8px; margin-bottom: 12px; }
  .gate-hero .gate-tile { --gate-tile: 64px; width: 64px; height: 64px; border-radius: 19px; font-size: 20px; }
  .gate-hero-name { font-size: 18px; }
  .gate-dots { margin: 2px 0 12px; }
  .gate-key { height: 54px; font-size: 21px; }
  .gate-remember { margin-top: 10px; }
  .gate-foot { margin-top: 12px; }
}
@media (max-height: 680px) {
  .gate-brand { margin-bottom: 8px; }
  .gate-seal { width: 36px; height: 36px; border-radius: 11px; font-size: 14px; }
  .gate-hero { gap: 6px; margin-bottom: 8px; }
  .gate-hero .gate-tile { --gate-tile: 54px; width: 54px; height: 54px; border-radius: 16px; font-size: 17px; }
  .gate-hero-name { font-size: 17px; }
  .gate-hero-sub { font-size: 12.5px; }
  .gate-dots { margin: 0 0 8px; gap: 10px; }
  .gate-keys { gap: 8px; }
  .gate-key { height: 46px; font-size: 20px; }   /* 44px tabanının üstünde */
  .gate-remember { margin-top: 8px; }
  .gate-msg { margin-top: 8px; }
  .gate-foot { margin-top: 8px; }
}
/* PIN fazında marka mührü hiç çizilmez (JSX `is-compact`); geriye kalan
   işletme adı şeridinin üst payı da o fazda gereksiz. */
.gate-stage.is-compact .gate-brand { margin-bottom: 14px; }

/* Küçük telefon (SE sınıfı): kutu daralır, ızgara üç sütunda kalsın. */
@media (max-width: 380px) {
  .gate-stage { --gate-tile: 80px; padding-left: 16px; padding-right: 16px; }
  .gate-grid { gap: 16px 12px; }
  .gate-title { font-size: 23px; }
  .gate-key { height: 56px; font-size: 22px; }
}

/* İmleçli cihazlar — Netflix'in "adı beyazlar" jesti: kart canlanır,
   ad tam kontrasta çıkar. Dokunmatikte tetiklenmez. */
@media (hover: hover) {
  .gate-card:hover .gate-tile { transform: translateY(-3px) scale(1.03); box-shadow: var(--shadow-lg); }
  .gate-card:hover .gate-name { color: var(--text); }
  .gate-card.is-locked:hover .gate-tile { transform: none; }
  .gate-key:hover { background: var(--surface-2); }
  .gate-key.is-quiet:hover { background: var(--surface-2); }
  .gate-exit:hover { background: var(--surface-2); color: var(--text); }
}

/* ──────────────────────────────────────────────────────────────
   KURULUM & TUR  (docs/ONBOARDING-PLANI.md §7)
   ──────────────────────────────────────────────────────────────
   KIRMIZI ÇİZGİ: metin taşıyan hiçbir öğe transform ile animasyon ALMAZ.
   Metin yalnız opacity ile gelir. Sebebi .rise'ın kapatılma sebebiyle
   AYNI (bkz. yukarıdaki .rise notu): transform metni GPU katmanında
   grayscale AA ile çizip bitişte keskin metne "küt" oturtuyor.
   Hareket, metin taşımayan katmanlara verilir: ikon diskleri, ilerleme
   halkası, spot ışığı, onay tiki, kart zemini.

   Süre sözlüğü (yeni easing UYDURULMAZ, hepsi dosyada zaten var):
     micro 180ms  · pop 240ms · swap 360ms · travel 520ms · draw 320ms
   Bütçe: bir durak açıldıktan sonra en geç 600ms içinde yerine oturur.
   ────────────────────────────────────────────────────────────── */
.ob-shell, .tour-layer {
  --ob-ease: cubic-bezier(0.32, 0.72, 0, 1);
  --ob-pop:  cubic-bezier(0.2, 1.6, 0.4, 1);
}

/* ── Kurulum kabuğu ──────────────────────────────────────────── */
.ob-shell {
  position: absolute; inset: 0;
  background: var(--bg); color: var(--text);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.ob-head {
  display: flex; align-items: center; gap: 12px;
  padding: max(18px, calc(env(safe-area-inset-top) + 8px)) 18px 6px;
}
.ob-body {
  flex: 1; min-height: 0; overflow-y: auto;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
  padding: 4px 20px 8px;
}
.ob-foot {
  padding: 10px 20px max(18px, calc(env(safe-area-inset-bottom) + 12px));
  display: flex; gap: 10px;
}

/* İlerleme halkası — metin YOK, yüzde yazılmaz. stroke-dashoffset ile
   dolar; SVG olduğu için transform yasağının kapsamı dışında. */
.ob-ring { width: 34px; height: 34px; flex: none; transform: rotate(-90deg); }
.ob-ring circle { fill: none; stroke-width: 3; stroke-linecap: round; }
.ob-ring .ob-ring-bg { stroke: var(--surface-2); }
.ob-ring .ob-ring-fg {
  stroke: var(--accent);
  transition: stroke-dashoffset 420ms var(--ob-ease);
}

/* Durak geçişi: giden opacity 1→0 (140ms), gelen 0→1 (200ms).
   Metin KAYMAZ. Yalnız .ob-step-deco (dekoratif katman) hafif kayar. */
.ob-step { animation: ob-step-in 200ms var(--ob-ease) both; }
.ob-step.is-leaving { animation: ob-step-out 140ms var(--ob-ease) both; }
@keyframes ob-step-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes ob-step-out { from { opacity: 1; } to { opacity: 0; } }

/* Dekoratif katman (ikon diski, mühür zemini) — metin taşımaz, kayabilir. */
.ob-step-deco { animation: ob-deco-in 360ms var(--ob-ease) both; }
@keyframes ob-deco-in {
  from { opacity: 0; transform: translateY(8px) scale(0.96); }
  to   { opacity: 1; transform: none; }
}

/* Kademeli giriş — en fazla 3 kademe × 40ms (bütçe). Yalnız opacity. */
.ob-stagger > * { animation: ob-fade 240ms var(--ob-ease) both; }
.ob-stagger > *:nth-child(1) { animation-delay: 0ms; }
.ob-stagger > *:nth-child(2) { animation-delay: 40ms; }
.ob-stagger > *:nth-child(3) { animation-delay: 80ms; }
.ob-stagger > *:nth-child(n+4) { animation-delay: 120ms; }
@keyframes ob-fade { from { opacity: 0; } to { opacity: 1; } }

/* Seçim kartı (sektör, ekip, saat şablonu) — Kart Picker dili:
   outline 2px var(--accent). Kart METİN taşır → transform YOK,
   hareket ikon diskinde (.ob-card-ico). */
.ob-card {
  width: 100%; text-align: left;
  display: flex; align-items: center; gap: 13px;
  padding: 14px 15px; margin-bottom: 9px;
  background: var(--bg-elev); border-radius: var(--r-tile);
  box-shadow: var(--shadow-sm);
  outline: 2px solid transparent; outline-offset: -2px;
  transition: outline-color 180ms var(--ob-ease), background 180ms ease;
}
.ob-card.is-sel { outline-color: var(--accent); background: var(--accent-soft); }
.ob-card-ico {
  width: 38px; height: 38px; border-radius: 11px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-2); color: var(--text-2);
  transition: background 180ms ease, color 180ms ease, transform 240ms var(--ob-pop);
}
.ob-card.is-sel .ob-card-ico {
  background: var(--accent); color: var(--text-on-accent);
  transform: scale(1.06);
}

/* Hizmet satırı — çıkarılınca yüksekliği 240ms'de kapanır. */
.ob-svc { overflow: hidden; transition: height 240ms var(--ob-ease), opacity 180ms ease; }
.ob-svc.is-removing { opacity: 0; }

/* Onay tiki — SVG stroke çizimi (draw 320ms). */
.ob-tick { stroke-dasharray: 32; stroke-dashoffset: 32; animation: ob-draw 320ms linear 60ms both; }
@keyframes ob-draw { to { stroke-dashoffset: 0; } }

/* Bitiş mührü — draw + pop, arkasında TEK yumuşak ışık dalgası.
   Konfeti yok (ürünün dili değil). */
.ob-seal { animation: ob-seal-in 420ms var(--ob-pop) both; }
@keyframes ob-seal-in {
  from { opacity: 0; transform: scale(0.72); }
  to   { opacity: 1; transform: scale(1); }
}
/* Kutlama halkası. Süre BÜTÇEYE tabidir (160+440 = 600ms): "dekoratif olduğu
   için uzun sürebilir" istisnası açılmadı — bir kez açılan istisna zamanla
   kuralı yer, ve nöbetçi test kesin bir çizgi olmadan işe yaramaz. */
.ob-seal-wave {
  position: absolute; inset: 0; border-radius: 50%;
  border: 2px solid var(--accent);
  animation: ob-wave 440ms var(--ob-ease) 160ms both;
}
@keyframes ob-wave {
  from { opacity: 0.5; transform: scale(1); }
  to   { opacity: 0;   transform: scale(1.9); }
}

/* ── Tanışma turu ────────────────────────────────────────────── */
/* Katman tıklamaları yakalar ama scroll'u kilitlemez; kaçış her zaman açık. */
.tour-layer { position: absolute; inset: 0; z-index: 90; }

/* Spot ışığı: TEK öğe. Karartı box-shadow spread ile çizilir (ayrı bir
   scrim elemanı yok) → delik ile karartı asla ayrışamaz. Hedeften hedefe
   travel(520ms) ile kayar ve boyut değiştirir. */
.tour-hole {
  position: absolute; border-radius: 16px;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.62);
  outline: 2px solid rgba(255, 255, 255, 0.9); outline-offset: 0;
  pointer-events: none;
  will-change: top, left, width, height;
  animation: ob-fade 240ms var(--ob-ease) both;
  transition: top 520ms var(--ob-ease), left 520ms var(--ob-ease),
              width 520ms var(--ob-ease), height 520ms var(--ob-ease);
}

/* Anlatı kartı — METİN taşır → YALNIZ opacity ile gelir, kaymaz.
   (Kartın altına ayrı bir kayan zemin katmanı KOYULMADI: spot ışığı zaten
   hareket ediyor, ikinci bir hareket aynı anda gözü böler.) */
.tour-card {
  position: absolute; left: 14px; right: 14px;
  background: var(--bg-elev); color: var(--text);
  border-radius: var(--r-card); box-shadow: var(--shadow-lg);
  padding: 16px 17px 14px;
  animation: ob-fade 240ms var(--ob-ease) both;
}
.tour-dots { display: flex; gap: 5px; align-items: center; }
.tour-dot {
  width: 5px; height: 5px; border-radius: 99px; background: var(--text-3);
  transition: width 180ms var(--ob-ease), background 180ms ease;
}
.tour-dot.is-on { width: 16px; background: var(--accent); }

/* Ekran ilk ziyaret ipucu — tepeden iner, metin taşır → opacity + ARKA
   PLAN katmanı kayar. */
.tour-hint { animation: ob-fade 240ms var(--ob-ease) both; }

/* ── Hareket azaltma ─────────────────────────────────────────────
   transform'ların TAMAMI kapanır, geçişler 120ms çapraz solmaya iner,
   spot ışığı zıplayarak yerleşir. İçerik her koşulda görünür kalır. */
@media (prefers-reduced-motion: reduce) {
  .ob-step, .ob-step.is-leaving, .ob-step-deco, .ob-stagger > *,
  .ob-seal, .ob-seal-wave, .ob-tick, .tour-hole, .tour-card, .tour-hint {
    animation-duration: 120ms !important;
    animation-delay: 0ms !important;
    transform: none !important;
  }
  .ob-seal-wave { display: none; }
  .ob-tick { stroke-dashoffset: 0; }
  .ob-ring .ob-ring-fg, .ob-card, .ob-card-ico, .ob-svc, .tour-hole, .tour-dot {
    transition: none !important;
  }
  .ob-card-ico { transform: none !important; }
}

/* ──────────────────────────────────────────────────────────────
   TABLET ve üstü (≥768px) — mobil görünüm ASLA etkilenmez (kapı bu media).
   ────────────────────────────────────────────────────────────── */
@media (min-width: 768px) {
  :root { --sidebar-w: 200px; --content-max: 640px; }

  /* Mobil alt çubuk (floating .navbar) + FAB gizlenir; sidebar bunların yerini
     alır (FAB'ın tek aksiyonu "Yeni Randevu" sidebar footer'ına taşındı). */
  .navbar, .fab { display: none; }

  /* Sidebar görünür */
  .tam-sidenav { display: flex; }

  /* İçerik alanı sidebar genişliği kadar sağa kayar */
  .tam-viewport { left: var(--sidebar-w); }

  /* İçeriği konforlu, ortalanmış banda otur (çocukların 16/22px margin'i korunur).
     padding-top host index.html'in max(54px…) kuralını yenmek için .tam-root ile
     yükseltilmiş özgüllük. */
  .tam-root .tam-scroll {
    padding-top: 30px;
    padding-bottom: 40px;
    padding-left: max(28px, calc((100% - var(--content-max)) / 2));
    padding-right: max(28px, calc((100% - var(--content-max)) / 2));
  }

  /* Sheet → ekran ortasında yüzen modal kart */
  .tam-sheet { display: flex; align-items: center; justify-content: center; padding: 32px; }
  .tam-sheet-panel {
    position: relative; left: auto; right: auto; bottom: auto;
    width: 100%; max-width: 560px;
    max-height: 86vh;
    border-radius: var(--r-sheet);
    box-shadow: var(--shadow-lg);
  }

  /* Shell-dışı ekranlar (Login/Onboarding/klasik geçit) — ortalanmış dar kolon */
  .tam-auth-shell { align-items: center; }
  .tam-auth-shell > * { width: 100%; max-width: 420px; }

  /* Geçit sahnesi tablette nefes alır: daha büyük kart, daha geniş ızgara.
     (.tam-auth-shell dar-kolon kuralı sahneye UYGULANMAZ — sahne ızgaralıdır.) */
  .gate-stage { --gate-tile: 108px; padding-left: 32px; padding-right: 32px; }
  .gate-inner { max-width: 620px; }

  /* Yumuşak geçişler (yalnız ≥768 — mobile transform/active dokunulmaz) */
  .tam-sidenav-item, .btn, .chip { transition: background-color 0.18s ease, color 0.18s ease; }
}

/* MASAÜSTÜ (≥1024px) — daha geniş kolon + tam etiketli sidebar */
@media (min-width: 1024px) {
  :root { --sidebar-w: 240px; --content-max: 840px; }
  .tam-root .tam-scroll { padding-bottom: 48px; }

  /* Geçit sahnesi — masaüstünde tek satırda 5 profile kadar yayılır. */
  .gate-stage { --gate-tile: 124px; }
  .gate-inner { max-width: 780px; }
  .gate-title { font-size: 30px; }
  .gate-hero .gate-tile { --gate-tile: 88px; width: 88px; height: 88px; border-radius: 26px; font-size: 27px; }
}

/* Hover affordance'ları — yalnız gerçek imleçli cihazlarda + ≥768px.
   DESIGN_SYSTEM: "hover scale yok" → scale DEĞİL, sadece hafif bg-tint. */
@media (hover: hover) and (min-width: 768px) {
  .tam-sidenav-item:hover { background: var(--surface-2); color: var(--text); }
  .tam-sidenav-item.is-active:hover { background: var(--accent-soft); color: var(--accent); }
  .tam-sidenav-new:hover { filter: brightness(1.06); }
  .btn-secondary:hover { background: var(--surface-3); }
  .btn-ghost:hover { background: var(--accent-soft); }
  .chip:not(.chip-active):hover { background: var(--surface-3); }
}

@media (min-width: 1024px) {
  /* ════════════════════════════════════════════════════════════════════
     MASAÜSTÜ UI/UX KATMANI (≥1024px) — kapsamlı geniş-ekran düzeni.

     SÖZLEŞME: Masaüstü katmanının HER kuralı (ve yorumu) @media
     (min-width:1024px) / (min-width:1280px) / (hover)+(1024px) kapısı
     İÇİNDEDİR. Mobil (<768) ve tablet (768–1023) çıkışı BAYT-BAYT aynı
     kalır — tests/desktop-guard.test.mjs bunu hash ile doğrular.

     Desen: ekranlar JSX'te yalnızca `desk-*` sınıf kancaları taşır; mobil
     CSS bu sınıfları hiç referans almaz. Ekran bölümlerinin mobil inline
     stillerini masaüstünde ezmek için bilinçli !important kullanılır
     (inline'ı sadece !important dövebilir; kapı ≥1024 olduğundan mobil
     asla etkilenmez). Tasarım dili DESIGN_SYSTEM: token renkler, hover =
     yalnız bg-tint / yumuşak gölge (scale YOK), süre skalası, mevcut eğriler.
     ════════════════════════════════════════════════════════════════════ */

  /* ── Genel kabuk ───────────────────────────────────────────────── */
  /* Alt scrim mobil floating-bar'a aitti; masaüstünde bar yok → veil kalksın
     (içeriğin son satırı soluk görünmesin). */
  .bottom-scrim { display: none; }

  /* Nefes payı: içerik bandı üstten biraz daha rahat otursun. */
  .tam-root .tam-scroll { padding-top: 36px; }

  /* Sheet modal'ı masaüstünde bir tık daha geniş (form/wizard konforu). */
  .tam-sheet-panel { max-width: 600px; }

  /* Etkileşim geçişleri: mevcut .tap eğrisi + bg/gölge kanalları (hover katmanı
     için). Süre skalası korunur (180ms). */
  .tap, .tap-soft {
    transition:
      transform 0.18s cubic-bezier(0.4, 0, 0.2, 1),
      opacity 0.18s ease,
      background-color 0.18s ease,
      box-shadow 0.18s ease;
  }

  /* ── BUGÜN (Dashboard) — iki kolonlu operasyon paneli ─────────────
     greet ─ tam genişlik
     now   │ duo (Sıradaki + Ciro, dikey)
     flow  ─ tam genişlik (yatay şerit → saran grid)
     pending ─ tam genişlik (kartlar 2-3 kolon)
     stats ─ tam genişlik (4 kolon)                                     */
  .tam-root .desk-dash {
    --content-max: 1120px;
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(300px, 1fr);
    grid-template-areas:
      "greet greet"
      "now   duo"
      "flow  flow"
      "pending pending"
      "stats stats";
    column-gap: 18px;
    align-content: start;
  }
  .desk-dash-greet   { grid-area: greet; }
  .desk-dash-now     { grid-area: now; }
  .desk-dash-duo     {
    grid-area: duo;
    grid-template-columns: 1fr !important;   /* yan rayda dikey yığın */
    align-content: start;
    padding-top: 16px !important;            /* now sarmalayıcısıyla üst hizası */
  }
  .desk-dash-flow    { grid-area: flow; }
  .desk-dash-pending { grid-area: pending; }
  .desk-dash-stats   { grid-area: stats; }

  /* Bugünün akışı: dokunmatik yatay şerit yerine saran kart grid'i
     (fare ile yatay scroll eziyettir; masaüstünde tüm gün tek bakışta). */
  .desk-flow-strip {
    display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    overflow-x: visible !important;
  }

  /* Bekleyen onaylar: kart başına tam satır israfı yerine 2-3 kolon. */
  .desk-pending-list {
    display: grid !important;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  }

  /* Günün özeti: 2×2 yerine tek satır 4 kolon. */
  .desk-stats-grid { grid-template-columns: repeat(4, 1fr) !important; }

  /* ── TAKVİM ──────────────────────────────────────────────────────── */
  .tam-root .desk-cal { --content-max: 1080px; }

  /* ── TAM AI (masaüstü) ────────────────────────────────────────────
     Mobilde başlık bir durum çubuğu bandı taşır (54px). Masaüstünde
     durum çubuğu YOKTUR: o bant burada boş bir şerit olarak kalıyordu.
     Ayrıca sohbet tam genişlikte akarsa satırlar okunamayacak kadar
     uzar; içerik `--content-max` bandına oturtulur.
     .ai-* düzeni sütun akışıdır, bu yüzden burada yalnız BOŞLUK ve
     GENİŞLİK ayarlanır — konumlandırmaya dokunulmaz. */
  .tam-root .ai-head { padding-top: 16px; }

  /* Akışın kendisi tam genişlikte kalır (kaydırma çubuğu kenarda dursun),
     İÇİNDEKİLER ortalanmış bir banda oturur. */
  .tam-root .ai-flow > * {
    max-width: var(--content-max);
    margin-left: auto; margin-right: auto;
  }
  /* Başlık ve yazma alanının iç içeriği de aynı bandı kullanır ki
     geri düğmesi ile ilk mesaj aynı hizada başlasın. */
  .tam-root .ai-head > *,
  .tam-root .ai-composer > * { max-width: none; }
  .tam-root .ai-composer {
    padding-left: max(28px, calc((100% - var(--content-max)) / 2));
    padding-right: max(28px, calc((100% - var(--content-max)) / 2));
  }
  .tam-root .ai-head > div {
    padding-left: max(28px, calc((100% - var(--content-max)) / 2));
    padding-right: max(28px, calc((100% - var(--content-max)) / 2));
  }

  /* Balon ve kartların mobil yan boşluğu (16px) geniş ekranda banda göre
     hesaplandığı için sıfırlanır; hizayı artık bant veriyor. */
  .tam-root .ai-bubble,
  .tam-root .ai-card,
  .tam-root .ai-confirm { margin-left: 0; margin-right: 0; }
  .tam-root .ai-me { margin-left: auto; }
  /* Yazıyor göstergesi artık bir balon (width: fit-content). Yukarıdaki
     `.ai-flow > * { margin: auto }` kuralı onu geniş ekranda ORTAYA
     alıyordu — asistan balonlarıyla aynı sol hizada durmalı. */
  .tam-root .ai-typing { margin-left: 0; margin-right: auto; }

  /* Sohbet balonu geniş ekranda 84% ile aşırı uzardı. */
  .tam-root .ai-bubble { max-width: 60%; }

  /* Boş ekran ortada nefes alsın. */
  .tam-root .ai-intro { padding-top: 48px; }

  /* Ay görünümü: takvim kartı solda, seçili gün ajandası sağda. */
  .desk-cal-month {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(340px, 0.95fr);
    column-gap: 24px;
    align-items: start;
  }
  .desk-cal-snap { margin-top: 0 !important; }

  /* Hafta ve gün görünümleri: okunur genişlikte ortalanmış bant. */
  .desk-cal-week { max-width: 880px; margin-left: auto; margin-right: auto; }
  .desk-cal .rise-1 { max-width: 440px; }        /* Ay/Hafta/Gün segmented'ı */

  /* Gün görünümü: Sabah | Öğleden sonra yan yana (tek bölümde tek kolon). */
  .desk-cal-day {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
    column-gap: 20px;
    align-items: start;
  }
  .desk-cal-day-empty { max-width: 560px; margin-left: auto; margin-right: auto; }

  /* ── MÜŞTERİLER — alfabetik gruplar 2 gazete kolonu ─────────────── */
  .tam-root .desk-cust { --content-max: 960px; }
  .desk-cust .rise-1 { max-width: 480px; }       /* arama alanı */
  .desk-cust-groups {
    columns: 2;
    column-gap: 20px;
  }
  .desk-cust-groups > div { break-inside: avoid; }

  /* ── HİZMETLER — kategori tile'ları tek şerit + hizmet kartları 2 kolon ── */
  .tam-root .desk-serv { --content-max: 1080px; }
  .desk-serv-cats {
    grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)) !important;
  }
  .desk-serv-list {
    display: grid !important;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: stretch;
  }

  /* ── DAHA (hub) — bölümler 2 kolon ızgara ───────────────────────── */
  .tam-root .desk-more {
    --content-max: 1040px;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 22px;
    align-content: start;
  }
  .desk-more-head, .desk-more-biz { grid-column: 1 / -1; }

  /* ── RAPORLAR — geniş kolon (iç 2'li/3'lü grid'ler nefes alır) ──── */
  .tam-root .desk-reports { --content-max: 960px; }
}

@media (min-width: 1280px) {
  /* Çok geniş masaüstü (≥1280px): varsayılan bant + raylar bir tık cömert. */
  :root { --content-max: 880px; }
  .tam-root .desk-dash { --content-max: 1180px; column-gap: 22px; }
  .tam-root .desk-cal  { --content-max: 1140px; }
  .desk-pending-list   { grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); }
}

@media (hover: hover) and (min-width: 1024px) {
  /* Masaüstü hover affordance'ları — yalnız gerçek imleç + ≥1024px.
     DESIGN_SYSTEM: hover scale YOK → yalnız bg-tint ve yumuşak gölge. */
  /* Liste satırları (yalnız etkileşimli olanlar) */
  button.list-row:hover, .list-row.tap-soft:hover { background: var(--surface-2); }

  /* Kart-buton yüzeyleri: kâğıt bir kademe kalkar (shadow-sm → md). */
  button.card.tap-soft:hover { box-shadow: var(--shadow-md); }
  .desk-flow-strip > .tap-soft:hover { box-shadow: var(--shadow-md); }

  /* Ay görünümü gün hücreleri (seçili hücrenin inline bg'si kazanmaya devam eder) */
  .desk-cal-mcard button.tap-soft:not(:disabled):hover { background: var(--surface-2); }

  /* Birincil aksiyonlar */
  .btn-primary:hover, .fab:hover { filter: brightness(1.06); }
}

/* Tweaks panel styling override (let starter own most of it) */

/* ══════════════════════════════════════════════════════════════════
   ABONELİK EKRANI (screen-billing.jsx · migration 076)
   ⚠️ .bl-plan* sınıfları FİYAT gösterir; native kabukta bu blok hiç
   çizilmez (Apple 3.1.3(f), kapı entCanShowPricing()).
   ══════════════════════════════════════════════════════════════════ */
/* Ekranın kendi dolgu ve boş-durum ailesi. Paylaşılan bir ad UYDURULMADI
   (.pad / .empty bu panelde YOK; kullanılsaydı ekran tarayıcı
   varsayılanıyla çizilirdi — nöbetçi tests/panel-css-classes.test.mjs). */
.bl-pad { padding: 4px 16px 24px; }
.bl-empty { padding: 28px 4px; text-align: center; }
.bl-empty-t { font-size: 15px; font-weight: 650; }
.bl-empty-s { font-size: 13px; color: var(--text-2); margin-top: 6px; line-height: 1.5; }
/* Son üç günde uyarı tonu. Kart zeminini değiştirmez, yalnız kenarını. */
.card-warn { border-color: color-mix(in srgb, var(--orange) 45%, var(--hair)); }

.bl-status { display: flex; align-items: center; gap: 12px; padding: 14px 16px; }
.bl-badge {
  width: 38px; height: 38px; flex: 0 0 38px; border-radius: 12px;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.card-warn .bl-badge { background: color-mix(in srgb, var(--orange) 14%, transparent); }
.bl-txt { min-width: 0; }
.bl-line { font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
.bl-sub  { font-size: 13px; color: var(--text-2); margin-top: 2px; }

/* ── Ödeme dönemi şeridi (aylık | yıllık) ───────────────────────────
   Landing #pricing şeridinin panel karşılığı. İki seçenek eşit
   genişlikte: biri diğerinden geniş olsaydı sessiz bir yönlendirme
   olurdu ve yıllık taahhüt kullanıcının kendi kararı olmalı. */
.bl-period {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 12px;
  background: var(--surface-2); border-radius: 12px;
}
.bl-period-b {
  flex: 1; appearance: none; border: none; cursor: pointer;
  background: transparent; color: var(--text-2); font: inherit;
  font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em;
  padding: 8px 6px; border-radius: 9px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  transition: background .18s, color .18s, box-shadow .18s;
}
.bl-period-b.on {
  background: var(--card); color: var(--text);
  box-shadow: 0 1px 3px rgba(0,0,0,.12);
}
.bl-save {
  font-size: 10.5px; font-weight: 700; padding: 2px 6px; border-radius: 999px;
  background: color-mix(in srgb, var(--green) 16%, transparent);
  color: var(--green); white-space: nowrap;
}

/* Paket kartları: tek sütun (mobil-önce), geniş ekranda üçe açılır. */
.bl-plans { display: grid; gap: 10px; }
@media (min-width: 640px) { .bl-plans { grid-template-columns: repeat(3, 1fr); } }

.bl-plan {
  appearance: none; text-align: left; cursor: pointer;
  background: var(--card); color: inherit; font: inherit;
  border: 1.5px solid var(--hair); border-radius: 16px; padding: 14px;
  transition: border-color .18s, background .18s, opacity .18s;
}
.bl-plan:disabled { opacity: .55; cursor: default; }
.bl-plan.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, var(--card)); }
.bl-plan-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bl-plan-n { font-size: 15px; font-weight: 650; }
.bl-plan-tag {
  font-size: 11px; font-weight: 600; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  padding: 2px 8px; border-radius: 999px;
}
.bl-plan-p { font-size: 22px; font-weight: 700; letter-spacing: -0.02em; margin-top: 8px; }
.bl-plan-per { font-size: 13px; font-weight: 500; color: var(--text-2); margin-left: 2px; }
.bl-plan-s { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.bl-note { font-size: 13px; line-height: 1.5; color: var(--text-2); margin: 12px 2px 0; }

/* ══════════════════════════════════════════════════════════════════
   TAM AI — panel içi asistan (screen-ai.jsx)
   Kontrat: docs/TAM-AI-ARASTIRMA.md

   Mobil-önce. Masaüstü ayarı YOK: sohbet tek kolondur ve geniş ekranda
   da tek kolon kalmalı (uzayan satır okunmaz). Bu yüzden bu blokta
   @media (min-width:1024px) kapısı bilerek yok — masaüstü katmanına
   hiç dokunulmuyor.
   ══════════════════════════════════════════════════════════════════ */

/* ── Düzen: SÜTUN AKIŞI, sihirli sayı YOK ───────────────────────────
   İlk sürüm sabit bir başlık + `.ai-flow { padding-top: 106px }` idi.
   İki kırılımda birden bozuldu:
     • masaüstünde `.tam-root .tam-scroll` (özgüllük 0,2,0) üst dolguyu
       30px'e çekiyordu → başlık içeriğin üstüne biniyordu,
     • mobilde 106px başlığın gerçek yüksekliğini tam tutmuyordu.
   Sayı tahmin etmek yerine üç parça doğal yüksekliğini alıyor: başlık ve
   yazma alanı kadar yer kaplar, akış kalanı doldurur. Hiçbir ekranda
   hesaplanacak bir şey kalmaz. */
.ai-screen {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  /* Klavye açılınca kabuk kısalsın (interactive-widget=resizes-content ile
     birlikte): yazma alanı klavyenin altında kalmaz. */
  overflow: hidden;
}

.ai-head {
  flex: 0 0 auto; z-index: 6;
  /* panel/index.html'deki `.tam-scroll` kuralının AYNISI: çentikli
     cihazlarda gerçek güvenli alan, düz ekranda 54px. */
  padding-top: max(54px, calc(env(safe-area-inset-top) + 12px));
  background: var(--bg-overlay);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid var(--hairline);
}
.ai-quota { font-size: 12px; color: var(--text-3); white-space: nowrap; }

/* ── DENEME ROZETİ ──────────────────────────────────────────────────
   Başlığın YANINDA duruyor, sağ bölgede değil: sağ bölge kotayı taşıyor
   ("Bu ay 37 mesaj hakkın kaldı") ve dar telefonda ikisi yan yana
   sığmıyor. Ayrıca "beta" adın bir niteleyicisidir — adın yanında okunur.

   Rozet bir DÜĞME (tıklanınca bilgi sayfası açılır) ama düğme gibi
   BAĞIRMAZ: aksan rengi soluk bir zemin üzerinde, başlıktan küçük.
   Dokunma alanı 24px'lik gövdenin ötesine taşırılıyor (padding değil
   `::after`, yoksa rozet fiziksel olarak büyür ve başlığı iter). */
.ai-title { display: inline-flex; align-items: center; gap: 7px; }
.ai-beta {
  position: relative;
  appearance: none; cursor: pointer; font: inherit;
  font-size: 10.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; line-height: 1;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  border: 0; border-radius: 999px;
  padding: 4px 7px;
  transition: background .18s ease, transform .16s var(--ai-spring);
}
.ai-beta:active { transform: scale(0.92); }
/* Görünmez dokunma payı: 44px'lik hedefe tamamlar, yerleşimi bozmaz. */
.ai-beta::after { content: ''; position: absolute; inset: -11px -8px; }

/* Deneme bilgisi sayfası — iki cümle, tek düğme. Uzun bir uyarı metni
   okunmaz, yalnızca yolu tıkar. */
.ai-beta-body { padding: 18px 22px 26px; }
.ai-beta-body p { margin: 0; font-size: 14.5px; line-height: 1.5; color: var(--text-2); }
.ai-beta-warn {
  display: flex; align-items: center; gap: 8px;
  margin-top: 12px !important; padding: 10px 12px;
  border-radius: 12px; font-weight: 600;
  color: var(--text) !important;
  background: color-mix(in srgb, var(--orange) 12%, transparent);
}
.ai-beta-warn svg { flex-shrink: 0; }
.ai-beta-body .btn { width: 100%; margin-top: 18px; }

.ai-flow {
  flex: 1 1 auto;
  /* min-height:0 ŞART: flex öğesinin varsayılan min-height'ı `auto`dur ve
     içerik uzayınca kap büyür, kaydırma yerine SAYFA taşar. */
  min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 10px 0 14px;
}

/* Giriş: boş sohbet ekranı.
   ⛔ SÜS İKON YOK. Başlık çubuğunda zaten "TAM AI" yazıyor; onun 20px
      altında bir parıltı küresi aynı şeyi ikinci kez söylüyordu ve
      cümleyi aşağı itiyordu. Karşılama artık metinle başlar. */
.ai-intro {
  padding: 46px 20px 8px; text-align: center;
  animation: ai-fade 300ms ease-out both;
}
.ai-intro-title { font-size: 20px; font-weight: 700; letter-spacing: -0.02em; }
.ai-intro-sub {
  font-size: 14px; color: var(--text-2); line-height: 1.5;
  margin: 6px auto 0; max-width: 30em;
}

.ai-chips { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-top: 18px; }
.ai-chip {
  appearance: none; cursor: pointer; font: inherit;
  font-size: 13.5px; font-weight: 550;
  color: var(--text); background: var(--bg-elev);
  border: 1px solid var(--hairline); border-radius: 999px;
  padding: 9px 14px;
  transition: background .18s ease, transform .16s var(--ai-spring), border-color .18s ease;
  /* Çipler TEK TEK gelir: altı çipin aynı anda belirmesi bir "yükleme
     bitti" sıçraması gibi okunuyordu; 45ms'lik kayma onu bir şeride
     çevirir. 8'den sonrası gecikmesiz gelir (liste büyürse son çipler
     için beklemek sabır ister, bilgi vermez). */
  animation: ai-chip-in 340ms var(--ai-soft) both;
}
@keyframes ai-chip-in {
  from { opacity: 0; transform: translate3d(0, 8px, 0); }
  to   { opacity: 1; transform: none; }
}
.ai-chips > *:nth-child(1) { animation-delay: 60ms; }
.ai-chips > *:nth-child(2) { animation-delay: 105ms; }
.ai-chips > *:nth-child(3) { animation-delay: 150ms; }
.ai-chips > *:nth-child(4) { animation-delay: 195ms; }
.ai-chips > *:nth-child(5) { animation-delay: 240ms; }
.ai-chips > *:nth-child(6) { animation-delay: 285ms; }
.ai-chips > *:nth-child(7) { animation-delay: 330ms; }
.ai-chips > *:nth-child(8) { animation-delay: 375ms; }
.ai-chip:active { background: var(--surface-2); transform: scale(0.95); }

/* Balonlar */
.ai-bubble {
  /* width:fit-content ŞART: balon bir blok öğedir ve onsuz kısa bir mesaj
     ("Bugün ne var?") satırın TAMAMINI kaplar; sağa yaslama da görünmez
     olur. max-width tek başına yetmez, o yalnız tavanı koyar. */
  width: fit-content;
  max-width: 84%; padding: 10px 14px; margin: 12px 16px;
  border-radius: 18px; font-size: 15px; line-height: 1.45;
  white-space: pre-wrap; word-break: break-word;
}

/* ── KONUŞMA RİTMİ ──────────────────────────────────────────────────
   Tek bir `margin` yetmiyordu: kullanıcı balonu ile asistan balonu
   arasında da, aynı kişinin arka arkaya iki balonu arasında da AYNI
   8px vardı (üstelik bitişik blokların dikey marjları BİRLEŞTİĞİ için
   gerçekte 16 değil 8px). Sonuç: iki taraf birbirine yapışık görünüyor
   ve gözün "sıra kimde" ayrımını yapacağı hiçbir işaret kalmıyordu
   (kullanıcı bildirdi).

   Ritim konuşmanın kendisinden gelir: SIRA DEĞİŞİNCE nefes, aynı
   kişi devam ederken sıkı duruş. Marj birleşmesi burada işimize
   yarıyor — komşu seçicideki daha büyük değer kazanır, iki kural
   toplanmaz. */
/* YENİ BİR KULLANICI TURU her zaman nefes alır, öncesinde ne olursa
   olsun (balon, kart, onay kartı). Ölçümde bu satır yokken kart sonrası
   kullanıcı balonu 12px'te kalıyordu: cevabın bitip yeni sorunun
   başladığı yer, en çok ayrılması gereken yerdi. */
.ai-flow > * + .ai-me { margin-top: 22px; }
.ai-me + .ai-bot      { margin-top: 22px; }
/* Aynı kişi sürüyorsa sıkı dursun. Yukarıdaki kuralla AYNI özgüllükte
   (0,2,0) olduğu için SIRA belirleyici: bu blok sonra gelmeli. */
.ai-me + .ai-me,
.ai-bot + .ai-bot { margin-top: 5px; }

/* Kart ve onay kartı bir cevabın PARÇASIDIR: kendinden önceki asistan
   balonuna yapışık durur, kullanıcı balonundan sonra ise nefes alır. */
.ai-bot + .ai-card,
.ai-card + .ai-card { margin-top: 6px; }
.ai-me + .ai-card,
.ai-me + .ai-confirm { margin-top: 20px; }

/* ══ HAREKET SÖZLÜĞÜ — SOHBET ═══════════════════════════════════════
   Sohbet ekranının hareketi panelin geri kalanından AYRI bir sözlük
   kullanır ve bunun sebebi ölçülebilir:

   Panelin `--ease-glide`i (easeOutSine) "yumuşak DURAN" bir eğridir;
   20-90px'lik ekran ve çubuk yolları için seçildi. Bir sohbet balonu
   ise DURMAZ, YERLEŞİR: parmağın bıraktığı yerden çıkıp hafifçe
   şişerek oturur. O his sıfır hızla inen bir eğriyle üretilemez, çünkü
   içinde küçük bir aşma (overshoot) vardır. `--ai-spring` tam olarak
   bu: ölçekte tepe ~1.02'ye çıkıp 1'e oturur.

   ⛔ HER GİRİŞ `transform: none` İLE BİTER, `scale(1)` ile değil.
      Bitiş `scale(1)` olsaydı öğe kalıcı bir compositor katmanında
      kalır, metin sonsuza dek grayscale AA ile çizilirdi. `none`
      katmanı düşürür (bkz. panel .rise notu: bu düşüş metinde küt bir
      keskinleşme yapabilir — balonlar KISA olduğu için burada kabul
      edilebilir, uzun metin taşıyan kartlar ölçek DEĞİL yalnız kayma
      alır).

   ⛔ HER GİRİŞ İKİ ANİMASYON: biri transform, biri opacity. Tek
      animasyonda ikisi de aynı eğriyi paylaşırdı; aşan bir eğri
      opacity'ye uygulandığında 1'i geçer, tarayıcı kırpar ve solma
      erken biter (gözle "çat" diye görünür). Ayırınca opacity kendi
      kısa, düz eğrisinde kalır. */
:root {
  --ai-spring: cubic-bezier(0.2, 0.9, 0.3, 1.12);  /* balon oturması (aşmalı) */
  --ai-soft:   cubic-bezier(0.22, 0.68, 0.3, 1);   /* kart/şerit (aşmasız) */
}

@keyframes ai-fade { from { opacity: 0; } to { opacity: 1; } }
/* Kullanıcı balonu SAĞ ALTTAN doğar: yazma alanının bulunduğu köşe. */
@keyframes ai-rise-me  { from { transform: translate3d(8px, 16px, 0) scale(0.76); } to { transform: none; } }
/* Asistan balonu SOL ALTTAN: aynı jest, aynadan. */
@keyframes ai-rise-bot { from { transform: translate3d(-8px, 16px, 0) scale(0.78); } to { transform: none; } }
/* Kart ve onay kartı METİN TAŞIR → ölçek yok, yalnız kısa bir kayma. */
@keyframes ai-rise-card { from { transform: translate3d(0, 14px, 0); } to { transform: none; } }

.ai-me {
  margin-left: auto; background: var(--accent); color: var(--text-on-accent);
  border-bottom-right-radius: 6px;
  box-shadow: 0 1px 2px rgba(15, 15, 20, 0.07);
  transform-origin: 100% 100%;
  animation: ai-rise-me 360ms var(--ai-spring) both, ai-fade 170ms ease-out both;
}
.ai-bot {
  margin-right: auto; background: var(--bg-elev); color: var(--text);
  border: 1px solid var(--hairline); border-bottom-left-radius: 6px;
  transform-origin: 0 100%;
  animation: ai-rise-bot 380ms var(--ai-spring) both, ai-fade 190ms ease-out both;
}

/* ── BALON GRUPLAMA ─────────────────────────────────────────────────
   Kuyruk (küçültülmüş köşe) bir GRUBUN SONUNU işaretler. Arka arkaya
   üç balon yazıldığında üçünde birden kuyruk olması, üç ayrı konuşma
   sırası gibi okunuyordu. `:has` desteklenmeyen tarayıcıda kural hiç
   uygulanmaz ve eski görünüm aynen kalır — kayıp yok. */
.ai-me:has(+ .ai-me)   { border-bottom-right-radius: 18px; }
.ai-bot:has(+ .ai-bot) { border-bottom-left-radius: 18px; }

/* Araç sonucu kartı — sayılar BURADAN okunur, modelin cümlesinden değil */
.ai-card {
  margin: 8px 16px; padding: 12px 14px;
  background: var(--bg-elev); border: 1px solid var(--hairline);
  border-radius: var(--r-card);
  animation: ai-rise-card 340ms var(--ai-soft) both, ai-fade 200ms ease-out both;
}
.ai-card-head {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 650; color: var(--text-2);
  text-transform: none; margin-bottom: 8px;
}
.ai-card-empty { font-size: 14px; color: var(--text-2); }
.ai-card-err {
  display: flex; align-items: center; gap: 8px;
  font-size: 14px; color: var(--text-2);
  border-color: color-mix(in srgb, var(--red) 30%, var(--hairline));
}

.ai-row {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 0; border-top: 1px solid var(--hairline-2);
}
.ai-row:first-of-type { border-top: 0; }
.ai-row-time { font-size: 13.5px; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Kart içi bölüm başlığı (paket takip: "süresi doluyor" / "durgun").
   Bir kartta iki AYRI liste varsa hangisinin ne olduğu yazılmalı;
   yoksa iki farklı sebep tek bir yığın gibi okunur. */
.ai-row-sub {
  padding: 9px 0 3px; font-size: 11.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; color: var(--text-3);
}
.ai-row-main { flex: 1; min-width: 0; display: block; }
.ai-row-main b { display: block; font-size: 14.5px; font-weight: 600; }
.ai-row-main em {
  display: block; font-style: normal; font-size: 12.5px;
  color: var(--text-2); margin-top: 1px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ai-pill {
  font-size: 11px; font-weight: 600; white-space: nowrap;
  color: var(--orange); background: color-mix(in srgb, var(--orange) 14%, transparent);
  padding: 2px 8px; border-radius: 999px;
}
.ai-big { font-size: 30px; font-weight: 700; letter-spacing: -0.02em; }

.ai-slots { display: flex; flex-wrap: wrap; gap: 6px; }
.ai-slot {
  font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent);
  padding: 5px 10px; border-radius: 10px;
}

/* Onay kartı — YAZMANIN TEK KAPISI. Görsel olarak da ayrışır: kalın
   kenarlık ve aksan rengi, "bu bir bilgi değil bir karar" der. */
.ai-confirm {
  margin: 10px 16px; padding: 14px;
  background: var(--bg-elev);
  border: 1.5px solid color-mix(in srgb, var(--accent) 45%, var(--hairline));
  border-radius: var(--r-card);
  animation: ai-rise-card 380ms var(--ai-soft) both, ai-fade 220ms ease-out both;
  /* Karar verilince kart RENK DEĞİŞTİRİR; bu yüzden geçiş listesinde
     hem kenarlık hem zemin var. Anlık değişim "bir şey oldu mu?"
     sorusunu bırakır, 260ms'lik geçiş cevabı verir. */
  transition: border-color 260ms ease, background 260ms ease, opacity 260ms ease;
}
.ai-confirm-danger { border-color: color-mix(in srgb, var(--red) 45%, var(--hairline)); }

/* ── KARAR SONRASI ──────────────────────────────────────────────────
   Onaylandı: kenarlık yeşile döner ve bir kez içeriden aydınlanır —
   "oldu" demenin sessiz hâli, üstelik başarı sesiyle aynı anda.
   Vazgeçildi: kart geri çekilir (soluk, nötr kenarlık); silinmez,
   çünkü kullanıcının neyi reddettiği okunabilir kalmalı. */
.ai-confirm-ok {
  border-color: color-mix(in srgb, var(--green) 55%, var(--hairline));
  /* 560ms: evin hareket bütçesi 600 ms ve İSTİSNA YOK (motion-budget).
     Aydınlanma zaten %20'de tepe yapıyor; kuyruğu kısaltmak hissi
     değiştirmiyor, kuralı korumak ise değiştiriyor. */
  animation: ai-ok-glow 560ms ease-out;
}
@keyframes ai-ok-glow {
  0%   { background: var(--bg-elev); }
  22%  { background: color-mix(in srgb, var(--green) 13%, var(--bg-elev)); }
  100% { background: var(--bg-elev); }
}
.ai-confirm-off {
  border-color: var(--hairline);
  /* ⛔ `!important` ŞART, üşengeçlik değil. ÖLÇÜLDÜ (gerçek Chrome):
     `.ai-confirm` girişi `ai-fade ... both` ile bitiyor ve `both`
     dolgusu animasyonu BİTTİKTEN SONRA DA `opacity: 1` uygulamaya
     devam ediyor. Animasyon değerleri cascade'de normal bildirimleri
     yener → bu satır `!important`süz hiçbir zaman çalışmıyordu
     (vazgeçilen kart sapasağlam duruyordu). */
  opacity: .62 !important;
}
.ai-confirm-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 15px; font-weight: 650; letter-spacing: -0.01em; margin-bottom: 8px;
}
.ai-confirm-line { font-size: 14px; color: var(--text-2); line-height: 1.5; }
.ai-confirm-actions { display: flex; gap: 8px; margin-top: 14px; }
.ai-confirm-actions button { flex: 1; }
.ai-confirm-done {
  display: flex; align-items: center; gap: 6px;
  margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--text-3);
  animation: ai-fade 300ms ease-out both;
}
.ai-confirm-done svg { flex-shrink: 0; }

/* ── YAZIYOR GÖSTERGESİ ─────────────────────────────────────────────
   Artık çıplak üç nokta değil, bir ASİSTAN BALONU. İki kazancı var:
     • Geldiği taraf ve kabuk, ardından gelecek cevabın yerini önceden
       tutar; balon belirdiğinde akış zıplamaz.
     • Noktalar da yalnız sönüp yanmıyor, sırayla ZIPLIYOR. Opacity
       tek başına "bekliyor" der; dalga "yazıyor" der.
   Nokta 7px'lik bir daire, metin değil → transform serbest. */
.ai-typing {
  display: flex; align-items: center; gap: 5px;
  width: fit-content; margin: 12px 16px;
  padding: 13px 16px;
  background: var(--bg-elev); border: 1px solid var(--hairline);
  border-radius: 18px; border-bottom-left-radius: 6px;
  transform-origin: 0 100%;
  animation: ai-rise-bot 380ms var(--ai-spring) both, ai-fade 190ms ease-out both;
}
.ai-typing span {
  width: 7px; height: 7px; border-radius: 50%; background: var(--text-3);
  animation: ai-blink 1.25s infinite ease-in-out;
}
.ai-typing span:nth-child(2) { animation-delay: .16s; }
.ai-typing span:nth-child(3) { animation-delay: .32s; }
@keyframes ai-blink {
  0%, 62%, 100% { opacity: .3;  transform: translate3d(0, 0, 0) scale(0.85); }
  28%           { opacity: .95; transform: translate3d(0, -4px, 0) scale(1); }
}
/* Konuşma ritmi göstergeyi de kapsar: kullanıcı sorduktan sonra nefes,
   asistan sürerken sıkı duruş. Bu satır olmasaydı gösterge kendi
   12px'iyle kalır ve sıra değişimi tam da beklenirken kaybolurdu. */
.ai-me + .ai-typing { margin-top: 22px; }
.ai-bot + .ai-typing,
.ai-card + .ai-typing { margin-top: 6px; }

/* Yazma alanı */
.ai-composer {
  /* Sütun akışının son parçası → absolute DEĞİL. Absolute olsaydı akışın
     son mesajını örterdi ve alttan boşluk yine elle hesaplanırdı. */
  flex: 0 0 auto; z-index: 5;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 14px calc(10px + var(--bottom-inset));
  background: var(--bg-overlay);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-top: 1px solid var(--hairline);
}
.ai-composer input {
  flex: 1; min-width: 0;
  appearance: none; font: inherit;
  /* 16px ALTINA İNMEZ: iOS'ta küçük yazı tipi sayfayı yakınlaştırır ve
     geri çıkmaz (docs: iOS yakınlaşma tuzağı). */
  font-size: 16px;
  color: var(--text); background: var(--bg-elev);
  border: 1px solid var(--hairline); border-radius: 999px;
  padding: 11px 16px;
  transition: border-color .2s ease, box-shadow .2s ease, background .2s ease;
}
.ai-composer input:focus {
  outline: none; border-color: var(--accent);
  /* Halka kenarlığın DIŞINA çizilir (box-shadow), yani yerleşim
     kaymaz; kenarlığı kalınlaştırmak alanı 2px oynatırdı. */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 15%, transparent);
}
.ai-send {
  appearance: none; cursor: pointer; flex-shrink: 0;
  width: 40px; height: 40px; border: 0; border-radius: 50%;
  background: var(--accent); display: grid; place-items: center;
  /* Düğme yalnız SOLMAZ, KÜÇÜLÜR de: yazı yazılır yazılmaz 0.86'dan
     1'e yaylanır. "Artık gönderebilirsin" mesajı, tek bir opaklık
     farkından çok daha okunur — özellikle güneşte. */
  transition: opacity .2s ease, transform 260ms var(--ai-spring);
}
.ai-send:active:not(:disabled) { transform: scale(0.88); }
.ai-send:disabled { opacity: .35; cursor: default; transform: scale(0.86); }

/* ── SESLİ KOMUT ────────────────────────────────────────────────────
   Kontrat: docs/SESLI-KOMUT-ARASTIRMA.md

   Mikrofon GİRDİ KUTUSUNUN SAĞINDA, gönderin hemen solundadır
   (ChatGPT/WhatsApp düzeni; kullanıcı bildirdi 2026-08-31). Sol taraf
   bu ürünlerde EK menüsünün yeridir.

   ⛔ ÇIPLAK İKON, dolu daire DEĞİL. Gönder düğmesi dolu ve renklidir;
   mikrofon da dolu olsaydı iki daire yan yana yarışır ve hangisinin
   birincil eylem olduğu okunmazdı. Mikrofon bir GİRİŞ TERCİHİDİR,
   gönder ise EYLEMDİR. Dolgu yalnız kayıt sürerken beliriyor. */
.ai-mic {
  appearance: none; cursor: pointer; flex-shrink: 0;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  /* ⛔ ÇIPLAK İKON SÖNÜK DURUYORDU (kullanıcı bildirdi 2026-08-31):
     şeffaf zemin + soluk ikon, düğmeyi girdi kutusunun içinde kaybolan
     bir süs hâline getirmişti. Görünürlük ile hiyerarşi ÇELİŞMEZ:
     mikrofon NÖTR bir yüzey alıyor (yükseltilmiş zemin + saç teli
     kenarlık), gönder ise VURGU rengiyle dolu kalıyor. Biri "burada
     bir kontrol var" der, diğeri "birincil eylem bu" der. */
  background: var(--bg-elev);
  border: 1px solid var(--hairline);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .06);
  /* ⛔ Bas-konuş jestinin ön şartı: basılı tutmak metin seçmemeli,
     iOS'ta büyüteç/bağlam menüsü açmamalı. */
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
  /* Parmak düğmenin üstünde dururken sayfa kaymamalı: kayma `up`
     olayını başka yere düşürüp mikrofonu açık bırakırdı. */
  touch-action: none;
  transition: background .2s ease, border-color .2s ease,
              transform 260ms var(--ai-spring);
}
/* Basma geri bildirimi gönderle AYNI dilde (aynı ölçek) — iki düğme
   farklı tepki verirse aynı çubuğa ait olmadıkları hissi doğar. */
.ai-mic:active:not(:disabled) { transform: scale(0.88); }
.ai-mic:disabled { opacity: .35; cursor: default; }
/* Kayıt sürerken düğme KIRMIZI ve nefes alıyor. Kırmızı burada bir
   hata değil, "canlı" demektir (kayıt göstergelerinin evrensel dili). */
.ai-mic-on {
  background: var(--red);
  border-color: var(--red);
  animation: ai-mic-pulse 1.4s ease-in-out infinite;
}
@keyframes ai-mic-pulse {
  0%, 100% { transform: scale(1);    box-shadow: 0 0 0 0 color-mix(in srgb, var(--red) 45%, transparent); }
  50%      { transform: scale(1.06); box-shadow: 0 0 0 7px color-mix(in srgb, var(--red) 0%, transparent); }
}
/* Hareketi azalt tercihi: nabız durur, renk kalır. Bilgi renkte
   taşındığı için hiçbir şey kaybolmuyor. */
@media (prefers-reduced-motion: reduce) {
  .ai-mic-on { animation: none; }
}

/* Durum şeridi composer'ın ÜSTÜNDE. Girdi kutusunun yanına
   sıkıştırılsaydı dar telefonda kutuyu ezerdi ve canlı transkript
   hiç sığmazdı. */
.ai-voice-bar {
  flex: 0 0 auto;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 16px;
  font-size: 13px; color: var(--text-2);
  background: var(--bg-overlay);
  border-top: 1px solid var(--hairline);
}
.ai-voice-err { color: var(--red); }
.ai-voice-text {
  flex: 1; min-width: 0;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
/* ⛔ `direction: rtl` HİLESİ KULLANILMADI. Metnin sonunu göstermenin
   bilinen yolu odur ama Türkçe noktalamayı yeniden sıralar ve bu proje
   RTL'e hazır bir i18n katmanı taşıyor (gerçek RTL dilde hile tersine
   döner). Kırpma JS tarafında, ölçülebilir biçimde yapılıyor
   (screen-ai.jsx · aiVoicePreview). */
.ai-voice-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--red); flex-shrink: 0;
  animation: ai-voice-blink 1.2s ease-in-out infinite;
}
@keyframes ai-voice-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .ai-voice-dot { animation: none; }
}

/* Onay kartındaki uyarı satırı (çift randevu, engelli müşteri).
   Kartın kendisi mavi/kırmızı; uyarı turuncu: "dur, bak" der ama
   "yapma" demez. Karar yine kullanıcınındır. */
.ai-confirm-warn {
  display: flex; align-items: flex-start; gap: 7px;
  margin-top: 10px; padding: 8px 10px;
  font-size: 13px; line-height: 1.45; color: var(--text);
  background: color-mix(in srgb, var(--orange) 12%, transparent);
  border-radius: 10px;
}
.ai-confirm-warn svg { flex-shrink: 0; margin-top: 1px; }

/* Gerçeklik notu: model "oluşturuldu" dediği hâlde onaylanmış hiçbir
   yazma yokken balonun içine düşer (screen-ai.jsx · aiClaimsWrite).
   Onay uyarısıyla AYNI turuncu: ikisi de "dur, bak" diyor. Ayrı bir
   balon DEĞİL, düzelttiği cümleye bitişik — ayrı balon iki ayrı cevap
   gibi okunur ve kullanıcı hangisine inanacağını bilemez. */
.ai-bubble-warn {
  margin-top: 8px; padding: 7px 9px;
  font-size: 12.5px; line-height: 1.45; font-weight: 600;
  color: var(--text);
  background: color-mix(in srgb, var(--orange) 14%, transparent);
  border-radius: 9px;
}


/* ── HAREKET AZALTMA ────────────────────────────────────────────────
   ⛔ `paused` DEĞİL, `none`. Buradaki girişlerin hepsi `both` dolgulu
      ve ilk karesi `opacity: 0`; duraklatılsalardı sohbetin TAMAMI
      görünmez kalırdı (feedback_animasyon_gorunurluk). `none` öğeyi
      kendi doğal, bitmiş hâlinde bırakır.
   Yazıyor göstergesinin noktaları TEK istisna: onlar bir süs değil,
   "bekleniyor" bilgisinin taşıyıcısı. Zıplama kaldırılır, yalnız
   sönüp yanan sakin bir nabız kalır. */
@media (prefers-reduced-motion: reduce) {
  .ai-intro, .ai-chip, .ai-me, .ai-bot, .ai-card, .ai-confirm,
  .ai-confirm-done, .ai-typing {
    animation: none !important;
    opacity: 1;
    transform: none !important;
  }
  .ai-confirm-off { opacity: .62; }
  .ai-send, .ai-chip, .ai-composer input, .ai-confirm { transition: none; }
  .ai-typing span {
    animation: ai-blink-flat 1.4s infinite ease-in-out !important;
  }
  @keyframes ai-blink-flat { 0%, 62%, 100% { opacity: .3; } 28% { opacity: .95; } }
}

/* ════════════════════════════════════════════════════════════════════
   ABONELİK DUVARI — deneme bitti / abonelik durdu
   ────────────────────────────────────────────────────────────────────
   KAPATILAMAZ: kapat düğmesi yok, dışına dokunmak kapatmaz, Esc yok.
   Kart bir sheet DEĞİL (sheet'in kapatma jesti var); kendi katmanı.
   z-index 200: turun (30) ve yüzen barın (90) üstünde, ama Toast'ın
   (250) altında — bir hata mesajı duvarın arkasında kaybolmamalı.
   ════════════════════════════════════════════════════════════════════ */
.ew-wrap {
  position: fixed; inset: 0; z-index: 200;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  padding-top: max(24px, calc(env(safe-area-inset-top) + 16px));
  padding-bottom: max(24px, calc(env(safe-area-inset-bottom) + 16px));
  background: color-mix(in oklab, var(--bg), transparent 12%);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  animation: ew-in 0.28s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}
@keyframes ew-in { from { opacity: 0 } to { opacity: 1 } }

.ew-card {
  width: 100%; max-width: 380px;
  background: var(--bg-elev);
  border-radius: 24px;
  padding: 28px 22px 22px;
  text-align: center;
  box-shadow: var(--shadow-lg, 0 24px 64px rgba(0,0,0,.28));
}
.ew-icon {
  width: 56px; height: 56px; border-radius: 50%; margin: 0 auto 16px;
  background: color-mix(in oklab, var(--orange), transparent 86%);
  display: flex; align-items: center; justify-content: center;
}
.ew-title { font-size: 21px; font-weight: 700; letter-spacing: -0.4px; color: var(--text); }
.ew-body  { margin-top: 8px; font-size: 14.5px; line-height: 1.45; color: var(--text-2); }
.ew-safe {
  margin-top: 14px; padding: 10px 12px; border-radius: 12px;
  background: var(--surface-2);
  font-size: 12.5px; line-height: 1.4; color: var(--text-2);
}
.ew-acts { margin-top: 18px; display: grid; gap: 9px; }
/* <a> de düğme gibi görünmeli: .btn zaten ortalar, yalnız satır
   yüksekliğini eşitliyoruz (a ile button'un baseline'ı farklı). */
.ew-acts .btn { width: 100%; display: inline-flex; align-items: center; justify-content: center; }
.ew-note { margin-top: 12px; font-size: 12.5px; line-height: 1.45; color: var(--orange); }

/* ── DUVARIN İÇİNDEKİ PAKET SEÇİMİ (089) ─────────────────────────────
   Kartlar geldiğinde kart genişler ve İÇİ KAYAR. Duvarın kendisi asla
   kaymaz (sayfa arkası zaten donuk); kaydırma yalnız bu kutudadır ki
   küçük ekranda "Satın al" düğmesi erişilemez kalmasın. */
.ew-card.ew-shop { max-width: 420px; text-align: left; max-height: 100%;
  overflow-y: auto; -webkit-overflow-scrolling: touch; }
.ew-card.ew-shop .ew-icon { margin-left: 0; }
.ew-card.ew-shop .ew-title,
.ew-card.ew-shop .ew-body { text-align: left; }
/* ⚠️ KAYDIRMA KARTIN KENDİSİNDE, kartların içinde DEĞİL. İç içe iki
   kaydırma alanı küçük ekranda "Ödeme yap" düğmesini erişilemez
   kılabilirdi: dış kutu sabit yükseklikte kalır, düğme alt kenarın
   altında sıkışır ve kullanıcı ödeme yapamaz — geçilemez bir ekranda
   bunun bedeli, tıkanmış bir tahsilattır. */
.ew-plans { margin-top: 16px; }
/* Ödeme düğmesi kartla birlikte KAYMAZ: küçük ekranda paket kartları
   kutuyu doldurduğunda düğme alt kenarın altında kalıyor ve kullanıcı
   onu ancak kaydırırsa buluyordu (360x640'ta ölçüldü). Geçilemez bir
   ekranda görünmeyen bir ödeme düğmesi, tıkanmış bir tahsilattır. */
.ew-card.ew-shop .ew-acts {
  position: sticky; bottom: -22px; z-index: 1;
  margin-top: 16px; padding: 12px 0 0;
  background: linear-gradient(to bottom,
    color-mix(in oklab, var(--bg-elev), transparent 100%) 0,
    var(--bg-elev) 14px);
}
/* ── FATURA KİMLİĞİ FORMU (090) ──────────────────────────────────────
   Duvarın içinde de, Abonelik ekranında da aynı bileşen; `bp-compact`
   yalnız duvardaki dar kutuda üst boşlukları kısar. */
.bp-form { text-align: left; }
.bp-form .bl-period { margin-bottom: 12px; }
.bp-form .section-h { margin-top: 16px; }
.bp-compact .section-h { margin-top: 12px; }
.bp-load { padding: 24px 0; text-align: center; color: var(--text-2); font-size: 14px; }
.bp-err {
  margin-top: 12px; padding: 10px 12px; border-radius: 12px;
  background: color-mix(in oklab, var(--red), transparent 90%);
  color: var(--red); font-size: 13px; line-height: 1.4;
}
.bp-acts { margin-top: 16px; display: grid; gap: 9px; }
.bp-acts .btn { width: 100%; }
.bp-kvkk { margin-top: 12px; font-size: 12px; line-height: 1.45; color: var(--text-3); }

.ew-pick {
  font-size: 12px; font-weight: 700; letter-spacing: .3px;
  text-transform: uppercase; color: var(--text-3); margin-bottom: 8px;
}
/* ── SAKİN HÂL: grace bildirimi bir uyarı değil, bir HABER ───────────
   Duvarla aynı iskeleti kullanır ama aynı ağırlıkta görünmemeli: perde
   daha az koyu, bulanıklık daha az. "Hiçbir şey durmadı" cümlesini
   söyleyen bir ekranın, hesabı kapanmış gibi görünmesi yalan olurdu
   (§S: sıfır gösterilir ama bağırmaz). */
.ew-wrap.ew-soft {
  background: color-mix(in oklab, var(--bg), transparent 28%);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}
.ew-icon.ew-icon-calm { background: color-mix(in oklab, var(--accent), transparent 88%); }

/* Masaüstünde kart biraz daha geniş nefes alır. */
@media (min-width: 1024px) {
  .ew-card { max-width: 420px; padding: 32px 28px 24px; }
}

/* Tavana kalan saniye. Yalnız son beş saniyede beliriyor; sürekli bir
   sayaç kullanıcıyı acele ettirir ve konuşmayı bozar. */
.ai-voice-left {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  font-size: 12px; font-weight: 600;
  color: var(--red);
  padding: 2px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--red) 12%, transparent);
}
