/* Renk, yarıçap, ağırlık, tipografi ölçeği ve geçiş süresi bu dosyada SEÇİLMEZ.
   Hepsi tokens.css'te, fonts.css'in yazı tipi için yaptığı işin aynısı: bir
   değer bir yerde seçilir, her yerde var() ile okunur. Aynı koyu palet üç
   dosyada birebir tekrar ediyordu ve üçü zaten ayrışmıştı.

   @import, <head>'e yeni bir <link> koymamak için: bunu yapmak dört HTML
   dosyasına birden dokunmak olurdu. @import'un bir bedeli var — stylesheet
   getirilip ayrıştırılmadan tokens.css istenmiyor, yani bir tur gecikiyor. Bu
   sayfa zaten kimlikli bir panel; ilk boyama süresi vitrinin sorunu, panelin
   değil. Vitrin (landing.html) kendi <link>'ini alsın.

   DİKKAT: bu istek apps/api/app.mjs'teki statik yol tablosunda bir satır
   gerektiriyor ("/tokens.css"). Tablo bir izin listesi ve fallback'i yok; o
   satır olmadan panel RENKSİZ açılır. */
@import url("./tokens.css");

/* --font-heading / --font-body fonts.css'ten geliyor; --accent kiracının kendi
   marka rengi (white-label) ve app.js onu işletme kaydından eziyor. */

* { box-sizing: border-box; }

/* The view switcher relies on the `hidden` attribute; author display rules
   (e.g. .kpi-strip { display: grid }) must never override it. */
[hidden] { display: none !important; }

/* Gövde ne `font-size` ne `line-height` taşıyordu: 1548 satırlık bir stil
   sayfasında okuma satır yüksekliği kararı hiç verilmemişti ve gövde
   tarayıcının `normal` değerine (Inter'de ~1,21) düşüyordu. 16/24, ölçeğin
   temel adımı. */
body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  grid-template-columns: 232px 1fr;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--leading-md);
  font-weight: var(--weight-body);
  letter-spacing: 0;
}

button,
input,
select {
  font: inherit;
}

/* --- Düğme sistemi ----------------------------------------------------------
 *
 * İlke: düğme bir YÜZEYDİR, bir çıkartma değil. Tek düz dolgu, tek ince kenar,
 * tasarlanmış bir basış. Dört varyant (birincil · ikincil · hayalet · yıkıcı) ×
 * beş durum (normal · üzerinde · basılı · odak · devre dışı) × üç beden.
 *
 * Atılanlar ve neden:
 * - 135° gradyan: mavi→yeşil, iki renk tek düğmede. Referans ürünlerin
 *   (Stripe, Linear, Vercel, Lemon Squeezy, Cloudflare) hiçbiri yapmıyor, ve
 *   paletin bütün kontrast tarihi bu süslemeyi ayakta tutmak için yazılmıştı:
 *   ikinci durak beyaz yazıyı taşıyabilsin diye önce --green'den #15803d'ye
 *   taşındı, sonra aksanın kendisi #4f7dff'ten #436ad9'a indi. Gradyan gidince
 *   o kısıt da gidiyor — dolgu tek renk olduğu için kontrast tek bir sayı.
 * - `border: 0`: kenarı olmayan bir dolgu renkli dikdörtgen gibi duruyor.
 *   1px koyu kenar (dolgunun bir adım koyusu) onu yüzeye çeviren tek şey.
 * - `filter: brightness(1.12)`: tasarlanmış bir hover rengi değil, hesaplanmış
 *   bir yıkama. Ölçüldü: #436ad9 üstündeki beyaz 4,88:1'den 4,01:1'e düşüyordu,
 *   yani paletin 2026-08-06'da satın aldığı AA, kullanıcı fareyle dokunduğu an
 *   geri veriliyordu. Üç bildirim, dört ölçüm, dördü de AA altıydı.
 * - 700 ağırlık: ürün arayüzlerinde düğme etiketi 500–600 olur.
 * - 7px yarıçap: hiçbir yerde kararı verilmemiş bir sayıydı.
 *
 * Hover KOYULAŞIR, açılmaz — ve bu bir zevk değil, bir zorunluluk: aksanı bir
 * adım AÇTIĞIMIZDA (#4a71dd) beyaz yazı 4,47:1'e düşüp AA tabanının altına
 * iniyor. Düğme parlayamaz, ancak gömülebilir. Kontrastın dayattığı bu hareket
 * tam da düğmeye fiziksellik veren şey.
 *
 * Odak halkası burada YOK ve olmamalı: base.css tek bir `:focus-visible`
 * kuralını `!important` ile her sayfaya veriyor, çünkü /admin'de Tabler
 * `outline: 0` diyor. Bir satıcı sayfasının kapatabildiği erişilebilirlik
 * tabanı taban değildir. */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: var(--control-md);
  padding: var(--control-pad-md);
  border: 1px solid var(--accent-hover);
  border-radius: var(--radius-control);
  background: var(--accent);
  /* Sabit `white` değildi, olamazdı: --accent kiracının yazdığı bir değer ve
     sunucu #ffffff'i kabul ediyor. app.js mürekkebi seçilen renkten türetiyor
     (brandContrast.mjs); buradaki #fff, renderBusiness koşmadan önceki giriş
     ekranının gördüğü platform varsayılanı ve o varsayılanla uyuşuyor. */
  color: var(--accent-ink, #fff);
  font-size: var(--text-sm);
  line-height: 1;
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: var(--transition-control);
}

button:hover {
  background: var(--accent-hover);
  border-color: var(--accent-pressed);
}

/* Bir adım daha koyu ve 1px aşağı. 80ms: parmağın altında yüzeye gömülüyor. */
button:active {
  background: var(--accent-pressed);
  border-color: var(--accent-pressed);
  transform: translateY(1px);
}

/* Devre dışı OPAKLIKLA DEĞİL gerçek renkle: `opacity` kenarlığı ve metni
   altındaki zeminle karıştırıp aynı düğmeye kartın üstünde başka, çekmecenin
   üstünde başka bir kontrast verdiriyor — yani ölçülemez yapıyor.
   `transform: none`: basılı durum devre dışı bir düğmede de tetiklenebiliyor. */
button:disabled,
button[aria-disabled="true"] {
  background: var(--disabled-bg);
  border-color: var(--disabled-line);
  color: var(--disabled-ink);
  cursor: not-allowed;
  transform: none;
}

/* Üç beden. Varsayılan form bedeni (36px) yukarıda; bunlar sapmalar. */
.btn-sm,
.link-btn,
.catalog-list li button,
.booking-review-actions button,
.attendance-actions button {
  min-height: var(--control-sm);
  padding: var(--control-pad-sm);
  gap: 6px;
}

.btn-lg {
  min-height: var(--control-lg);
  padding: var(--control-pad-lg);
}

/* Kaba işaretçide üç beden de 44px'e çıkıyor. Bu kod tabanı dokunma tabanını
   her yerde 44 kullanıyor (.back-button, .topbar, .lang-switch); WCAG 2.5.8'in
   24px'i taban, 44 bizim kararımız. */
@media (pointer: coarse) {
  button,
  .btn-sm,
  .btn-lg,
  .link-btn,
  .catalog-list li button,
  .booking-review-actions button,
  .attendance-actions button {
    min-height: var(--control-touch);
    padding: 0 18px;
  }
}

/* İkincil: kendi zemini var. Kartla aynı #121a26 olduğunda düğmenin kart
   üstünde hiç zemini yoktu, yalnız 1px çizgi — estetik değil işlevsel bir
   kusur. #1b2534 karttan ölçülebilir bir adım ayrı, üstündeki yazı 13,11:1. */
.secondary {
  background: var(--surface-2);
  border-color: var(--line);
  color: var(--ink);
}

.secondary:hover {
  background: var(--surface-2-hover);
  border-color: var(--line-strong);
}

.secondary:active {
  background: var(--surface-2-pressed);
}

/* Hayalet: zemini de kenarı da yok. Yıkıcı olmayan, ikincil bile olmayan
   eylemler için — bir satırın içindeki "Düzenle" gibi. */
.ghost,
.link-btn {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.ghost:hover,
.link-btn:hover {
  background: var(--surface-2);
  border-color: transparent;
  color: var(--ink);
}

.ghost:active,
.link-btn:active {
  background: var(--surface-2-hover);
}

/* Yıkıcı DOLGULU DEĞİL. Dolgulu kırmızı bir ekranda altı kez geçerse hiçbiri
   uyarmıyor demektir; dolgusu yalnız onay penceresindeki son adımın hakkı
   (--danger-solid, beyaz yazı 6,02:1). Buradaki hâli çerçeveli: metin koyu
   zeminde 5,43:1, açık zeminde 6,02:1. */
.danger {
  background: transparent;
  border-color: var(--danger-line);
  color: var(--danger-ink);
}

.danger:hover {
  background: var(--danger-wash);
  border-color: var(--danger-line-strong);
}

.danger:active {
  background: var(--danger-bg);
}

.danger-solid {
  background: var(--danger-solid);
  border-color: var(--danger-solid);
  color: var(--danger-solid-ink);
}

.danger-solid:hover {
  background: color-mix(in srgb, var(--danger-solid) 93.8%, #000);
  border-color: color-mix(in srgb, var(--danger-solid) 82.3%, #000);
}

.danger-solid:active {
  background: color-mix(in srgb, var(--danger-solid) 82.3%, #000);
}

/* Devre dışı her varyantı yener: dört varyantın dördü de aynı ölü yüzeye
   düşmeli, yoksa "basılamaz" dört farklı şeye benziyor. */
.secondary:disabled,
.ghost:disabled,
.link-btn:disabled,
.danger:disabled,
.danger-solid:disabled {
  background: var(--disabled-bg);
  border-color: var(--disabled-line);
  color: var(--disabled-ink);
}

.ghost:disabled,
.link-btn:disabled,
.danger:disabled {
  background: transparent;
}

.sidebar {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--line);
  background: var(--side);
  padding: 24px 16px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  text-decoration: none;
  font-size: var(--text-lg);
  font-weight: var(--weight-display);
  line-height: 1.15;
}

/* `.brand-mark` burada İKİNCİ kez tanımlıydı (kenarlıklı kare + yatay çubuk) ve
   bu sayfa şekli tanımlayan asıl dosyayı — `/bannerView.css` — yüklemediği için
   ekranda görülen işaret buydu. Tanım silindi, dosya `<head>`e bağlandı;
   gerekçe orada yazılı.

   Neden burada kalamazdı: işaret `--accent` ile boyanıyordu ve `--accent`
   işletme kaydından eziliyor, yani platformun işareti kiracının markasının
   rengine bürünüyordu. `bannerView.css` bu kararı açıkça ters yönde veriyor
   (`--primary`, "işaret PLATFORMUN mavisi, kiracının değil"). İki dosya aynı
   sınıf için zıt iki karar taşıyorsa, ekranda görünen kararı yükleme sırası
   seçer — ve o bir karar değildir. */

nav {
  display: grid;
  gap: 8px;
  margin-top: 42px;
}

.nav-item {
  width: 100%;
  justify-content: flex-start;
  text-align: left;
  /* Kenar rengi de sıfırlanmak zorunda: genel `button` kuralı artık aksanın bir
     adım koyusunu kenar veriyor, ve kenar çubuğundaki her öğe o çerçeveyi
     taşısaydı üçü de birincil eylem gibi okunurdu. */
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.nav-item:hover {
  background: var(--hover);
  border-color: transparent;
  color: var(--ink);
}

.nav-item.active,
.nav-item.active:hover {
  background: var(--accent-tint-bg);
  border-color: transparent;
  color: var(--accent-tint-text);
}

/* Dil anahtarı. Bu panelin hiç dil kontrolü yoktu: `users.locale` alanı vardı,
   sunucu onu kabul ediyordu, onu yazabilecek hiçbir düğme yoktu.

   Dosyanın genel `button` kuralı degrade zemin ve beyaz yazı veriyor; bir
   şeritteki iki düğmenin ikisi de öyle görünürse hangisinin seçili olduğu
   anlaşılmaz. Seçili olan, panelin başka yerde de "seçili" demek için
   kullandığı biçimi alır (bkz. `.nav-item.active`); seçili olmayan yalnız
   --muted yazı. 44px, kod tabanının her yerdeki dokunma tabanı. */
.lang-switch {
  display: inline-flex;
  align-self: flex-start;
  margin-top: 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  overflow: hidden;
}

.lang-switch button {
  min-width: var(--control-touch);
  min-height: var(--control-touch);
  padding: 8px 14px;
  background: transparent;
  border: 0;
  border-radius: 0;
  color: var(--muted);
  font-weight: var(--weight-medium);
  font-size: var(--text-sm);
}

.lang-switch button:hover {
  background: var(--hover);
  color: var(--ink);
}

.lang-switch button[aria-pressed="true"] {
  background: var(--accent-tint-bg);
  color: var(--accent-tint-text);
}

.clinic-switch {
  margin-top: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  padding: 13px;
  color: var(--muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.shell {
  min-width: 0;
  padding: 22px 24px 32px;
  /* Bu kural iki leke için yazılmıştı ve LEKELER ARTIK YOK (yukarıda, satır 441
     civarındaki blokta gerekçesi yazılı). Ne yaptıklarını kayıt için: 320px
     genişliğindeki `.topbar::after` `right:10%`te duruyor, 60px sağa sürüklenip
     1,15 kat büyüyordu — 390px'lik bir ekranda sağ kenarı 416px'e ulaşıyor, yani
     panel her görünümde, 16 saniyelik bir çevrimde 26px'e kadar yana kayıyordu.
     İlk ölçümde "8px" yazılmıştı; hareketli bir sayının bir karesi okunmuştu.

     Kural KALIYOR ve sebebi artık başka: yatay taşma bu panelde tek bir dekora
     bağlı değil — geniş tablolar, uzun işletme adları ve `min-width:0` almayı
     unutan bir gelecek grid hücresi aynı şeyi yapar, ve sonucu telefonda bütün
     sayfanın yana kayması olur. `clip`, `hidden` değil: hidden burayı bir kaydırma
     kabı yapar ve yanında `overflow-y` `auto`ya hesaplanır — sayfanın içinde
     ikinci bir dikey kaydırma çubuğu. Kırpma payı kenarı border kutusuna itiyor. */
  overflow-x: clip;
  overflow-clip-margin: 24px;
}

/* Amber, not red: nothing is broken. It is a state the reader has to keep in
   mind for as long as the tab is open, which is what a warning colour is for. */
.impersonation-banner {
  margin: 0 0 18px;
  padding: 12px 14px;
  border: 1px solid var(--warning-ink);
  border-radius: var(--radius-container);
  background: var(--warning-bg);
  color: var(--ink);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

h1,
h2,
p {
  margin: 0;
}

h1,
h2,
.brand {
  font-family: var(--font-heading);
}

/* h1 24px/1.2 (= 28,8px kutu) ve h2 15px/1.2 (= 18px) idi. İki kusur birden:
   h2 gövdeden (16px) KÜÇÜKTÜ — bir bölüm başlığı altındaki paragraftan küçük
   yazılıyordu, yani ekran okuyucunun "ikinci seviye" dediği şeyi göz "etiket"
   olarak görüyordu — ve 24'ten 15'e tek adımda 1,6 kat düşüş vardı, arada
   hiçbir basamak yoktu. Hiyerarşi boyla kurulamayınca ağırlıkla (800'e karşı
   700) ve renkle kurtarılmaya çalışılmıştı.
   Şimdi h1 24/32, h2 20/28, gövde 16/24: her adım 8'in katı ve h1 gövdenin
   tam 1,5 katı. */
h1 {
  font-size: var(--text-xl);
  line-height: var(--leading-xl);
  font-weight: var(--weight-display);
}

h2 {
  font-size: var(--text-lg);
  line-height: var(--leading-lg);
  font-weight: var(--weight-heading);
}

/* BURADA İKİ `.topbar` PSÖDO-ELEMANI VARDI ve silindiler (tasarım haritası
   §8, satır 19). Ne oldukları: 320×320px, `blur(70px)`, `opacity:.32`,
   `mix-blend-mode: screen`, `animation: imp-drift 16s infinite alternate` —
   panel başlığının arkasında sonsuza kadar sürüklenen iki renkli leke, ve
   onları besleyen `@keyframes imp-drift` ile `.topbar{position:relative}`.

   Neden silindiler, iki sebep:
   1. `mix-blend-mode: screen` tanımı gereği AÇIK zeminde neredeyse hiçbir şey
      yapmıyor — screen, sonucu her zaman iki girdiden açık olana doğru itiyor,
      ve zemin zaten beyaza yakınsa itecek yer kalmıyor. Yani bu dekor açık
      temada sessizce ölüyordu: aynı ürünün iki yüzeyinden birinde var, ötekinde
      yok. Görülmeyen bir süs, bakımı olmayan bir süstür.
   2. İnsanların bütün gün içinde çalıştığı bir yüzeyde, duraklatma denetimi
      olmayan sonsuz bir animasyon. base.css'in `prefers-reduced-motion` bloğu
      onu duraklatıyordu; ama bir hareketi yalnız işletim sistemi istediğinde
      durdurmak, hareketin orada olmasını gerektiren bir sebep bulmuş olmak
      demek değil.

   base.css'teki blok SİLİNMEDİ ve silinmemeli: tek tek animasyon adı saymıyor,
   bundan sonra eklenecek olanı da kapsıyor. */

.topbar p,
.panel-header p,
.muted,
small {
  color: var(--muted);
  font-size: var(--text-xs);
}

.top-actions,
.toolbar {
  display: flex;
  gap: 10px;
  align-items: center;
}

#appointment-search {
  width: min(260px, 34vw);
}

.kpi-strip {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}

.kpi-strip article {
  min-height: 108px;
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  background: var(--panel);
  padding: 18px;
}

.kpi-strip span {
  display: block;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
  text-transform: uppercase;
}

.kpi-strip strong {
  display: block;
  margin: 7px 0 2px;
  color: var(--primary);
  font-size: var(--text-2xl);
  line-height: var(--leading-2xl);
}

.risk-kpi strong { color: var(--danger-ink); }
.risk-kpi b { color: var(--danger-ink); }

/* Subscription purchase surface (Lemon Squeezy) ---------------------------- */
.billing-period-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin: 14px 0 12px;
  padding: 5px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-container);
}
.billing-period-option {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: var(--control-md);
  padding: var(--control-pad-sm);
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-weight: var(--weight-medium);
  cursor: pointer;
}
.billing-period-option.is-active { background: color-mix(in srgb, var(--primary) 16%, transparent); color: var(--ink); }
.billing-period-badge {
  padding: 3px 7px;
  border-radius: var(--radius-round);
  background: var(--success-bg);
  color: var(--success-ink);
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
  white-space: nowrap;
}
.billing-plan-matrix { display: grid; gap: 10px; }
.billing-plan { padding: 13px; border: 1px solid var(--line-soft); border-radius: var(--radius-container); }
.billing-plan.is-current { border-color: var(--primary); }
.billing-plan-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.billing-plan-price { font-weight: var(--weight-heading); }
.billing-plan-current { margin: 8px 0 0; color: var(--primary); font-size: var(--text-sm); font-weight: var(--weight-medium); }
.billing-plan-buy { width: 100%; margin-top: 10px; }

/* İptal, plan matrisinin altında ayrı bir şerit. Matrisle aynı hizada değil:
   kartların yaptığı iş satın almak, bunun yaptığı iş onun tersi, ve ikisini yan
   yana koymak hangi düğmeye bastığını karıştıran tek düzen olurdu. */
.billing-manage { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
.billing-manage p { margin: 0 0 10px; }
/* İki düğme eşit ağırlıkta ve aynı satırda; dar ekranda alt alta iniyor.
   Onayı küçültüp "Vazgeç"i büyütmek, düzenlemelerin adını koyduğu desen. */
.billing-manage-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.billing-manage-actions button { flex: 1 1 160px; }
/* Fatura listesi. Tarayıcı varsayılanı burada yanlış: madde imleri ve 40px'lik
   girinti, kartın geri kalanı 0 hizasındayken listeyi sağa kaydırıyordu. Yeni bir
   sınıf değil, var olan `.billing-manage` üzerinden bir alt seçici -- /consumer bu
   dosyayı yüklemiyor ama bir fatura listesi de çizmiyor, yani 2026-08-14'ün
   eksik-stil hatası buraya ulaşmıyor. */
.billing-manage ul { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
@media (min-width: 620px) { .billing-plan-matrix { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.workspace {
  display: grid;
  grid-template-columns: minmax(620px, 1fr) 330px;
  gap: 16px;
}

/* Two columns need 620 + 16 + 330 = 966px, and the workspace only gets what is
   left after the 232px sidebar and 24px of padding -- so the layout stops
   fitting at roughly 1240px of viewport, not at the 1000px where the rest of
   the responsive block collapses. Between those two numbers the right rail was
   pushed off-screen: measured 213px of horizontal overflow at 1024x768 and
   37px at 1200x800, which covers common tablet-landscape and laptop widths. */
@media (max-width: 1240px) {
  .workspace {
    grid-template-columns: 1fr;
  }
}

.timeline-panel,
.right-rail section,
.create-panel {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  background: var(--panel);
}

.panel-header {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
}

.panel-header.compact {
  padding: 14px 16px;
}

/* Girdi ve secim dugmeyle AYNI bedende: satir ici formlar `align-items: end`
   ile diziliyor ve 40px girdi ile 36px dugme yan yana geldiginde ikisi de
   yanlis hizalanmis gorunuyor. Tek beden, tek hiza. */
select,
input {
  min-height: var(--control-md);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--field);
  color: var(--ink);
  padding: var(--control-pad-md);
  font-size: var(--text-sm);
}

select option {
  background: var(--panel);
  color: var(--ink);
}

.table-wrap {
  width: 100%;
  overflow: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
  /* Bu satır `@media (max-width: 1000px)` bloğunun İÇİNDEYDİ ve orada hiçbir
     işe yaramıyordu -- çünkü tabloyu ezen şey dar EKRAN değil, dar KAPSAYICI.
     Gösterge panelinde tablo `.workspace`in `minmax(620px, 1fr)` sütununda
     duruyor ve sağ raf 330px alıyor; yani 1280px'lik bir dizüstünde ekran
     genişken kapsayıcı 652px'e iniyor. Medya sorgusu yanlış şeyi ölçüyordu.

     Aşağıdaki sütunların sabit toplamı 76+154+220+104+88 = 642px, üstüne
     yüzdeli iki sütun (%22 + %17) geliyor. 642px sabit + %39 yüzde, 100%'e
     ancak ~1053px'te sığıyor; altında `table-layout: fixed` yüzdeli sütunları
     eziyor. Ölçüldü (2026-08-21, 1280x800): "Müşteri" sütunu **6 piksele**
     düşüyor ve içeriği 115px taşıyor, "Hizmet" 4 piksele -- müşterinin adı ve
     telefonu durum rozetinin üstüne basıyor. 1440'ta hâlâ 25px taşma var.

     `min-width` her genişlikte geçerli olunca `.table-wrap`in zaten ilan
     ettiği `overflow: auto` devreye giriyor: tablo ezilmek yerine kayıyor.
     930px'te yüzdeli sütunlara 288px kalıyor (Müşteri ~162px, Hizmet ~126px),
     ki ad + telefon ve en uzun hizmet adı bu genişliklerde okunuyor. */
  min-width: 930px;
}

th,
td {
  border-bottom: 1px solid var(--line-soft);
  padding: 12px 14px;
  text-align: left;
  vertical-align: middle;
  font-size: var(--text-sm);
}

th:nth-child(1), td:nth-child(1) { width: 76px; }
th:nth-child(2), td:nth-child(2) { width: 22%; }
th:nth-child(3), td:nth-child(3) { width: 17%; }
th:nth-child(4), td:nth-child(4) { width: 154px; }
th:nth-child(5), td:nth-child(5) { width: 220px; }
th:nth-child(6), td:nth-child(6) { width: 104px; }
th:nth-child(7), td:nth-child(7) { width: 88px; }

th {
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
}

td strong,
td small {
  display: block;
}

td small {
  white-space: nowrap;
}

.time {
  color: var(--ink);
  font-weight: var(--weight-heading);
}

.status {
  display: inline-flex;
  min-width: 116px;
  justify-content: center;
  border-radius: var(--radius-round);
  padding: 6px 8px;
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
}

/* Dört durumun dördü de token okuyor. Sabit `rgba(255,255,255,.08)` açık
   temada beyaz kartın üstünde GÖRÜNMEZ; "gönderildi" rozeti zemin olmadan
   yalnız gri yazıya düşerdi ve dört durumdan üçü rozet, biri metin olurdu.
   Ölçülen açık tema oranları: başarı 5,12:1 · uyarı 5,61:1 · hata 5,22:1 ·
   nötr 5,03:1. */
.status.confirmed { background: var(--success-bg); color: var(--success-ink); }
.status.pending { background: var(--warning-bg); color: var(--warning-ink); }
.status.sent { background: var(--neutral-bg); color: var(--neutral-ink); }
.status.risky { background: var(--danger-bg); color: var(--danger-ink); }
.status.cancelled { background: var(--neutral-bg); color: var(--neutral-ink); }

.channel {
  display: block;
  color: var(--ink);
  font-weight: var(--weight-medium);
}

.link-btn {
  width: 72px;
  color: var(--muted);
  white-space: nowrap;
}

.empty-state {
  padding: 40px;
  text-align: center;
}

.empty-state strong,
.empty-state span {
  display: block;
}

.empty-state button {
  margin: 16px auto 0;
}

.right-rail {
  display: grid;
  gap: 16px;
  align-content: start;
}

#risk-badge {
  min-width: 28px;
  border-radius: var(--radius-round);
  background: var(--danger-bg);
  color: var(--danger-ink);
  text-align: center;
  padding: 4px 8px;
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
}

.risk-list article {
  display: grid;
  grid-template-columns: 58px 1fr auto;
  gap: 10px;
  align-items: center;
  border-top: 1px solid var(--line-soft);
  padding: 13px 16px;
}

.risk-list strong {
  color: var(--danger-ink);
}

.risk-list span,
.risk-list small {
  display: block;
}

.risk-list em {
  color: var(--muted);
  font-size: var(--text-xs);
  font-style: normal;
}

.booking-review-actions {
  display: flex;
  gap: 6px;
}

.booking-review-actions button {
  font-size: var(--text-xs);
  white-space: nowrap;
}

.summary-list {
  margin: 0;
  padding: 6px 16px 16px;
}

.summary-list div {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid var(--line-soft);
  padding: 13px 0;
}

dt {
  color: var(--muted);
}

dd {
  margin: 0;
  color: var(--primary);
  font-weight: var(--weight-heading);
}

/* "Closed" is a transform, and the accessibility tree does not read transforms:
   tabbing through the dashboard walked ten controls parked below the viewport,
   where no focus ring can be seen and Enter ran reportValidity() on fields
   nobody could read. The state that actually closes it is the `inert` attribute
   app.js sets through dialog.js -- this transform is only the animation of it.
   The markup therefore ships with `inert` already on. */
.create-panel {
  position: fixed;
  left: 256px;
  right: 24px;
  bottom: 20px;
  transform: translateY(calc(100% + 28px));
  transition: transform .22s ease;
  z-index: 10;
}

.create-panel.open {
  transform: translateY(0);
}

form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  align-items: end;
  padding: 16px;
}

label {
  display: grid;
  gap: 6px;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

/* --- Yeni randevu çekmecesi: dokuz kontrol, tek satır -----------------------
 *
 * Global `form` kuralı yukarıda `repeat(auto-fit, minmax(150px, 1fr))` diyor.
 * Çekmece `left:256px; right:24px` ile ~1620px açılıyor, dokuz kontrolün hepsi
 * 150px eşiğini geçtiği için `auto-fit` hepsini TEK satıra diziyordu: alan
 * başına ~165px. O genişlikte `datetime-local` girdisi ve onay kutusu kendi
 * kutularını taşırıyor, etiketlerin hangi alana ait olduğu okunmuyordu.
 *
 * Sütun sayısını içeriğin anlamı değil, çekmecenin genişliği belirliyordu --
 * `auto-fit` bu formda yanlış araç. Dört sütun sabit; alan başına ~390px, yani
 * en geniş kontrol olan tarih/saat bile rahat sığıyor. Global kural olduğu gibi
 * bırakıldı: ayarlar, giriş ve tüketici formları ondan besleniyor.
 */
#appointment-form {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px 16px;
}

/* Kaydet her kırılımda son sütunda kalıyor: formun bittiği yer, gözün satırı
   bıraktığı yerle aynı olsun. Tek sütuna düştüğünde tam genişliğe yayılır. */
#appointment-form button[type="submit"] {
  grid-column: -2 / -1;
}

@media (max-width: 1100px) {
  #appointment-form {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  #appointment-form {
    grid-template-columns: 1fr;
  }
}

.check {
  grid-template-columns: 18px 1fr;
  align-items: center;
  color: var(--ink);
  min-height: var(--control-md);
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  padding: 0 10px;
  cursor: pointer;
  align-self: end;
}

.check input {
  min-height: 18px;
  width: 18px;
  margin: 0;
}

/* Yalnız ekran okuyucuya. Rafın kehribar/kırmızı noktası bir metin taşıyor ve o
   metin görünmüyor; rengi görmeyen biri için "kurulum bekliyor" ile "sorun var"
   arasındaki farkı taşıyan tek şey bu. `clip-path` yerine klasik kırpma kutusu:
   satır kutusunu 1px'e indirmek, metnin yine de okunmasını sağlayan tek
   güvenilir biçim. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.settings-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  background: var(--panel);
  padding-bottom: 16px;
}

.settings-card form {
  grid-template-columns: 1fr;
  padding: 16px 18px 0;
}

.settings-hint {
  padding: 0 18px;
  margin-bottom: 10px;
}

.settings-actions {
  display: flex;
  gap: 10px;
  padding: 0 18px;
  margin-top: 12px;
}

.wa-badge {
  border-radius: var(--radius-round);
  padding: 5px 10px;
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
}

.wa-badge.wa-disconnected { background: var(--neutral-bg); color: var(--neutral-ink); }
/* "Bilinmiyor" ile "bağlı değil" aynı renkte, ve bu bilerek: ikisi de bir
   olumsuzluk DEĞİL, bir bilgi yokluğu. Ayrı bir renk vermek, sorulmamış bir
   soruya bir durum atfetmek olurdu — ayrımı kelime taşıyor, boya değil. */
.wa-badge.wa-neutral { background: var(--neutral-bg); color: var(--neutral-ink); }
.wa-badge.wa-connected { background: var(--success-bg); color: var(--success-ink); }
.wa-badge.wa-error { background: var(--danger-bg); color: var(--danger-ink); }

.wa-detail {
  padding: 0 18px;
}

.wa-error-text {
  color: var(--danger-ink);
  font-size: var(--text-xs);
  margin: 4px 0 0;
}

/* Keşfet kapıları. Renk tek başına taşıyıcı değil: açık kapı ✓ ile, kapalı kapı
   • ile işaretli, metin de zaten iki durumda iki ayrı cümle. */
.gate-list {
  list-style: none;
  margin: 8px 0;
  padding: 0;
  display: grid;
  gap: 6px;
}

.gate {
  display: grid;
  grid-template-columns: 16px 1fr;
  gap: 8px;
  align-items: start;
  font-size: var(--text-sm);
  line-height: 1.45;
}

.gate-mark {
  font-weight: var(--weight-heading);
  text-align: center;
}

.gate-open { color: var(--success-ink); }
.gate-closed { color: var(--muted); }

/* `.form-error` bu dosyada hiç tanımlı değildi, oysa index.html onu
   `#billing-checkout-error` için zaten kullanıyordu — yani ödeme kartının hata
   satırı gövde metniyle aynı renkte, hiç öne çıkmadan basılıyordu. */
.form-error {
  margin: 0;
  color: var(--danger-ink);
  font-size: var(--text-sm);
  line-height: 1.45;
}

.form-error[hidden] { display: none; }

input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
  border-color: var(--danger-ink);
  outline: 1px solid var(--danger-ink);
}

@media (max-width: 1000px) {
  body {
    grid-template-columns: 1fr;
  }

  .sidebar {
    min-height: auto;
    display: grid;
    grid-template-columns: 1fr;
    align-items: start;
    gap: 18px;
    overflow: hidden;
  }

  nav {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
    margin-top: 0;
  }

  .nav-item {
    text-align: center;
    padding-inline: 8px;
  }

  .clinic-switch {
    display: none;
  }

  .topbar {
    display: grid;
    align-items: start;
  }

  .top-actions {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .toolbar {
    width: 100%;
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  #appointment-search {
    width: 100%;
    grid-column: 1 / -1;
  }

  .workspace,
  .kpi-strip {
    grid-template-columns: 1fr;
  }

  /* `table { min-width: 620px }` buradaydı ve zaten ölüydü: aynı medya
     sorgusunun ilerideki bir bloğu 930px yazıyordu, yani art arda gelen iki
     kuraldan sonraki kazanıyordu ve bu 620 hiçbir ekranda uygulanmıyordu.
     Ölü olduğu için de kimse fark etmedi; taban kural 930'a taşınınca bu satır
     ANİDEN canlanır ve dar ekranda tabloyu 620px'e ezerdi -- sabit sütunların
     toplamı 642px olduğuna göre yüzdeli iki sütuna sıfır kalırdı. Bir kuralın
     zararsız görünmesi, ölü olmasından kaynaklanıyor olabilir. */

  .create-panel {
    left: 16px;
    right: 16px;
  }

  form {
    grid-template-columns: 1fr;
  }
}

/* --- Takvim gorunumu (haftalik kolonlar / aylik grid) --- */

.calendar-view {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  padding: 20px;
  margin-bottom: 24px;
}

.cal-mode {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  overflow: hidden;
}

.cal-mode-btn {
  border: 0;
  border-radius: 0;
  background: var(--panel);
  color: var(--muted);
  min-height: var(--control-md);
}

.cal-mode-btn.active {
  background: var(--accent);
  color: var(--accent-ink, #fff);
}

.calendar-grid.cal-week {
  display: grid;
  grid-template-columns: repeat(7, minmax(120px, 1fr));
  gap: 10px;
  overflow-x: auto;
}

.cal-day {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-container);
  padding: 8px;
  min-height: 140px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: rgba(255, 255, 255, .02);
}

.cal-day header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 6px;
  border-bottom: 1px solid var(--line);
  padding-bottom: 6px;
}

.cal-day header span {
  color: var(--muted);
  font-size: var(--text-xs);
}

.cal-day.cal-today {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.cal-empty {
  text-align: center;
  margin: auto 0;
}

.cal-chip {
  display: grid;
  gap: 1px;
  text-align: left;
  background: var(--accent-tint-bg);
  color: var(--ink);
  border: 1px solid var(--line-soft);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-control);
  padding: 6px 8px;
  min-height: 0;
  font-weight: var(--weight-medium);
}

.cal-chip:hover { background: var(--hover); }
.cal-chip small { color: var(--muted); }
.cal-chip.risky { border-left-color: var(--danger-ink); }
.cal-chip.pending { border-left-color: var(--warning-ink); }
.cal-chip.confirmed { border-left-color: var(--success-ink); }
.cal-chip.cancelled { border-left-color: var(--muted); opacity: .6; }

.calendar-grid.cal-month {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
}

.cal-month-head {
  text-align: center;
  color: var(--muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  padding: 4px 0;
}

.cal-month-cell {
  position: relative;
  min-height: 72px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-control);
  background: rgba(255, 255, 255, .02);
  color: var(--ink);
  font-weight: var(--weight-medium);
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
  padding: 8px;
}

.cal-month-cell:hover { background: var(--hover); }
.cal-month-cell.cal-outside { opacity: .45; }
.cal-month-cell.cal-today {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.cal-count {
  position: absolute;
  right: 8px;
  bottom: 8px;
  background: var(--accent);
  color: var(--accent-ink, #fff);
  border-radius: var(--radius-round);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  min-width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px;
}

/* --- Hizmet katalogu + personel kartlari (Ayarlar) --- */

.inline-form {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr auto;
  gap: 10px;
  align-items: end;
}

#staff-form.inline-form {
  grid-template-columns: 1fr auto;
}

.catalog-list {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: grid;
  gap: 8px;
}

.catalog-list li {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  padding: 8px 12px;
}

.catalog-list li button {
  padding: var(--control-pad-sm);
}

@media (max-width: 900px) {
  .calendar-grid.cal-week {
    grid-template-columns: repeat(7, minmax(150px, 1fr));
  }

  .inline-form {
    grid-template-columns: 1fr;
  }
}
/* --- Dogrulanmis pazar yeri, katilim ve raporlar --- */

.marketplace-view,
.reports-view {
  display: grid;
  gap: 18px;
}

.marketplace-hero {
  display: flex;
  justify-content: space-between;
  align-items: end;
  gap: 24px;
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  padding: 24px;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--accent) 18%, var(--panel)), var(--panel) 55%),
    var(--panel);
}

.marketplace-hero h2 {
  max-width: 780px;
  margin: 7px 0 9px;
  font-size: clamp(var(--text-lg), 3vw, var(--text-2xl));
}

.eyebrow {
  color: var(--accent-tint-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
  letter-spacing: .08em;
  text-transform: uppercase;
}

.marketplace-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.marketplace-search-card,
.marketplace-results-card,
.marketplace-appointments-card {
  grid-column: 1 / -1;
}

.card-body {
  display: grid;
  gap: 12px;
  padding: 16px 18px;
}

.trust-card {
  min-width: 210px;
  border: 1px solid color-mix(in srgb, var(--success-ink) 45%, var(--line));
  border-radius: var(--radius-container);
  background: var(--success-bg);
  color: var(--success-ink);
  padding: 12px 14px;
  font-size: var(--text-sm);
  font-weight: var(--weight-heading);
}

.marketplace-results {
  display: grid;
  gap: 10px;
  padding: 16px 18px;
}

.marketplace-result {
  position: relative;
  display: grid;
  gap: 8px;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-container);
  padding: 14px;
  background: rgba(255, 255, 255, .025);
}

.marketplace-result > div:first-child strong,
.marketplace-result > div:first-child small {
  display: block;
}

.recommendation-score {
  position: absolute;
  right: 14px;
  top: 14px;
  border-radius: var(--radius-round);
  background: var(--accent-tint-bg);
  color: var(--accent-tint-text);
  padding: 5px 9px;
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
}

.review-form {
  grid-template-columns: 100px 1fr auto;
  align-items: end;
}

.attendance-cell {
  display: table-cell;
}

.attendance-cell > strong,
.attendance-cell > span,
.trust-badge {
  display: block;
}

.attendance-actions {
  display: flex;
  gap: 6px;
  margin-bottom: 5px;
}

.attendance-actions button {
  font-size: var(--text-xs);
}

.attendance-yes {
  background: var(--success-bg);
  color: var(--success-ink);
  border: 1px solid color-mix(in srgb, var(--success-ink) 35%, transparent);
}

.attendance-arrived { color: var(--success-ink); font-weight: var(--weight-heading); }
.attendance-no-show { color: var(--danger-ink); font-weight: var(--weight-heading); }
.trust-badge { margin-top: 4px; color: var(--accent-tint-text); }

.reports-view {
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  background: var(--panel);
}

.report-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
}

.report-grid article {
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-container);
  padding: 18px;
  background: rgba(255, 255, 255, .025);
}

.report-grid span {
  display: block;
  color: var(--muted);
  font-size: var(--text-xs);
}

.report-grid strong {
  display: block;
  margin-top: 7px;
  color: var(--accent-tint-text);
  font-size: var(--text-xl);
}

@media (max-width: 1000px) {
  nav { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .marketplace-hero { display: grid; }
  .marketplace-grid { grid-template-columns: 1fr; }
  .marketplace-search-card,
  .marketplace-results-card,
  .marketplace-appointments-card { grid-column: auto; }
  .report-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* `table { min-width: 930px }` buradaydı; kural artık koşulsuz (gerekçe
     tanımın yanında). Dar ekran, tabloyu ezen tek durum değildi. */
}

@media (max-width: 620px) {
  nav { grid-template-columns: 1fr 1fr; }
  .review-form,
  .report-grid { grid-template-columns: 1fr; }
  .trust-card { min-width: 0; }
}

/* Portal separation and owner authentication */
.business-login-shell {
  min-height: 100vh;
  grid-column: 1 / -1;
  display: grid;
  place-items: center;
  padding: 32px 20px;
  background:
    radial-gradient(circle at 82% 12%, color-mix(in srgb, var(--green) 14%, transparent), transparent 34%),
    radial-gradient(circle at 10% 88%, color-mix(in srgb, var(--primary) 20%, transparent), transparent 38%),
    var(--bg);
}

.business-login-card {
  width: min(100%, 460px);
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  padding: 30px;
  background: color-mix(in srgb, var(--panel) 94%, transparent);
  box-shadow: var(--shadow-drawer);
}

/* Marka ve dil düğmesi tek sırada. Düğme kendi satırındayken kart 689px'den
   753px'e çıkıyordu ve 720px yüksekliğinde bir ekranda markayı tepeden kesiyordu.
   Satırın alt boşluğu 28px'den 16px'e iniyor: sıra artık kenarlıklı bir denetim
   taşıdığı için görsel olarak daha ağır, ve inen 12px, 34px'lik markanın 46px'lik
   düğmeyle aynı sıraya girmesiyle eklenen 12px'i tam karşılıyor. Kartın yüksekliği
   bu düğme eklenmeden önceki değerinde kalıyor. */
.business-login-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.business-login-brand { margin-bottom: 0; }

/* .lang-switch'in 18px'lik üst boşluğu kenar çubuğunun dikey yığınına ait;
   bir satırın içinde onu aşağı kaydırmaktan başka bir şey yapmıyor. */
.business-login-lang { margin-top: 0; }

.portal-kicker,
.portal-label {
  color: var(--accent-tint-text);
  font-size: var(--text-xs);
  font-weight: var(--weight-heading);
  letter-spacing: .14em;
}

.portal-label {
  margin: 12px 0 0 44px;
  color: var(--muted);
}

.business-login-card h1 {
  margin-top: 7px;
  /* Akışkan boy, akışkan satır kutusu. Yalnız `font-size` clamp'lenince satır
     yüksekliği temel `h1` kuralından SABİT geliyordu (--leading-xl, 32px): boy
     tavana çıktığında (32px) oran 1,0'a iniyor ve iki satırlık başlık kendi
     üstüne biniyordu. Tarayıcıda ölçüldü — 32px/32px.
     6.25vw, 5vw'nin 1,25 katı; yani ölçeğin kendi oranı (32/40) genişlik
     boyunca korunuyor ve iki uç da 8px ızgarasına oturuyor. */
  font-size: clamp(var(--text-xl), 5vw, var(--text-2xl));
  line-height: clamp(var(--leading-xl), 6.25vw, var(--leading-2xl));
}

.business-login-card > .muted {
  margin-top: 10px;
  line-height: 1.55;
}

.business-login-form {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  padding: 24px 0 0;
}

.business-login-form label,
.settings-view label {
  min-width: 0;
}

.business-login-form input {
  width: 100%;
}

.login-status {
  min-height: 18px;
  color: var(--success-ink);
  font-size: var(--text-xs);
}

.login-status.is-error { color: var(--danger-ink); }

/* The slot every failed mutation writes into, one per settings card. It reads
   as a block rather than as red text so it is not mistaken for a field hint,
   and it carries its own upgrade button on a 402 — the plan refusal is an offer
   and needs somewhere to go. `hidden` keeps it out of the layout until there is
   something to say. */
.panel-error {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 10px 0 0;
  padding: 10px 12px;
  border-radius: var(--radius-container);
  border: 1px solid var(--danger-line);
  background: var(--danger-bg);
  color: var(--danger-ink);
  font-size: var(--text-xs);
  line-height: 1.45;
}

.panel-error[hidden] { display: none; }

/* Bu yuva bugüne kadar YALNIZ hata taşıyordu, o yüzden kutunun kendisi kırmızıydı.
   Artık bir de sonuç taşıyor -- ayarların WhatsApp bölümündeki "yeniden kuyruğa
   al" düğmesi cevabını buraya yazıyor, çünkü `#status-line` ayarlar açıkken
   gizli. Başarılı bir sonucu kırmızı bir kutuda göstermek, kullanıcıya bir daha
   basması gereken bir şey yaptığını düşündürür. Kırmızı `is-error`a taşındı;
   sınıfı paintPanelMessage yalnız gerçek bir hata varken koyuyor. */
.panel-error:not(.is-error) {
  border-color: var(--line);
  background: var(--panel-2);
  color: var(--ink);
}

.panel-error-action {
  padding: 6px 12px;
  border-radius: var(--radius-round);
  border: 1px solid currentColor;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: var(--weight-medium);
  cursor: pointer;
}

.panel-error-action:hover { background: var(--danger-wash); }

/* The dashboard's shared status line doubles as its error line; it is never
   hidden, because the appointment table writes its own summary there. */
#status-line.is-error { color: var(--danger-ink); font-weight: var(--weight-medium); }

/* Aynı sebep, ayarlardaki konum satırı için (F10-2). Bu satır da üç iş birden
   yapıyor -- ipucu, doğrulanmış adres, hata -- yani `panel-error` kutusuna
   çevrilemez: kutu boşken gizleniyor ve adres o gizli düğüme yazılırdı. Geriye
   `#status-line`ın çözümü kalıyor: satır durur, rengi hatayı söyler. */
#business-location-selection.is-error { color: var(--danger-ink); font-weight: var(--weight-medium); }

.portal-divider {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 22px 0 14px;
  color: var(--muted);
  font-size: var(--text-xs);
}

.portal-divider::before,
.portal-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.portal-admin-link,
.back-link {
  display: block;
  color: var(--accent-tint-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-align: center;
  text-decoration: none;
}

.portal-admin-link {
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  padding: 11px 14px;
  background: var(--field);
}

.back-link {
  margin-top: 14px;
  color: var(--muted);
  font-weight: var(--weight-medium);
}

.business-logout {
  width: 100%;
  margin-top: 10px;
}

/* --- Ayarlar: sol raf + sağ panel -------------------------------------------
 *
 * Altı kart 12 kolonluk bir ızgarada yan yana duruyordu. Yerine kanvasın ölçtüğü
 * düzen geldi: 208px'lik başlıklı bir raf ve bir seferde tek bir bölüm. Panel
 * tek kolon, çünkü bir bölüm bir konudur -- iki kartı yan yana koymak, okuyanı
 * yine tarama işine sokar. */
.settings-layout {
  display: grid;
  grid-template-columns: 208px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}

.settings-rail {
  display: grid;
  gap: 2px;
  align-content: start;
  border-right: 1px solid var(--line-soft);
  padding-right: 12px;
}

/* Başlıklar tıklanamıyor ve bilerek: gezinme tek seviyede kalıyor, kapsam yine
   de görünür oluyor. Kanvas bedelini ölçtü -- üç başlık ~82px. */
.settings-rail-group {
  margin: 14px 0 4px;
  padding: 0 10px;
  color: var(--muted);
  font-size: 10.5px;
  font-weight: var(--weight-display);
  letter-spacing: .09em;
  text-transform: uppercase;
}

.settings-rail-group:first-child { margin-top: 0; }

.settings-rail-item {
  width: 100%;
  /* Kapsayan blok. Noktanın içindeki `.sr-only` metin mutlak konumlu; düğme
     konumlandırılmamışken o metnin kapsayan bloğu rafın DIŞINDA kalıyor, yani
     dar ekranda raf `overflow-x: auto` ile düğmeleri kırparken bir pikselli
     metin kırpılmıyor ve sayfayı genişletiyordu -- 390px'te belge 876px
     (2026-09-05, ilk CI koşusu; tarayıcıda ölçüldü, bu satırla 390). */
  position: relative;
  justify-content: flex-start;
  gap: 8px;
  text-align: left;
  /* Kenar çubuğundaki `.nav-item` ile aynı sebep: genel `button` kuralı dolgu ve
     kenar veriyor, ve dokuz öğenin dokuzu birincil eylem gibi okunurdu. */
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

.settings-rail-item > span:first-child { flex: 1; min-width: 0; }

.settings-rail-item:hover {
  background: var(--hover);
  border-color: transparent;
  color: var(--ink);
}

.settings-rail-item[aria-selected="true"],
.settings-rail-item[aria-selected="true"]:hover {
  background: var(--accent-tint-bg);
  border-color: transparent;
  color: var(--accent-tint-text);
}

/* İşaret RENKTEN ibaret değil: içindeki `.sr-only` metin düğmenin erişilebilir
   adının parçası. Kehribar "kurulum bekliyor", kırmızı "sorun var". */
.settings-rail-dot {
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: var(--radius-round);
  background: var(--warning-ink);
}

.settings-rail-dot.is-error { background: var(--danger-ink); }

.settings-panel { min-width: 0; }

/* 720px, kanvasta ölçülen içerik genişliği. Sınırsız bırakıldığında 1440px'lik
   bir ekranda form alanları 913px'e uzuyor ve bir metin kutusunun okunabilir
   genişliğinin iki katını geçiyor. */
.settings-section {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
  align-items: start;
  max-width: 720px;
}

.settings-view .settings-card {
  min-width: 0;
  grid-column: auto;
}

/* Tek kolonlu bir ızgarada `1 / -1` o tek kolondur, yani bu satır bugün hiçbir
   şeyi değiştirmiyor. Duruyor çünkü tests/waitlist.mjs:172 onu METİN olarak
   arıyor -- stil sayfasında bir arayüz iddiası tutan tek satır orada, ve o test
   bana verilen dosyalardan değil. Kaldırılması gereken yer testin kendisi. */
.settings-view .settings-location-card,
.settings-view .settings-smtp-card { grid-column: 1 / -1; }

/* --- Boş hal: kurulum sayacı ----------------------------------------------- */
.setup-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin-bottom: 20px;
  border: 1px solid var(--accent);
  border-radius: var(--radius-container);
  /* Zemin aksan tonu DEĞİL, kartın kendisi. Ölçüldü: açık temada `--muted`
     (#5a6675) aksan tonlu zeminin üstünde 4,13:1 veriyordu -- AA'nın altında,
     ve tam da bu afişin ikinci satırı, yani neyin eksik olduğunu anlatan cümle.
     Kart zemininde aynı yazı 5,40:1. Afişi ayıran şey artık aksan çizgisi;
     rengi bir kenarın taşıması, okunabilirliğe hiçbir şeye mal olmuyor. */
  background: var(--panel);
  padding: 16px 18px;
}

.setup-banner-text { flex: 1 1 320px; min-width: 0; }

.setup-banner-text h2 {
  font-size: var(--text-md);
  line-height: var(--leading-md);
  font-weight: var(--weight-heading);
}

.setup-banner-text p { margin-top: 4px; }

.setup-banner-meter {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}

.setup-meter {
  width: 128px;
  height: 6px;
  border-radius: var(--radius-round);
  background: var(--neutral-bg);
  overflow: hidden;
}

.setup-meter span {
  display: block;
  height: 100%;
  background: var(--accent);
}

/* --- Yükleniyor hali: iskelet ----------------------------------------------
 *
 * Yükseklikler gelecek içeriğin kendisinden: 16px başlık, 24px rozet, 40px alan,
 * 36px düğme. Zıplamayı önlemesi gereken bir iskelet, önce kendisi doğru
 * yüksekliği tutmak zorunda. Hareket azaltma cevabı burada YOK: base.css tek bir
 * blokla her animasyonu kapatıyor. */
/* İskelet ile içerik ASLA aynı anda ekranda değil: ikisi birden çizilseydi
   kart iki kere görünür ve "yükleniyor" bir gecikme değil bir kusur gibi
   okunurdu. Anahtar tek bir sınıf, app.js ilk gerçek yanıtta kaldırıyor. */
.settings-view:not(.is-loading) .settings-skeleton { display: none; }
.settings-view.is-loading .settings-section,
.settings-view.is-loading .setup-banner { display: none; }

.settings-skeleton .settings-card { padding-bottom: 18px; }

.sk {
  display: block;
  border-radius: var(--radius-control);
  background: linear-gradient(90deg, var(--field), var(--hover), var(--field));
  background-size: 300% 100%;
  animation: sk-sweep 1.4s ease-in-out infinite;
}

@keyframes sk-sweep {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}

.sk-title { width: 190px; height: 16px; }
.sk-badge { width: 72px; height: 24px; border-radius: var(--radius-round); }
.sk-label { width: 104px; height: 11px; }
.sk-field { width: 100%; height: 40px; }
.sk-button { width: 148px; height: var(--control-md); }

.sk-body {
  display: grid;
  gap: 14px;
  padding: 16px 18px 0;
}

.sk-field-group { display: grid; gap: 7px; }

.sk-actions { display: flex; gap: 10px; }

/* --- Bağlantı bölümlerinin boş ve hata halleri ------------------------------ */
.conn-empty,
.conn-error {
  display: grid;
  gap: 8px;
  margin: 0 18px 14px;
  border-radius: var(--radius-container);
  padding: 14px 16px;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.conn-empty {
  border: 1px solid var(--line-soft);
  background: var(--panel-2);
}

.conn-empty-title { font-weight: var(--weight-heading); }

.conn-error {
  border: 1px solid var(--danger-line);
  background: var(--danger-wash);
}

.conn-error-title {
  color: var(--danger-ink);
  font-weight: var(--weight-heading);
}

/* Etki satırı kırmızı DEĞİL: bir uyarı değil, bir sayı. Kırmızıyı sebebe
   saklamak, sebebin kendisini görünür tutan şey. */
.conn-error-impact { color: var(--ink); }

.conn-error button { justify-self: start; }

/* --- Hesap ve oturum: tercih satırları -------------------------------------- */
.pref-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  padding: 14px 0;
  border-top: 1px solid var(--line-soft);
}

.pref-row:first-child { border-top: 0; padding-top: 0; }

.pref-row-text { flex: 1 1 240px; min-width: 0; }

.pref-row-text p:first-child {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.pref-row-text p + p { margin-top: 3px; }

/* Kenar çubuğundaki dil anahtarının kendi üst boşluğu var; bir satırın içinde
   duran aynı kontrolün olmamalı. */
.pref-switch { margin-top: 0; align-self: center; flex-shrink: 0; }

.settings-view form,
.settings-view input,
.settings-view select {
  min-width: 0;
  max-width: 100%;
}

.settings-view input,
.settings-view select,
.settings-view textarea { width: 100%; }

.settings-smtp-card #smtp-form {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: end;
}

.settings-smtp-card #smtp-form button { grid-column: 1 / -1; }

/* --- Dar ekran: raf yatay bir sekme şeridine dönüşüyor ----------------------
 *
 * Kanvas bunu 390x844'te çizdi. Aynı DOM, aynı roller, aynı ok tuşları -- yalnız
 * yön değişiyor, o yüzden app.js hem yatay hem dikey okları dinliyor.
 *
 * Grup başlıkları şeritte GİZLENİYOR: yatayda üç büyük harfli etiket dokuz
 * sekmenin arasına serpiştirilince gruplama okunmuyor, yalnız yer yiyor. Bölüm
 * adları kendi başlarına zaten tam: "Plan ve ödeme" hangi grupta olduğunu
 * söylemeye ihtiyaç duymuyor.
 *
 * Şerit kendi içinde kayıyor (`overflow-x`), sayfa değil: `.shell` yatay taşmayı
 * kırpıyor ve kırpılan bir şerit, dokuzuncu bölüme telefondan hiç ulaşılamaması
 * demek olurdu. */
@media (max-width: 900px) {
  .settings-layout {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }

  .settings-rail {
    display: flex;
    gap: 8px;
    border-right: 0;
    border-bottom: 1px solid var(--line-soft);
    padding: 0 0 12px;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .settings-rail::-webkit-scrollbar { display: none; }

  .settings-rail-group { display: none; }

  .settings-rail-item {
    width: auto;
    flex-shrink: 0;
    /* Dokunma tabanı. tokens.css kaba işaretçide her düğmeyi 44px'e çıkarıyor;
       bu satır fare ile açılmış dar bir pencerede de aynı hedefi veriyor. */
    min-height: var(--control-touch);
    border-radius: var(--radius-round);
    border-color: var(--line);
  }

  .settings-rail-item[aria-selected="true"],
  .settings-rail-item[aria-selected="true"]:hover {
    border-color: var(--accent);
  }
}

@media (max-width: 700px) {
  .business-login-card { padding: 24px 20px; }
  .settings-smtp-card #smtp-form { grid-template-columns: minmax(0, 1fr); }
  .settings-smtp-card #smtp-form button { grid-column: auto; }
  .settings-actions { flex-direction: column; }
}

.settings-location-card #business-location-form {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: end;
  margin-top: 18px;
}

.settings-location-card #business-location-form button,
.settings-location-card #business-location-form .check { grid-column: 1 / -1; }

.settings-location-card textarea {
  min-height: 94px;
  resize: vertical;
  border: 1px solid var(--line);
  border-radius: var(--radius-control);
  background: var(--field);
  color: var(--ink);
  padding: 12px;
  font: inherit;
}

.place-autocomplete { margin-top: 14px; }
.place-autocomplete gmp-place-autocomplete { width: 100%; }
.business-map {
  width: 100%;
  min-height: 360px;
  margin-top: 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-container);
  overflow: hidden;
}

@media (max-width: 700px) {
  .settings-location-card #business-location-form { grid-template-columns: minmax(0, 1fr); }
  .settings-location-card #business-location-form button,
  .settings-location-card #business-location-form .check { grid-column: auto; }
  .business-map { min-height: 280px; }
}
/* Account deletion card (A1, 2026-09-05). A full tinted border, never a side
   stripe; the confirm form opens inline under its own button, no modal. Width
   capped so the password field does not stretch across the panel. */
.settings-danger-card { border-color: var(--danger-line); }
.danger-confirm { display: grid; gap: 12px; max-width: 440px; margin-top: 12px; }
.danger-confirm-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
