/* =========================================================================
   RANDEVU PANELI — TASARIM DILI (Melih'in `references/tasarim-dili/
   01-anasayfa.html` tasarimi; sozlesme: `.ai-factory/blackboard/ui-ux/
   2026-08-17-1145-tasarim-dili-spec.md`).

   NE DEGISTI: renk, tipografi, kose, bosluk ritmi, golge, kart kalibi.
   Onceki "Karanlik Editoryal" dili (fildisi/bronz #FAF7F2 / #8A5F25,
   Fraunces + Work Sans, 2px kose, koyu varsayilan) TAMAMEN KALKTI.
   Yeni dil: notr-soguk taban, kategori basina pastel simge kutusu, koyu
   antrasit kahraman kart, 24/16/12/999 kose olcegi, TEK gölge kademesi.

   NE DEGISMEDI: bilgi yogunlugu, ekran sayisi, adim sayisi, metinler.
   Bu bir gorsel dil degisimi; spec §9 "yeni yazi eklenmez" baglayici.

   VARSAYILAN ARTIK ACIK TEMA. `:root` acik paleti tasiyor, koyu palet
   `[data-theme='dark']` icinde. Sebep VISION D1: "her ekran once acik
   temada tasarlanir, koyu tam kapsamli bir gece modudur". Onceki surumde
   ters duruyordu ve sistem sinyali okunamayan bir tarayicida panel koyuya
   dusuyordu — o dusus dallarinin hepsi (`index.html` satir ici betik,
   `admin.js` initTheme) artik ACIGA dusuyor.

   PANEL VE MOBIL AYNI SAYIYI TASIR. Her token degeri `mobile/lib/core/
   palette.dart` icinde birebir ayni; kapisi `server/test/panel-tema.test.js`.
   ========================================================================= */

/* FONTLAR — Plus Jakarta Sans, TEK aile (spec §4).
   Fraunces (serif) ve Work Sans panelden CIKTI: VISION'in "sadece
   sans-serif" kurali ve tasarimin kendisi tek aile soyluyor; iki aile
   arasindaki display/body ayrimini artik AGIRLIK ve OLCEK tasiyor.

   CDN YOK (spec §9 madde 8-9). Dosyalar `public/fonts/` icinde, vitrinin
   kullandigi ayni boru hattindan iniyor (`npm run fonts` ->
   `scripts/fetch-fonts.mjs`); `/admin/fonts/*` istekleri `server/index.js`
   icinde oraya yonleniyor, dosya kopyasi yok. Lisans OFL 1.1.
   Turkce `g s I` latin-ext altkumesinde — iki kural da sart. */
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/admin/fonts/plus-jakarta-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/admin/fonts/plus-jakarta-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Metrik-uyumlu yedek — dosya engellenirse/bozulursa duzen ZIPLAMASIN.
   Spec §4 yedek zinciri: Plus Jakarta Sans -> Manrope -> system-ui.
   Manrope panelde indirilmiyor (ikinci bir aile ikinci bir indirme
   demekti); onun yerine sistem yiginini metrik olarak Plus Jakarta'ya
   yaklastiran bir yedek yuz tanimli. Olcum yontemi vitrinin
   `src/styles/fonts.css` dosyasindakiyle ayni: ayni punto ve satir
   sayisinda iki yuzun kapladigi kutu karsilastirildi.

   TEK YEDEK KURALI, AGIRLIK BANDI YOK: Segoe UI/Roboto ailelerinde
   ayri bold dosyasi cagirmak sentetik kalinlik uretip olcumu bozuyordu;
   degisken eksenli tek kural her agirlikta ayni kutuyu veriyor. */
@font-face {
  font-family: 'Jakarta Fallback';
  font-weight: 400 700;
  src: local('Segoe UI'), local('Roboto'), local('Helvetica Neue'), local('Arial');
  size-adjust: 103.5%;
  ascent-override: 96.6%;
  descent-override: 24.1%;
  line-gap-override: 0%;
}

/* =========================================================================
   ACIK TEMA = VARSAYILAN (`:root`). Koyu tema asagida `[data-theme='dark']`.

   Butun degerler spec'ten BIREBIR alindi; turetilmis olanlar tek tek
   isaretli. Kontrast oranlari OLCULDU (WCAG 2.1), tahmin edilmedi — kapisi
   `server/test/panel-tema.test.js` ve ayni ciftler mobilde
   `mobile/test/contrast_test.dart` icinde.
   ========================================================================= */
:root {
  /* ---- yapi katmani (spec §1.1) ---- */
  --bg: #f8fafc;
  --surface: #ffffff;
  --surface-2: #f1f5f9;
  --surface-3: #e2e8f0;
  --line: #f1f5f9;
  --line-2: #e2e8f0;
  --ink: #0f172a;
  --ink-2: #475569;
  /* `--ink-3` SPEC'TEN BIR KADEME KOYULASTIRILDI (CEO karari, 2026-08-17).
     Spec'in onerdigi `#64748B` yalnizca `surface` (4,76) ve `bg` (4,55)
     uzerinde olculmustu; panelde bu token UCUNCU yuzeye de biniyor
     (`.pill` zemini, secili musteri satiri, sekme kabi) ve orada olculunce
     `surface-2` 4,34 · `surface-3` 3,86 cikiyor — ikisi de AA alti.
     Deger kaydirildi, AILE ve HIYERARSI korundu:
       #55637A  bg 5,81 · surface 6,08 · surface-2 5,55 · surface-3 4,93
     Hiyerarsi kartta: ink 17,85 > ink-2 7,58 > ink-3 6,08.
     Mobil AYNI sayiyi yaziyor — bu bir panel karari degil, tek karar. */
  --ink-3: #55637a;

  /* ---- vurgu (spec §1.5): HUE'LU TEK VURGU YOK ----
     Global vurgu koyu antrasit (kahraman kartin zemini), baglamsal vurgu
     bulundugun kategorinin rengi. Eski `#8A5F25` altin tamamen kalkti.
     `--accent-deep` yalnizca ZEMIN/KENAR (dolu dugmenin uzerine gelme
     hali) — hicbir yerde metin degil. */
  --accent: #2d2d2d;
  --accent-deep: #0f172a;
  --accent-soft: #f1f5f9;
  --accent-ink: #ffffff;

  /* ---- durum renkleri (spec §1.4) ---- */
  --ok: #047857;
  --warn: #b45309;
  --danger: #be123c;
  /* Durum cipinin YUMUSAK ZEMINI. Spec §1.4 bu zeminleri tek tek veriyor ve
     ucu de kategori pastel kutulariyla AYNI renk — yeni renk uretilmedi.
     Onceki surum cip zeminini `rgba(var(--durum-rgb), .12)` ile uretiyordu;
     yeni palette olculunce `warn` kendi %12 tintinde 4,25 kaliyor (AA alti),
     spec'in verdigi `#FFFBEB` uzerinde 4,84 geciyor. Tint yerine ISIMLI
     zemin: hem olculebilir hem spec'in soyledigi sey. */
  --ok-soft: #ecfdf5;
  --warn-soft: #fffbeb;
  --danger-soft: #fff1f2;

  /* ---- kahraman kart (spec §1.1 + §6.2) ----
     Acik temada TERS YUZEY: sayfanin en koyu blogu. Mevcut hicbir token
     bunu karsilamiyordu, spec dort yeni alan tanimladi. `--hero-ink-2`
     (#94A3B8) beyaz kartta 2,56 ile AA'yi GECMEZ ve orada KULLANILMAZ;
     yalnizca bu koyu zeminde mesru (5,37 ✓). */
  --hero: #2d2d2d;
  --hero-ink: #ffffff;
  --hero-ink-2: #94a3b8;
  --hero-glow: rgba(255, 255, 255, 0.05);

  /* KANAL BELIRTECLERI — tint'lerin tek kaynagi.
     Panelde `rgba(134,189,148,.3)` gibi 86 gomulu deger vardi ve hepsi KOYU
     paletin renklerini tasiyordu; acik zeminde bunlar ya kayboluyor ya da
     yamalik duruyordu. Kanal belirteci ayni gorunumu koyu tarafta birebir
     koruyor (degerler degismedi), acik tarafta tek satirdan degisiyor.
     `rgba(var(--ok-rgb), .3)` bicimi ozel ozellik destegi olan her
     tarayicida calisiyor — `color-mix` gibi yeni bir ozellige bagli degil. */
  --ok-rgb: 4, 120, 87;
  --warn-rgb: 180, 83, 9;
  --danger-rgb: 190, 18, 60;
  --accent-rgb: 45, 45, 45;
  --ink-rgb: 15, 23, 42;
  --walkin-rgb: 2, 132, 199;
  --demo-rgb: 147, 51, 234;
  --shadow-rgb: 15, 23, 42;

  /* TAKVIM RENK KODU PALETI (Tur 2 — S7). Sekiz kanal belirteci.
     Indeksi SUNUCU atiyor (`server/colors.js`); burasi yalnizca degerleri
     tasiyor ve mobil karsiligi `mobile/lib/core/palette.dart` -> `calendar`.
     Iki istemcinin AYNI sirada AYNI renkleri tasimasi test edilir
     (`server/test/panel-tema.test.js` + `mobile/test/contrast_test.dart`).

     UC KURAL:
      1. Renk METNIN ALTINDAN gecmiyor: blok zemini yalnizca %8 alfa ile
         tonlaniyor, yani `--ink`/`--ink-2` kontrasti pratik olarak
         degismiyor. Dolgun bir zemin, sekiz rengin sekizi icin ayri metin
         rengi hesaplamak demekti.
      2. Tasiyici kanal SOL KENAR (3px, opak) — 1.4.11'in 3:1 esigi burada
         ve degerler ona gore secildi.
      3. Renk TEK BASINA bilgi tasimiyor (1.4.1): hizmet adi her blokta
         yazili, efsane ekranda. Renk yalnizca TARAMAYI hizlandiriyor. */
  --cal-1-rgb: 225, 29, 72;
  --cal-2-rgb: 5, 150, 105;
  --cal-3-rgb: 2, 132, 199;
  --cal-4-rgb: 217, 119, 6;
  --cal-5-rgb: 147, 51, 234;
  --cal-6-rgb: 13, 148, 136;
  --cal-7-rgb: 219, 39, 119;
  --cal-8-rgb: 79, 70, 229;

  /* ---- ayni ailenin OPAK tonlari (metin ve blok zeminleri) ----
     Hepsi ESKI SICAK PALETTEN turemisti (spec §8.3 bunlari tek tek bayrakla
     isaretledi) ve yeni notr-soguk tabanda yeniden hesaplandi. Uretim
     kurali: metin tasiyanlar (`*-ink`) kendi ailesinin AA gecen derin
     tonu, zemin/doku tasiyanlar `surface`/`surface-2`/`surface-3`
     kademelerinden. Olculdu — hicbiri tahmin degil. */
  --ok-ink: #065f46; /* kart 7,32 · surface-3 5,87 · ok-soft 6,96 */
  --walkin: #0284c7; /* grafik: kart 4,09 ✓ */
  --walkin-ink: #075985; /* kart 8,25 · surface-3 6,62 */
  --demo-ink: #7e22ce; /* kart 7,20 · surface-3 5,77 */
  /* Takvim blogunun uzerine gelme / paketlenme zeminleri. `--blk-hover`
     BILEREK `surface-2` DEGIL: 3px renk kanali sol kenarda duruyor ve
     `--cal-4` (kehribar) `#F1F5F9` uzerinde 2,91 ile 3:1'in ALTINA
     dusuyordu. `#F8FAFC` uzerinde 3,04 — dar ama gecer. Pay dar oldugu
     icin uzerine gelme ayrimini yalniz zemine yuklemiyoruz, kenarlik da
     bir kademe koyulasiyor (asagida `.blk-appt:hover`). */
  --blk-hover: #f8fafc;
  --blk-packed: #f8fafc;
  --hatch-a: #f1f5f9;
  --hatch-b: #e2e8f0;
  --hatch2-a: #f8fafc;
  --hatch2-b: #edf2f7;
  --gate-glow: #ffffff;
  --surface-0: #f8fafc;
  --backdrop: rgba(15, 23, 42, 0.45);

  /* ARAYUZ BILESENININ SINIRI — metin kutusu, secici, cerceveli dugme.
     `--line-2`den AYRI bir belirtec cunku ikisi ayri kurala tabi: ayrac
     dekoratif, bilesen kenari WCAG 1.4.11 kapsaminda (3:1).

     ARTIK OPAK. Eski deger alfaliydi ve dort yuzeyde ayri ayri
     harmanlaniyordu; yeni palette tek bir hex dordunde de gecerken
     alfa gereksiz bir dolayli katman birakiyordu.

     SPEC'TEN BIR KADEME KOYULASTIRILDI (CEO karari, `--ink-3` ile ayni
     sebep): spec'in `#7C8CA3` degeri `surface-3` uzerinde 2,78 ile 3:1'in
     altinda kaliyordu. Olculen yeni tablo:
       #6F7F96  bg 3,90 · surface 4,08 · surface-2 3,72 · surface-3 3,31
     Mobil AYNI sayiyi yaziyor (`palette.dart` -> `lineField`). */
  --line-field: #6f7f96;

  /* ---- KATEGORI RENK AILESI (spec §1.3) ----
     Kategori rengi artik CIFT: pastel kutu zemini + uzerindeki simge rengi.
     Sira SABIT ve iki istemcide ayni:
       [Bugun, Randevular, Musteriler, Kasa, Raporlar, Isletme]

     Eski kural ("kategori renkleri takvim kanallarindan turetilir") DUSTU:
     yeni palette kategori ve takvim iki AYRI ailedir — kategori pastel
     kutu + orta ton, takvim tek doygun kanal. Bu spec §1.3'un dogrudan
     soyledigi sey; parite testi de artik bunu bekliyor.

     Simge bir GRAFIK NESNE -> esik 3,0 (WCAG 1.4.11). Kendi kutusunda
     olculdu: 9,45 · 3,34 · 3,58 · 3,69 · 3,84 · 3,07.
     `#D97706` (Isletme) 3,07 ile EN DAR pay: simge cizgisi 1,75px'in
     altina inerse `#B45309` (4,84) devreye girmeli. */
  --cat-bugun-rgb: 51, 65, 85;
  --cat-randevu-rgb: 244, 63, 94;
  --cat-musteri-rgb: 5, 150, 105;
  --cat-kasa-rgb: 168, 85, 247;
  --cat-rapor-rgb: 2, 132, 199;
  --cat-isletme-rgb: 217, 119, 6;
  /* Pastel simge kutusu zeminleri. Kartla ayrimi (~1,10) DEKORATIF —
     kategori kimligini simge rengi + yazili baslik birlikte tasiyor,
     yani 1.4.1 renk-tek-basina kuraliyla sorun yok. */
  --cat-bugun-box: #f1f5f9;
  --cat-randevu-box: #fff1f2;
  --cat-musteri-box: #ecfdf5;
  --cat-kasa-box: #faf5ff;
  --cat-rapor-box: #f0f9ff;
  --cat-isletme-box: #fffbeb;

  /* ---- KOSE YARICAPI OLCEGI (spec §2): dort kademe, baskasi yok ----
     Panelin eski 2px sert kosesi KALKTI. Panel ve mobil artik AYNI sayiyi
     tasiyor ("her platform kendi olceginde bir kademe atlar" kurali dustu,
     Melih'in "birlikte hareket eder" karari geregi).
     Ic ice kural: ic radius = dis radius - bosluk, olcek kademesine
     yuvarlanir (24px kartin icindeki kutu 16'ya iner). */
  --radius-hero: 24px; /* kart · kategori kutucugu · kahraman · dialog */
  --radius: 16px; /* simge kutusu · form alani · birincil dugme */
  --radius-sm: 12px; /* cip · rozet · satir ici mini kutu */
  --radius-pill: 999px; /* yuvarlak dugme · durum hapi · avatar */

  /* ---- BOSLUK RITMI (spec §3, 4/8 tabanli) ---- */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s8: 32px;
  --s10: 40px;

  /* ---- YUKSELTI (spec §5) ----
     TEK GOLGE KADEMESI. Kart, kutucuk, yuvarlak dugme, kahraman kart —
     hepsi ayni golgeyi tasir; tasarimda ikinci bir kademe YOK. Karti
     zeminden ayiran sey golge + 1px `--line` kenarligidir (zemin farki
     yalnizca 1,05). Eski surumdeki `--shadow-hero` ayrimi kalkti; token da
     kalkti (hicbir yerde `var()` ile cagrilmiyordu). */
  --shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.05),
    0 2px 10px -2px rgba(0, 0, 0, 0.02);
  /* Basili hal (spec §5): golge bir kademe toplanir + 0,985 olcek. */
  --shadow-press: 0 2px 8px -2px rgba(0, 0, 0, 0.06);

  /* ---- TIPOGRAFI (spec §4) ----
     TEK AILE. Display/body ayrimini artik AGIRLIK ve OLCEK tasiyor, ikinci
     bir aile degil. Iki token de ayni degeri veriyor — `--font-display`
     dosyada ~10 yerde cagriliyor ve tek tek silmek yerine ayni aileye
     baglandi; boylece "baslik ailesi" kavrami ileride geri gelirse tek
     satirdan doner. */
  --font-body: 'Plus Jakarta Sans', 'Jakarta Fallback', 'Manrope', system-ui,
    'Segoe UI', Roboto, sans-serif;
  --font-display: var(--font-body);

  /* hareket — spec §5/§7.4: 180ms, yalniz transform/opacity */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-1: 180ms;
  --dur-2: 320ms;

  /* ---- MESGUL HALI (I-084) ----
     Panelde `aria-busy` ONLARCA yerde yazilmisti ama CSS'te hicbir kurali
     yoktu: ekran okuyucu "mesgul" diyordu, GOZ hicbir sey gormuyordu ve
     ekrandaki eski veri taze sanildi. Bu iki belirtec o boslugu tek yerden
     dolduruyor.
     ANIMASYON YOK — nabiz/parilti CEO karari 2 ve 4 ile kapali (asagida
     `admin.css` iskelet notu); solma + imlec, hareketsiz bir sinyal.
     Tema-bagimsiz olduklari icin `[data-theme='dark']` karsiligi yok —
     radius/bosluk/sure belirtecleriyle ayni istisna. */
  --busy-opacity: 0.55;
  --busy-cursor: progress;

  color-scheme: light; /* native date/time/select acilir menuleri de acik */
  font-synthesis-weight: none;
}

/* =========================================================================
   GECE MODU — aynidil, koyu hali (spec §1.6).

   KURAL: ayni radius, ayni bosluk, ayni tipografi olcegi, ayni hiyerarsi.
   Degisen yalnizca yuzey ve murekkep. Yukselti koyuda golgeyle DEGIL
   YUZEY ACIKLIGIYLA anlatiliyor (bg #0B1220 -> surface #151C2B ->
   hero #272C34): kahraman kart acik temada sayfanin en KOYU blogu iken
   koyu temada en ACIK blogu — ayni "one cikma" mesaji, ters yonde.

   YARIM BIRAKILMADI: acik temada tanimli her token burada karsiligini
   aliyor; tek istisna olcek/hareket belirtecleri (radius, bosluk, sure)
   cunku onlar temaya gore degismiyor — bu bir eksik degil, kuralin
   kendisi.
   ========================================================================= */
[data-theme='dark'] {
  --bg: #0b1220;
  --surface: #151c2b;
  --surface-2: #1e2637;
  --surface-3: #2a3446;
  --line: #262c3b;
  --line-2: #373e4b;
  --line-field: #7a889e; /* kart 4,74 · surface-3 3,48 (CEO karari) */
  --ink: #e9eef5;
  --ink-2: #a3b0c2;
  --ink-3: #96a3b7; /* surface-3 4,90 (CEO karari) */

  --accent: #e9eef5;
  --accent-deep: #cbd5e1;
  --accent-soft: #2a3446;
  --accent-ink: #0b1220;

  --ok: #34d399;
  --warn: #fbbf24;
  --danger: #fb7185;
  --ok-soft: #143539;
  --warn-soft: #342b25;
  --danger-soft: #392233;

  --hero: #272c34;
  --hero-ink: #e9eef5;
  --hero-ink-2: #a3b0c2;
  --hero-glow: rgba(255, 255, 255, 0.04);

  --ok-rgb: 52, 211, 153;
  --warn-rgb: 251, 191, 36;
  --danger-rgb: 251, 113, 133;
  --accent-rgb: 233, 238, 245;
  --ink-rgb: 233, 238, 245;
  --walkin-rgb: 56, 189, 248;
  --demo-rgb: 192, 132, 252;
  --shadow-rgb: 0, 0, 0;

  --cal-1-rgb: 251, 113, 133;
  --cal-2-rgb: 52, 211, 153;
  --cal-3-rgb: 56, 189, 248;
  --cal-4-rgb: 251, 191, 36;
  --cal-5-rgb: 192, 132, 252;
  --cal-6-rgb: 45, 212, 191;
  --cal-7-rgb: 244, 114, 182;
  --cal-8-rgb: 129, 140, 248;

  --cat-bugun-rgb: 203, 213, 225;
  --cat-randevu-rgb: 251, 113, 133;
  --cat-musteri-rgb: 52, 211, 153;
  --cat-kasa-rgb: 192, 132, 252;
  --cat-rapor-rgb: 56, 189, 248;
  --cat-isletme-rgb: 251, 191, 36;
  /* Kutu zemini = kategori hue'sunun %16'si, kart yuzeyi ustunde
     duzlestirilmis (spec §1.6). Alfa degil OPAK yaziliyor: iki istemcinin
     ayni sayiyi tasiyabilmesi icin (Flutter'da alfa harmanlama zemine
     bagli, hex degil). */
  --cat-bugun-box: #2a3446;
  --cat-randevu-box: #392233;
  --cat-musteri-box: #143539;
  --cat-kasa-box: #2d254c;
  --cat-rapor-box: #143249;
  --cat-isletme-box: #342b25;

  --ok-ink: #6ee7b7;
  --walkin: #38bdf8;
  --walkin-ink: #7dd3fc;
  --demo-ink: #d8b4fe;
  --blk-hover: #232c3e;
  --blk-packed: #1e2637;
  --hatch-a: #1e2637;
  --hatch-b: #151c2b;
  --hatch2-a: #131a29;
  --hatch2-b: #0f1626;
  --gate-glow: #151c2b;
  --surface-0: #10182a;
  --backdrop: rgba(3, 6, 14, 0.7);

  /* Koyu zeminde golge is gormez ama SIFIR da olmamali: kartin kenarligi
     (`--line`, karta 1,22) asil ayrimi tasiyor, golge yalnizca derinlik
     veriyor. Bu bir tasarim karari, eksiklik degil (spec §5). */
  --shadow: 0 4px 20px -2px rgba(0, 0, 0, 0.45),
    0 2px 10px -2px rgba(0, 0, 0, 0.3);
  --shadow-press: 0 2px 8px -2px rgba(0, 0, 0, 0.5);

  color-scheme: dark;
}

* { box-sizing: border-box; }

/* `hidden` NITELIGI HER ZAMAN GIZLESIN — bu projede UCUNCU KEZ isirdi.
   Tarayicinin varsayilan `[hidden] { display: none }` kurali yazarin HERHANGI
   bir `display:` bildiriminden zayif; `display: grid`/`flex` tasiyan bir
   elemana `hidden` vermek hicbir sey yapmiyor ve JS "gizledim" sanıyor.
   Uc olculmus vaka: giris ekrani (`.gate`, display:grid), ana ekran
   kategorileri (`.home-tiles`, display:grid, Tur 1A), QR eylem satiri
   (`.btn-row`, display:flex, Tur 2).

   Iki tekil yama yerine TEK genel kural: `!important` burada dogru kullanim,
   cunku `hidden` bir gorunum tercihi degil bir DURUM bildirimi — ekran
   okuyucular zaten oyle okuyor, gorsel katman da oyle okumali.
   Bilincli gizlemeyi `hidden` ile degil bir sinifla yapmak gerekir. */
[hidden] { display: none !important; }

/* MESGUL = GORUNUR BIR DURUM (I-084, saha dalga 2).
   `aria-busy="true"` panelde zaten yaziliyordu; kurali olmadigi icin
   "yukleniyor" bilgisi yalnizca ekran okuyucuya ulasiyordu. Gorunen katman
   artik ayni seyi soyluyor: icerik soluyor, imlec bekleme haline geciyor.
   Spinner ya da iskelet EKLENMEDI (CEO karari 2/4) ve gecis suresi
   `--dur-1` — panelin tek hareket olcegi. */
[aria-busy='true'] {
  opacity: var(--busy-opacity);
  cursor: var(--busy-cursor);
  transition: opacity var(--dur-1) var(--ease-out);
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  /* Govde 14/1,429 (spec §4 "Gövde / alt başlık"). Eski 15/1,5 olcek
     disiydi; 14px + 20px satir yuksekligi 4/8 ritmine oturuyor ve panelin
     yogun tablolarinda satir yuksekligini oynatmadan daha ferah okunuyor. */
  font: 500 14px/1.429 var(--font-body);
  -webkit-font-smoothing: antialiased;
}

/* TIPOGRAFI OLCEGI (spec §4). Iki aile yerine tek aile oldugu icin
   hiyerarsiyi PUNTO + AGIRLIK tasiyor. `-0,025em` harf araligi yalnizca
   H1'de — tasarimin `tracking-tight` imzasi orada. */
h1, h2 {
  margin: 0 0 var(--s2);
  font-family: var(--font-display);
  font-weight: 700;
}
h1 { font-size: 24px; line-height: 32px; letter-spacing: -0.025em; }
h2 { font-size: 18px; line-height: 28px; letter-spacing: 0; }
.muted { color: var(--ink-3); }
.small { font-size: 13px; }
.grow { flex: 1; }

code {
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 1px 5px;
  border-radius: var(--radius-sm);
  font-size: 12px;
}

/* Logotype: KIRACININ isaretini tasiyan kancalar — burada hicbir isletmenin
   kompozisyonu tarif EDILMIYOR. Isaretlemenin kendisi kiraci varligindadir
   (`server/admin/logotypes/<anahtar>.svg`, anahtar kiraci kaydindan gelir);
   bu blok yalnizca olcu ve renk baglar. Renkler currentColor + degisken
   uzerinden, boylece giris karti ile ust bar ayni isaretten beslenebiliyor.
   Iki satirlik bir isaret varsayilmiyor: `lt-rule`/`lt-sub` sinifi olmayan bir
   varlik da sorunsuz cizilir, yalnizca bu kurallardan etkilenmez. */
.logotype { display: block; width: 100%; height: auto; }
.logotype .lt-rule { stroke: var(--line-2); }
.logotype .lt-sub { fill: var(--ink-2); }

/* ------------------------------------------------------------------ giris */

/* `display: grid` `hidden` niteligini ezer — giris ekrani basarili giristen
   sonra sayfada kaliyordu. */
.gate[hidden] { display: none; }

.gate {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--s6);
  background:
    radial-gradient(120% 90% at 50% -10%, var(--gate-glow) 0%, var(--bg) 62%);
}
/* KART YOK (spec §7.5): giris ekrani zeminin USTUNDE yasiyor.
   Onceki surumde beyaz bir kart vardi ve yeni dilde zemin de acik oldugu
   icin "kart icinde kart" gorunumu veriyordu — ayrimi yalnizca golge
   tasiyacakti, yani 1,05'lik bir fark ustune duren bir kutu. Sinif ADI
   korunuyor (`admin.js` ve markup ona bagli), tasidigi gorsel dil degisti. */
.gate-card {
  width: min(448px, 92vw);
  background: none;
  border: 0;
  padding: 0;
  box-shadow: none;
  text-align: center;
}
/* NOTR URUN AMBLEMI. Giriste hangi isletmeye girildigi henuz bilinmiyor;
   kiracinin logosu ancak PIN'den sonra cozuluyor. Mobil giris ekraniyla ayni
   kompozisyon (yumusak kare + takvim isareti) — iki istemci ayni kapiyi
   acmis gibi gorunuyor. */
/* Amblem artik kahraman kartin simge kutusu diliyle ayni: kare, 16px kose,
   pastel kuyu. Kart kalkinca amblem sayfanin tek yukseltilmis ogesi kaldi,
   bu yuzden golgeyi O tasiyor. */
.gate-mark {
  width: 64px;
  height: 64px;
  margin: 0 auto var(--s5);
  display: grid;
  place-items: center;
  color: var(--hero-ink);
  background: var(--hero);
  border: 0;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.gate-mark svg { width: 30px; height: 30px; display: block; }
.gate-card h1 { font-size: 24px; line-height: 32px; letter-spacing: -0.025em; }
.gate-card > .muted { font-size: 14px; line-height: 20px; margin: 0; }
/* PIN alani: form alani kalibi (spec §7.3) ama yuksekligi 52 degil 60 —
   22px'lik ortalanmis bir PIN 52 piksellik kutuda optik olarak sikisiyor.
   Zemin `surface` (spec: form alani zemini kart yuzeyi), kenarlik
   `line-field` (3:1 gecen tek cizgi belirteci). */
/* Secici `.gate .gate-card input`, `.gate-card input` DEGIL — ve bu bir
   olcumun sonucu. Genel `input[type=...]` kurali (panel bolumu) ayni
   ozgullukte (0,1,1) ama dosyada DAHA SONRA geldigi icin beraberligi o
   kazaniyordu: PIN alani 60 yerine 44 piksel ciziliyordu. Ekranda
   olculdu (`offsetHeight` 44), gozle degil — 16 piksellik fark tek
   basina bakinca "biraz kisa" gorunuyor, yanlis gorunmuyor. */
.gate .gate-card input {
  width: 100%;
  height: 60px;
  margin: var(--s6) 0 var(--s4);
  padding: 0 var(--s4);
  font-family: var(--font-body);
  font-size: 22px;
  font-weight: 600;
  text-align: center;
  letter-spacing: 0.42em;
  text-indent: 0.42em; /* letter-spacing sagda bosluk birakir, ortayi kacirir */
  border: 1px solid var(--line-field);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
}
.gate-card .btn { width: 100%; justify-content: center; height: 52px; }

/* ---- MESAJLA GIRIS: IKI ADIM (Faz 1) ----------------------------------
   Adimlar AYNI kartin icinde yer degistiriyor, ayri sayfalar degil: kapinin
   yuksekligi degisse de amblemi ve basligi yerinde kaliyor, yani kullanici
   "baska bir yere gittim" hissi yasamiyor.
   Gizleme `hidden` niteligiyle; burada `display` ezen bir kural YOK (giris
   kabinin kendisinde bu hata bir kez yapildi, bkz. `.gate[hidden]`). */
.gate-step[hidden], .gate-yedek[hidden] { display: none; }

/* ULKE KODU AYRI VE SABIT. Girdi degil bir ETIKET: dokunulabilir gorunen bir
   kutu, kullaniciyi degistirebilecegi sanisina iter ve doldurulacak alan
   sayisini artirirdi. Kenarligi form alaninin kendi belirtecinden
   (`--line-field`) geliyor — yeni bir cizgi rengi uretilmedi. */
.gate-phone {
  display: flex;
  align-items: stretch;
  gap: var(--s2);
  margin: var(--s6) 0 var(--s4);
}
.gate-cc {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  min-width: 72px;
  padding: 0 var(--s3);
  font-size: 17px;
  font-weight: 600;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--line-field);
  border-radius: var(--radius);
}
/* Numara alani SOLA yasli ve seyrek harf araligi olmadan: telefon numarasi
   bir sir degil, okunacak bir dizi. Kod alani (tek kullanimlik) ortalanmis
   kalibin kendisi — o yuzden yalnizca bu alan ezliyor. */
.gate .gate-card .gate-phone input {
  flex: 1 1 auto;
  margin: 0;
  text-align: left;
  letter-spacing: 0.06em;
  text-indent: 0;
}
.gate-links {
  display: flex;
  gap: var(--s2);
  justify-content: center;
  flex-wrap: wrap;
  margin-top: var(--s3);
}
.gate-card .gate-links .btn { width: auto; height: 36px; }

/* Isletme secimi: her isletme bir dugme. `select` degil, cunku bu bir tercih
   degil bir DALLANMA — secilen sey aninda giris demek ve bir acilir listede
   "sec + onayla" iki adim olurdu. */
.gate-tenants { display: grid; gap: var(--s2); margin: var(--s6) 0 0; }
.gate-card .gate-tenants .btn { width: 100%; }

.gate-yedek {
  margin-top: var(--s6);
  padding-top: var(--s4);
  border-top: 1px solid var(--line-2);
  text-align: left;
}
.gate-yedek h2 { font-size: 15px; margin: 0 0 var(--s2); }
.gate-yedek p { margin: 0 0 var(--s2); }
/* ONE CIKAN YEDEK YOL (K4). Ikinci basarisiz turdan sonra bolum kendiliginden
   aciliyor ve gorunur agirlik kazaniyor: saldirgan kod kanalini tikadiginda
   mesru kullanicinin kalan tek yolu bu ve gizli bir baglanti olarak kalamaz.
   Kendi rengi YOK — var olan yuzey ve cizgi belirtecleri kullaniliyor. */
.gate-yedek.one-cikan {
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: var(--s4);
  margin-top: var(--s4);
}
.gate-field {
  display: block;
  margin-top: var(--s3);
  color: var(--ink-2);
}
/* Yedek yolun alanlari KOD ALANI DEGIL: kapinin 60 piksellik, ortalanmis,
   seyrek kalibi burada yanlis bir vaat olurdu (bunlar tek kullanimlik
   rakamlar degil, yazilan metinler). */
.gate .gate-card .gate-field input {
  height: 44px;
  margin: var(--s1) 0 0;
  font-size: 15px;
  font-weight: 400;
  text-align: left;
  letter-spacing: normal;
  text-indent: 0;
}
.gate-card .gate-yedek .btn { margin-top: var(--s3); height: 44px; }

.err { color: var(--danger); font-size: 13px; margin: var(--s3) 0 0; }
.hint {
  color: var(--ink-3);
  font-size: 13px;
  margin: var(--s6) 0 0;
  line-height: 1.5;
  padding-top: var(--s4);
  border-top: 1px solid var(--line-2);
}

/* ------------------------------------------------------------------- ust */

.top {
  display: flex; align-items: center; gap: var(--s5);
  /* Sayfa yatay kenari spec §3: 24 (mobil) / 32 (>=768) / 40 (>=1280).
     Ust cubuk govdeyle AYNI kenari tasimali, yoksa marka ile sayfa
     basligi dikey olarak hizasiz duruyor. */
  padding: 0 var(--s6); height: 64px;
  background: var(--surface);
  border-bottom: 1px solid var(--line-2);
  position: sticky; top: 0; z-index: 20;
}
@media (min-width: 768px) { .top { padding: 0 var(--s8); } }
@media (min-width: 1280px) { .top { padding: 0 var(--s10); } }

/* SEKME SERIDI KENDI SATIRINA INIYOR (dar masaustu).
   Olculdu: 1280 pikselde serit 936 piksel istiyor ama tek satirlik cubukta
   547 piksel buluyordu — on bir sekmenin besi kayma alaninda kaliyordu.
   ("Ana ekran" sekmesi ve gorunum secicisi bu sikismayi buyuttu, ama sorun
   yeni degil: seridin kendi notunda 1280'de 190 piksellik tasma zaten
   yaziliydi.) Iki satirda serit tam genisligi buluyor ve HICBIR sekme
   kayma alanina dusmuyor.

   Esik 1500px: bunun ustunde tek satir hala rahat sigiyor ve daha kompakt
   duruyor. Kayma + kenar solmasi mekanizmasi olduğu gibi kaliyor — daha da
   dar bir pencerede (tablet) yine devreye giriyor. */
@media (max-width: 1500px) {
  .top {
    flex-wrap: wrap;
    height: auto;
    padding-top: var(--s2);
    padding-bottom: var(--s2);
    row-gap: var(--s1);
  }
  /* SATIR KIRICI SAHTE OGE. Serit kendi satirina inmeli ama HAP KABI
     icerigi kadar genis olmali — `flex-basis: 100%` ikisini ayni anda
     istiyordu ve kabi 1400 piksellik bir kapsule cevirmisti (kare
     `02-anaekran/koyu-ustcubuk.png`). Yuksekligi sifir, gorunmez bir
     ::before satiri kiriyor; serit de artik `auto` genislikte. */
  .top::before {
    content: '';
    order: 2;
    flex: 0 0 100%;
    height: 0;
  }
  .top .tabs {
    order: 3;
    flex: 0 1 auto;
    width: auto;
    max-width: 100%;
    margin-top: var(--s1);
  }
}
/* MARKA SATIRI — iki bicim, tek kutu genisligi.
   `.mark`  : kiracinin kendi logotipi (kayitta logo anahtari varsa).
   `.tenant-name` : logosu olmayan kiraci — tipografik ad, vitrinin baslik
   ailesiyle. Ikisi de ust cubukta ayni yeri kapliyor, boylece kiraci
   degistirmek serit genisligini oynatmiyor. Uzun isletme adlari sarmiyor,
   kirpiliyor: 58 piksellik cubugun iki satira cikmasi (paket 5'te olculdu)
   govdeyi tasiriyordu. */
.brand { display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.brand .mark { width: 108px; color: var(--ink); flex: 0 0 auto; }
.brand .tenant-name {
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--ink);
  max-width: 220px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* DOKUZ SEKME (istatistikler eklendi). Sekiz sekmede serit 1440px'e rahat
   siğiyordu; dokuzuncuyla flex kutulari SIKISTIRMAYA basladi ve "Saatler &
   Molalar" etiketi kendi icinde iki satira sarip ust cubugu 58 → 81 piksele
   cikardi. Uc parcalik cozum:
   - `nowrap` + `flex: 0 0 auto`: etiket sarmaz, dugme kendi genisligini korur;
   - `.tabs { min-width: 0; overflow-x: auto }`: dar ekranda serit KENDI icinde
     kayar, ust cubugu ya da sayfayi tasirmaz (govde tasmasi 34px olculmustu);
   - kaydirma cubugu gizli, cunku klavye gezinmesi (ok tuslari) zaten var ve
     58 piksellik bir cubukta 8 piksellik gri bir cizgi gorsel gurultu. */
/* SEKME SERIDI = HAP KABI (spec §7.4).
   Kap `surface-2` zeminli, 999px kose, 4px ic dolgu, 44px yuksek; aktif
   sekme kabin icinde beyaz bir HAP (koyu temada `surface-3`) + golge.
   Onceki dil alt-cizgiliydi ve yeni dilde tek basina kaliyordu: tasarimda
   hicbir yerde alt cizgi yok, secili durum DOLGUYLA anlatiliyor.

   `overflow-x: auto` + gizli kaydirma cubugu KORUNDU — serit dar ekranda
   hala kendi icinde kayiyor ve sayfayi tasirmiyor. Hapin kabin disina
   tasmamasi icin kap `overflow` degil `padding` tasiyor. */
.tabs {
  display: flex; gap: var(--s1); min-width: 0;
  overflow-x: auto; scrollbar-width: none;
  background: var(--surface-2);
  border-radius: var(--radius-pill);
  padding: 4px;
  height: 44px;
  align-items: center;
}
.tabs::-webkit-scrollbar { display: none; }
/* SERIT KAYABILIYORSA BUNU SOYLE.
   `overflow-x: auto` + gizli kaydirma cubugu sayfayi tasmaktan koruyor ama
   "daha var" bilgisini HICBIR YERDE gostermiyordu. Onuncu sekme (Oturumlar)
   eklenince olculdu: cok kiracili isletmeci oturumunda serit 1440 pikselde
   46, 1366'da 113, 1280'de 190 piksel tasiyor — yani en yaygin dizustu
   genisliklerinde SON sekme yarim kaliyor ve kullanici kaydirabilecegini
   bilmiyor. Kenar solmasi o bilgiyi geri veriyor: kirpilmis bir etiket
   kaza gibi gorunur, solan bir kenar "devami var" der. */
.tabs.more-right { mask-image: linear-gradient(to right, #000 calc(100% - 30px), transparent); }
.tabs.more-left { mask-image: linear-gradient(to right, transparent, #000 30px); }
.tabs.more-left.more-right {
  mask-image: linear-gradient(to right, transparent, #000 30px, #000 calc(100% - 30px), transparent);
}
/* TUR 2C — SERIT ARTIK BES SEKME. Yukaridaki kayma/solma cozumu DURUYOR
   (bir sonraki kategori eklenirse yine gerekir) ama olculen tasmanin kendisi
   kalmadi: on iki sekme yerine bes kategori var ve serit 1024 pikselde bile
   tam siğiyor. Sekmeye piktogram eklendi (madde 7) ve alt cizgi artik
   kategorinin kendi rengini tasiyor (madde 5) — sekme seridiyle ana ekranin
   kutucuklari ayni renk sozlugunu konusuyor. */
/* PASIF SEKME `--ink-2`, spec'in dedigi `--ink-3` DEGIL — ve bu olcumun
   sonucu. Spec §7.4 pasif sekmeyi `ink3` yaziyor ama kabin zemini
   `surface-2`; o cift 4,34'te kaliyordu (AA 4,5 alti). `--ink-3` bir
   kademe koyulasinca (CEO karari) cift 5,55'e cikti, yine de `--ink-2`
   secildi: aktif sekme `--ink` ve aradaki hiyerarsi ink > ink-2 daha
   okunur bir basamak veriyor. Pasif/aktif ayrimini asil DOLGU tasiyor,
   renk degil. */
.tabs button {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; color: var(--ink-2); cursor: pointer;
  padding: 0 var(--s3); height: 36px; font: inherit;
  font-size: 14px; font-weight: 500;
  white-space: nowrap; flex: 0 0 auto;
  border-radius: var(--radius-pill);
  transition: color var(--dur-1) var(--ease-out),
    background-color var(--dur-1) var(--ease-out),
    transform 90ms var(--ease-out);
}
.tabs button svg { width: 16px; height: 16px; flex: 0 0 auto; }
.tabs button:hover { color: var(--ink); }
.tabs button:active { transform: scale(0.985); }
/* SECILI SEKME = `accent` DOLGU + `accentInk` METIN (spec §1.5 bunu ismen
   soyluyor: "birincil dugme, SECILI SEKME DOLGUSU bunu kullanir";
   Addendum-3 baglayici kural).

   ONCEKI HALI OLCULDU: dolgu `--surface` (#FFFFFF), kap `--surface-2`
   (#F1F5F9) — iki durum arasindaki fark 1,10. Ayni hex degildi, ama bir
   DURUM farkini tasiyan tek sinyal 1,10'luk bir zemin oynamasiydi; golge
   ve 600 agirlik onu telafi etmek icin oradaydi. Simdi fark 16,30 ve
   telafiye gerek yok — golge kalkti, cunku dolu bir hap zaten kabin
   icinden ayriliyor ve ikinci bir yukselti sinyali gurultu olurdu.

   TEK KURAL IKI TEMADA: `[data-theme='dark']` override'i KALKTI. Koyu
   temada `--accent` (#E9EEF5) / `--accent-ink` (#0B1220) zaten ters cifti
   tasiyor; ayri bir koyu kural iki temanin ayrisma yeriydi. Mobil ayni
   kurali uyguluyor. */
.tabs button.on {
  color: var(--accent-ink);
  background: var(--accent);
  font-weight: 600;
}
/* Dokuz sekmeyle ust cubugun genislik butcesi olculmustu (1440px'te):
   marka 268 + serit 834 + sag blok 395 + bosluk/padding 76 = 1573px. O turda
   feda edilen oge sabit "RANDEVU PANELI" yazisiydi ve 1600px ustunde geri
   geliyordu; artik cubukta hic yok. Urun adi giris kapisinda duruyor, ust
   cubuk yalnizca KIRACIYI soyluyor — marka kutusu 268'den ~108-220 piksele
   indigi icin serit her genislikte daha rahat. */

.top-right { margin-left: auto; display: flex; gap: var(--s2); align-items: center; }
.top-right select {
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-field);
  padding: 0 var(--s3); height: 40px; border-radius: var(--radius);
  font: inherit; font-size: 14px;
}

/* ---------------------------------------------------------------- panel */

/* Sayfa kabi spec §7.6: maks. 1280px, yatay dolgu 40/32/24, dikey 32. */
.panel { padding: var(--s8) var(--s6) var(--s10); max-width: 1280px; margin: 0 auto; }
@media (min-width: 768px) { .panel { padding-left: var(--s8); padding-right: var(--s8); } }
@media (min-width: 1280px) { .panel { padding-left: var(--s10); padding-right: var(--s10); } }

.bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-bottom: 14px;
}
.bar label { display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-2); }
/* Filtre seridindeki dugme, YANINDAKI alanla ayni yuksekligi tasimali.
   Varsayilan `.btn` 40, form alani 44 — dorder piksellik fark tek basina
   bakinca gorunmuyor ama ayni satirda yan yana durunca dugme "biraz
   yukarida" duruyor (kare `04-randevular/acik-liste.png`). */
.bar .btn { height: 44px; }
.bar .btn.tiny { height: 32px; }

/* SAYIM TABANI notu — tarih secicinin hemen altinda, sayilarin ustunde.
   Yeri onemli: "hangi tarih?" sorusunun sorulduğu yerle "hangi tarih
   sayiliyor?" cevabi arasinda baska bir sey durmuyor. Ince altin cizgi
   uyari degil DIPNOT tonu veriyor. */
.basis {
  margin: -4px 0 14px;
  max-width: 92ch;
  line-height: 1.55;
  padding-left: 11px;
  border-left: 2px solid rgba(var(--accent-rgb), 0.38);
  /* RENK BILINCLI OLARAK `--ink-3` DEGIL. O token koyu zeminde 3,90
     kontrastta ve AA'yi (4,5) karsilamiyor (mobil belirteclerinde olculup
     yazili: `mobile/lib/core/tokens.dart`). Bu satir dekorasyon degil,
     sayilarin ne anlama geldigini soyleyen TASIYICI bilgi — okunmali. */
  color: var(--ink-2);
}
.basis strong { color: var(--ink); font-weight: 600; }
.daynav { display: flex; align-items: center; gap: 6px; }

/* ------------------------------------------------- TAKVIM EKSENI (M11)
   Segment secici; iki durum ayni anda gorunur olsun diye acilir liste
   DEGIL. Kullanicinin sordugu soru "hangi eksendeyim" ve cevabi tek
   bakista okunmali — bir <select> once acilmayi bekletir.
   `hidden` niteligi bir `display` kurali TASIMIYORUZ: yalnizca
   tarayicinin varsayilani calisiyor. (Yazar tarafinda bir `display:flex`
   kurali koysaydik `hidden` sessizce ISLEVSIZ kalirdi — bu kod tabaninda
   daha once yasanmis bir kusur sinifi.) */
.cal-axis-switch[hidden] { display: none; }
/* Eksen secici de HAP KABI dilinde (sekme seridiyle ayni kalip): kap
   `surface-2`, aktif hap `surface` + golge. Ic kenarlik cizgileri kalkti —
   dolgu zaten ayirıyor, cizgi eklemek iki sinyal olurdu. */
.cal-axis-switch {
  display: inline-flex; gap: var(--s1); border: 0;
  background: var(--surface-2);
  border-radius: var(--radius-pill); padding: 4px; margin-left: var(--s1);
}
.axis-btn {
  appearance: none; border: 0; background: none; color: var(--ink-2);
  font: inherit; font-size: 13px; font-weight: 500;
  padding: 0 var(--s3); height: 32px; cursor: pointer;
  border-radius: var(--radius-pill);
  transition: background var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
}
.axis-btn:hover { color: var(--ink); }
/* Eksen secicisi de bir SEKME: ayni kural (spec §1.5). Olculen eski fark
   1,10 (beyaz hap / #F1F5F9 kap) — yeni fark 16,30. */
.axis-btn.on { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.axis-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.daymeta { font-size: 14px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.daymeta strong { color: var(--ink); font-weight: 600; }

/* FORM ALANI (spec §7.3). Yukseklik 44 — spec 52 diyor ve MOBILDE oyle;
   panelde ayni satirda 4-5 kontrol bulunan filtre seritleri var (takvim
   basligi, saat satirlari) ve 52 orada satiri iki kata cikariyor. 44,
   `tapMin`in (48) hemen altinda ama bunlar isaretleme cihazi hedefleri;
   dokunmatik hedef kurali dokunulabilir kutucuklarda (kategori, satir)
   zaten saglaniyor. Kose, zemin, kenarlik, odak halkasi spec'in aynisi. */
input[type='date'], input[type='time'], input[type='text'], input[type='tel'],
input[type='password'], input[type='number'], select {
  padding: 0 var(--s3); height: 44px;
  border: 1px solid var(--line-field); border-radius: var(--radius);
  background: var(--surface); font: inherit; font-size: 14px; color: var(--ink);
  transition: border-color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out);
}
input[type='date'], input[type='time'] { font-variant-numeric: tabular-nums; }
input:hover, select:hover { border-color: var(--ink-3); }
input::placeholder { color: var(--ink-3); }
/* ODAK: kenarlik `accent` + 2px dis halka (spec §7.3). `outline` TEK BASINA
   YASAK — 16px kose yaricapinda tarayici anahattı kutuyu kare gosteriyor ve
   odak halkasi kartin kosesinden tasiyordu. `box-shadow` halkasi kose
   yaricapini takip ediyor. `outline: none` degil `outline-color:
   transparent`: zorlanmis renk kipinde (Windows yuksek kontrast) anahat
   geri geliyor, yani odak orada da gorunur kaliyor. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid transparent; outline-offset: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.14);
}
button:focus-visible, a:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm);
}
/* TAKVIM IKONU ARTIK BIZIM, TARAYICININ DEGIL (D1/2, 2026-08-27).
 *
 * OLCULEN KUSUR: koyu temada ikon HIC gorunmuyordu (ekran goruntusuyle
 * dogrulandi). Kok, iki dogru kuralin carpismasi: `:root[data-theme='dark']`
 * `color-scheme: dark` tasiyor, yani Chrome yerel gostergeyi ZATEN ACIK tonda
 * ciziyor; eski `filter: invert(0.9)` onu tekrar KOYUYA cevirip koyu zemine
 * gomuyordu. Filtre yazildiginda `color-scheme` yoktu — kural bozulmadi,
 * altindaki varsayim degisti.
 *
 * COZUM TERSLEME DEGIL MASKE: gosterge bir MASKE ile kendi piktogram
 * ailemize donuyor ve rengini `--ink-2` BELIRTECINDEN aliyor. Boylece
 * "hangi temada ne renk" sorusunun cevabi tarayici varsayilanina degil
 * belirtece bagli — iki temada da olculebilir. Maskede tek bir renk degeri
 * YOK: SVG'de `fill` yazilmadigi icin sekil varsayilan opak alfayla kesiliyor
 * (maskede siyah = "burasi gorunsun"), yani bu bir RENK degil bir STENSIL.
 *
 * Olcu 13px'ten (tarayici varsayilani) 18px'e cikti: Melih'in denemesinde
 * ikon hem gorunmuyor hem de "kucuk" diye isaretlendi.
 *
 * SAAT (`input[type='time']`) DISARIDA: onun gostergesi saat kadrani, takvim
 * degil; olculmemis bir yuzeye kendi glifimizi dayatmiyoruz. Orada eski
 * terslemenin YERINE filtre kaldirildi — `color-scheme: dark` altinda yerel
 * kadran zaten acik tonda ciziliyor. */
input[type='date']::-webkit-calendar-picker-indicator {
  cursor: pointer;
  width: 18px; height: 18px;
  opacity: 0.75;
  background-color: var(--ink-2);
  background-image: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2h2v4H7zM15 2h2v4h-2zM3 6h18v3H3zM3 9h2v12H3zM19 9h2v12h-2zM3 19h18v2H3zM7 12h3v3H7zM12 12h3v3h-3z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2h2v4H7zM15 2h2v4h-2zM3 6h18v3H3zM3 9h2v12H3zM19 9h2v12h-2zM3 19h18v2H3zM7 12h3v3H7zM12 12h3v3h-3z'/%3E%3C/svg%3E") center / contain no-repeat;
}
input[type='time']::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.6;
}
[data-theme='dark'] input[type='time']::-webkit-calendar-picker-indicator {
  opacity: 0.75;
}
input[type='date']::-webkit-calendar-picker-indicator:hover {
  opacity: 1; background-color: var(--ink);
}
input[type='time']::-webkit-calendar-picker-indicator:hover { opacity: 1; }
input[type='checkbox'] {
  width: 15px; height: 15px; accent-color: var(--accent);
  vertical-align: -2px; cursor: pointer;
}

/* DUGME (spec §7.3). Ikincil dugme artik CERCEVELI DEGIL DOLGULU
   (`surface-2` zemin, `ink` metin) — tasarimda hicbir yerde cerceveli
   dugme yok, ayrim dolguyla yapiliyor. `--line-field` kenarlik yalnizca
   `.btn.outline` varyantinda kaldi (tablo satirlarindaki tekil eylemler
   dolgulu olunca satir bir dugme tarlasina donuyordu). */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 0 var(--s4); height: 40px;
  border: 1px solid transparent; background: var(--surface-2);
  color: var(--ink); border-radius: var(--radius); cursor: pointer;
  font: inherit; font-size: 14px; font-weight: 600; letter-spacing: 0;
  text-decoration: none; white-space: nowrap;
  transition: background-color var(--dur-1) var(--ease-out),
    border-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out),
    transform 90ms var(--ease-out);
}
.btn:hover { background: var(--surface-3); }
.btn:active { transform: scale(0.985); box-shadow: var(--shadow-press); }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.btn.primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.btn.outline {
  background: transparent; border-color: var(--line-field); color: var(--ink);
}
.btn.outline:hover { background: var(--surface-2); border-color: var(--ink-3); }
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--surface-2); color: var(--ink); border-color: transparent; }
.btn.icon { padding: 0; width: 40px; font-size: 17px; line-height: 1; }
.btn.tiny { padding: 0 var(--s3); height: 32px; font-size: 12px; font-weight: 600; border-radius: var(--radius-sm); }
.btn.danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.btn.danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn-row { display: flex; gap: var(--s2); flex-wrap: wrap; margin-top: var(--s4); }
.btn-row.end { justify-content: flex-end; }

/* -------------------------------------------------------------- kiyas

   Demonun kanit anı. Sayilar buyuk, tipografi vitrinin display ailesi,
   iki taraf gorsel olarak esit AGIRLIKTA DEGIL: bizim motor altin ve
   dolu, DD notr ve kesik cizgili — sayfanin geri kalanindaki serit
   renkleriyle birebir ayni kod. */

.compare-bar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 16px; margin-bottom: 14px;
  background: linear-gradient(90deg, var(--accent-soft), transparent 62%),
    var(--surface);
  border: 1px solid var(--line);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius);
}
.switch { display: flex; align-items: center; gap: 9px; cursor: pointer; font-size: 14px; color: var(--ink-2); }
.switch strong { color: var(--ink); font-weight: 600; }
/* "3.3×" GERCEKTEN ORTADA DURSUN.
   Onceden flex + otomatik genislikti: "23 BIZIM MOTOR" (2 haneli, kisa etiket)
   ile "7 DD · SABIT 60 DK" (1 haneli, uzun etiket) icerige gore farkli
   genislige oturuyor, aradaki carpan da bu yuzden optik olarak sola
   kayiyordu. Grid 1fr/auto/1fr iki kutuyu esitliyor ve carpani tam ortaya
   kilitliyor — hizmet dropdown'i degisip rakamlarin basamak sayisi degisse
   bile (or. 7 -> 12) hizalama bozulmuyor. Bu serit demonun kanit ani, en
   ince detayi da tutmali. */
.cmp-summary {
  margin-left: auto;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: 14px;
  align-items: stretch;
}
.cmp-metric {
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px 14px; border-radius: var(--radius);
  border: 1px solid var(--line-2); background: var(--surface-2);
  min-width: 104px;
}
.cmp-metric b {
  font-family: var(--font-display);
  font-size: 26px; font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.cmp-metric span {
  font-size: 10.5px; letter-spacing: 0.11em; text-transform: uppercase;
  font-weight: 600; color: var(--ink-3);
}
/* "Bizim motor DOLU, DD notr ve kesik" — yorumun soyledigi sey buydu ama
   dolgu `accentSoft` idi ve o da `surface-2`ye esit: iki kutu OLCULEN
   1,00, yani demonun kanit aninda iki taraf ayni griydi. Fark yalnizca
   %50 opak bir cerceveden (#8F9193) ve metin renginden okunuyordu.
   Simdi gercekten dolu: `accent` + `accentInk` (16,30). */
.cmp-metric.ours {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}
.cmp-metric.ours b { color: var(--accent-ink); }
.cmp-metric.ours span { color: var(--accent-ink); opacity: 0.72; }
.cmp-metric.dd { border-style: dashed; }
/* ARA SURE kazanimi dorduncu bir kutu ekliyor — yalnizca kazanim VARSA
   (sinif JS'te ekleniyor), aksi halde uc kutuluk hizalama bozulurdu. */
.cmp-summary.with-gap { grid-template-columns: 1fr auto 1fr 1.35fr; }
.cmp-metric.gap {
  border-color: rgba(var(--ok-rgb), 0.5);
  background: rgba(var(--ok-rgb), 0.1);
}
.cmp-metric.gap b { color: var(--ok); }
.cmp-metric.gap span { color: var(--ok-ink); }
.cmp-metric.gap em {
  font-style: normal; font-size: 10.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums; letter-spacing: 0;
}
.cmp-x {
  align-self: center;
  font-family: var(--font-display);
  font-weight: 600; font-size: 19px; color: var(--accent);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------- takvim */

.calendar-wrap {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); box-shadow: var(--shadow); overflow: auto;
}
.calendar { display: grid; min-width: 640px; position: relative; }
.cal-head {
  position: sticky; top: 0; z-index: 4; background: var(--surface);
  border-bottom: 1px solid var(--line-2); padding: 10px 8px;
  font-size: 13px; font-weight: 600; text-align: center; color: var(--ink);
}
.cal-head .sub {
  display: block; font-weight: 500; font-size: 11px; color: var(--ink-3);
  margin-top: 2px; font-variant-numeric: tabular-nums;
}
.cal-head.off { color: var(--ink-3); }
.cal-head.off .sub { color: var(--danger); }

/* Ilk saat etiketi (translateY(-50%)) sutunun tepesinden tasip yapisik
   basligin altinda kaliyordu; iki taraf da ayni miktarda asagi kaydirilinca
   hizalama bozulmadan gorunur oluyor. */
.cal-axis, .cal-col { margin-top: 10px; }
.cal-axis { border-right: 1px solid var(--line); position: relative; background: var(--surface-0); }
.axis-label {
  position: absolute; right: 6px; font-size: 11px; color: var(--ink-3);
  transform: translateY(-50%); font-variant-numeric: tabular-nums;
}
.cal-col { position: relative; border-right: 1px solid var(--line); }
.cal-col:last-child { border-right: 0; }
.hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--line); }
.half-line { position: absolute; left: 0; right: 0; border-top: 1px dashed rgba(var(--ink-rgb), 0.05); }

.blk {
  position: absolute; left: 4px; right: 4px;
  border-radius: var(--radius-sm); padding: 5px 8px; overflow: hidden;
  font-size: 12px; line-height: 1.25; cursor: pointer;
}
/* ÇAKIŞIK RANDEVU ŞERİTLERİ (K1, Melih kararı 2026-08-27).
   İşletme artık dolu bir aralığa BİLEREK yazabiliyor; iki blok sütunun
   tamamını kaplayınca sonradan çizilen ötekini TAMAMEN örtüyordu — ekranda
   tek randevu, veritabanında iki.

   `right: auto` BURADA, satır içinde DEĞİL. `left` + `right` + `width`
   üçü birden verilirse tarayıcı `right`i "aşırı kısıtlı" diye düşürüyor;
   o düşürmeye güvenmek, kuralın bir tarayıcı ayrıntısına asılması olurdu.
   Genişliğin kendisi satır içinde, çünkü şerit SAYISINA bağlı (blokların
   `top`/`height`i de aynı şekilde hesaplanıyor). */
.blk-serit { right: auto; }
/* BLOK ZEMINI ARTIK `--surface`, `--surface-3` DEGIL — ve bu olcumun
   sonucu, uslup degil. Renk kodunun sekiz kanali blogun SOL KENARINDA
   3px opak bir cizgi olarak duruyor ve 1.4.11'in 3:1 esigine tabi;
   `--cal-4` (kehribar #D97706) `--surface-3` (#E2E8F0) uzerinde 2,58
   olculuyor, `--surface` uzerinde 3,19. Sekiz kanaldan yedisi her iki
   zeminde geciyordu, bir tanesi gecmiyordu — ve bu, blok zemini
   koyulastikca dogan bir kusur sinifi. Yeni dilde takvim zaten beyaz
   kartin icinde yasiyor, yani bu ayni zamanda spec §7.2'nin dedigi sey. */
.blk-appt {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-2); border-left: 3px solid var(--accent);
  transition: background-color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out);
}
/* Uzerine gelme ayrimini zemin TEK BASINA tasiyamiyor: `--blk-hover`
   (#F8FAFC) beyazdan yalnizca 1,05 ayriliyor (kehribar kanali daha acik
   bir zemin istedigi icin bilincli olarak boyle). Golge ikinci sinyal. */
.blk-appt:hover { background: var(--blk-hover); box-shadow: var(--shadow); }
.blk-appt .t { font-weight: 700; font-variant-numeric: tabular-nums; }
.blk-appt .n { color: var(--ink-2); }

/* ================= SURUKLE-TASI (SK-3, ui-ux sartnamesi §1.2-§1.4) ========
   YENI JETON YOK — hepsi `:root`ta zaten tanimli ve koyu temada yeniden
   tanimli, yani bu blok icin ikinci bir tema kaydi gerekmiyor (spec §6).

   `touch-action: pan-x pan-y` (spec §4): parmak bloga degip hemen kayarsa bu
   bir KAYDIRMADIR, surukleme degil. Sureklilik JS esiginde (~350ms) karara
   baglaniyor; burada tarayiciya "once kaydirmayi dene" deniyor. */
.blk-appt { touch-action: pan-x pan-y; }
/* HAYALET: blok kalkti ama goz nereye donecegini bilsin (§1.2). Ara sureli
   randevuda birden cok parca ayni sinifi aliyor — yarisi solmus bir randevu
   "bir kismi tasindi" gibi okunurdu. */
.blk-appt.tasima-kaynak { opacity: 0.35; }
/* KALDIRMA: imleci izleyen klon. `transition: none` bilincli — geciste kalan
   bir blok imlecin arkasindan surunur (emsal: `dialog#asistanDlg.tasiniyor`). */
/* `z-index: 30` — yapisik ust cubugun (20) USTUNDE, asistan penceresinin (50)
   ALTINDA. Ustune cikmasi U1/§1.0'in olctugu kurali kirardi: non-modal
   pencere `show()` ile acildigi icin ust katmani YOK ve panelin hicbir
   katmani onu asmamali. Suruklenen bir blok da bir panel katmanidir. */
.tasima-klon {
  position: fixed; z-index: 30; pointer-events: none;
  transform: scale(1.03); box-shadow: var(--shadow); transition: none;
}
/* I-066 — BEKLEYEN TASIMANIN ONIZLEMESI, IZGARANIN ICINDE.
   `.tasima-klon`un aksine `position: absolute` ve hedef sutunun cocugu:
   kaydirma, yeniden cizim ve yerlesim kaymasi onu bozamaz. Kesikli kenar
   "henuz olmadi" diyor; kati bir blok onaylanmis bir randevu demekti.
   `pointer-events: none` — onizleme bir hedef degil, bir goruntu. */
.blk-onizleme {
  left: 4px; right: 4px; pointer-events: none;
  background: rgba(var(--accent-rgb), 0.12);
  border: 1px dashed rgba(var(--accent-rgb), 0.55);
  color: var(--accent);
  font-weight: 600;
}
/* GERI DONUS (§1.4/3): yalnizca reddedilen ya da vazgecilen birakmada. */
.tasima-klon.tasima-geri {
  transition: left var(--dur-2) var(--ease-out), top var(--dur-2) var(--ease-out);
}
/* HEDEF DILI (§1.3). Gecerli = vurgu, gecersiz = uyari. `--danger-rgb`
   KULLANILMIYOR: bu bir hata degil, henuz tamamlanmamis bir hareket. */
.cal-col.tasima-gecerli { background: rgba(var(--accent-rgb), 0.12); }
.cal-col.tasima-gecersiz { background: rgba(var(--warn-rgb), 0.10); cursor: not-allowed; }
/* Surukleme boyunca metin secimi kapali: aksi halde takvim boyunca suruklenen
   parmak/imlec sutun basliklarini mavi bir blok halinde secerdi. */
body.takvim-tasiniyor { user-select: none; }
/* I-067 — ONAY KARTI YAPISKAN. Kart izgaranin USTUNDE duruyor; kullanici
   650 piksel asagida ogleden sonra satirlarindayken kart gorus alaninin cok
   disinda kaliyordu ve `scrollIntoView` sayfayi kartin belge konumuna —
   pratikte en uste — atlatiyordu. Her birakmada bir kez. Yapiskan kart
   kaydirmadan bagimsiz gorunur kaliyor; JS tarafi da kaydirmayi geri koyuyor
   (`tasimaKartCiz`). `.calendar-wrap`a yukseklik VERILMIYOR — iç kaydirma
   I-010'u geri getirirdi. */
.cal-onay {
  margin-bottom: var(--s3);
  position: sticky; top: 0; z-index: 5; background: var(--surface);
}
.cal-onay .switch { margin-top: var(--s3); }

/* TAKVIM RENK KODU (Tur 2 — S7).
   Bu blogun `.blk-appt`ten SONRA, durum sinifi kurallarindan (`.walkin`,
   `.has-gap`, `.packed`, `.orphan`) ONCE gelmesi bilincli: renk kodu
   varsayilan vurguyu eziyor ama DURUM renklerini ezmiyor. Walk-in mavisi ve
   yetim uyarisi, kullanicinin actigi bir gorsel tercihten daha onemli.

   Zemin %8 alfa: metin kontrasti pratikte degismiyor (olculdu, §QA).
   Dolgun zemin, sekiz renk icin sekiz ayri metin rengi hesaplamak demekti.

   TON `background-image` OLARAK BINIYOR, `background` KISAYOLUYLA DEGIL.
   Sebep somut: `:hover` ve `.packed` zemini kisayolla degistiriyor. Kisayol
   kullansaydik ya uzerine gelme calismaz (bizimki sonra geldigi icin) ya da
   renk kaybolurdu. `background-image` ayri bir uzun ozellik oldugu icin ton
   uzerine-gelmede DURUYOR, zemin rengi ise altta degisiyor.

   NOT: `color-mix` bilincli olarak KULLANILMIYOR (bkz. kanal belirteclerinin
   notu): alfa katmani ozel-ozellik destegi olan her tarayicida calisiyor. */
.blk-appt.cal-c0 { border-left-color: rgb(var(--cal-1-rgb)); background-image: linear-gradient(rgba(var(--cal-1-rgb), .08), rgba(var(--cal-1-rgb), .08)); }
.blk-appt.cal-c1 { border-left-color: rgb(var(--cal-2-rgb)); background-image: linear-gradient(rgba(var(--cal-2-rgb), .08), rgba(var(--cal-2-rgb), .08)); }
.blk-appt.cal-c2 { border-left-color: rgb(var(--cal-3-rgb)); background-image: linear-gradient(rgba(var(--cal-3-rgb), .08), rgba(var(--cal-3-rgb), .08)); }
.blk-appt.cal-c3 { border-left-color: rgb(var(--cal-4-rgb)); background-image: linear-gradient(rgba(var(--cal-4-rgb), .08), rgba(var(--cal-4-rgb), .08)); }
.blk-appt.cal-c4 { border-left-color: rgb(var(--cal-5-rgb)); background-image: linear-gradient(rgba(var(--cal-5-rgb), .08), rgba(var(--cal-5-rgb), .08)); }
.blk-appt.cal-c5 { border-left-color: rgb(var(--cal-6-rgb)); background-image: linear-gradient(rgba(var(--cal-6-rgb), .08), rgba(var(--cal-6-rgb), .08)); }
.blk-appt.cal-c6 { border-left-color: rgb(var(--cal-7-rgb)); background-image: linear-gradient(rgba(var(--cal-7-rgb), .08), rgba(var(--cal-7-rgb), .08)); }
.blk-appt.cal-c7 { border-left-color: rgb(var(--cal-8-rgb)); background-image: linear-gradient(rgba(var(--cal-8-rgb), .08), rgba(var(--cal-8-rgb), .08)); }

/* QR kutusu (S8) — kod HER ZAMAN beyaz zeminde. Koyu temada koyu zemine
   basilan/gosterilen bir QR okunmaz; tarayicilar ters kontrasti cogunlukla
   cozemiyor. Bu yuzden kutu temadan BAGIMSIZ. */
.qr-box {
  display: inline-block; background: #fff; padding: var(--s3);
  border: 1px solid var(--line-2); border-radius: var(--radius); line-height: 0;
}
.qr-box svg { display: block; width: 200px; height: 200px; }

/* Tablo satirindaki islem dugmeleri tek satirda kalsin. */
.row-actions { white-space: nowrap; }

/* Efsane kutucugu — takvim blogunun kucultulmus hali. */
.lg-cal { background-color: var(--surface); border: 1px solid var(--line-2); }
.lg-cal.cal-c0 { border-left: 3px solid rgb(var(--cal-1-rgb)); background-image: linear-gradient(rgba(var(--cal-1-rgb), .08), rgba(var(--cal-1-rgb), .08)); }
.lg-cal.cal-c1 { border-left: 3px solid rgb(var(--cal-2-rgb)); background-image: linear-gradient(rgba(var(--cal-2-rgb), .08), rgba(var(--cal-2-rgb), .08)); }
.lg-cal.cal-c2 { border-left: 3px solid rgb(var(--cal-3-rgb)); background-image: linear-gradient(rgba(var(--cal-3-rgb), .08), rgba(var(--cal-3-rgb), .08)); }
.lg-cal.cal-c3 { border-left: 3px solid rgb(var(--cal-4-rgb)); background-image: linear-gradient(rgba(var(--cal-4-rgb), .08), rgba(var(--cal-4-rgb), .08)); }
.lg-cal.cal-c4 { border-left: 3px solid rgb(var(--cal-5-rgb)); background-image: linear-gradient(rgba(var(--cal-5-rgb), .08), rgba(var(--cal-5-rgb), .08)); }
.lg-cal.cal-c5 { border-left: 3px solid rgb(var(--cal-6-rgb)); background-image: linear-gradient(rgba(var(--cal-6-rgb), .08), rgba(var(--cal-6-rgb), .08)); }
.lg-cal.cal-c6 { border-left: 3px solid rgb(var(--cal-7-rgb)); background-image: linear-gradient(rgba(var(--cal-7-rgb), .08), rgba(var(--cal-7-rgb), .08)); }
.lg-cal.cal-c7 { border-left: 3px solid rgb(var(--cal-8-rgb)); background-image: linear-gradient(rgba(var(--cal-8-rgb), .08), rgba(var(--cal-8-rgb), .08)); }
.blk-appt.walkin { border-left-color: var(--walkin); }
.blk-break {
  background: repeating-linear-gradient(45deg, var(--hatch-a) 0 6px, var(--hatch-b) 6px 12px);
  color: var(--ink-3); border: 1px dashed var(--line); cursor: default;
}

/* ============================================ ARA SURE / ISLEM SURESI (#5)
   Takvimde anlatilmasi gereken tek cumle: "bu randevu 90 dakika yer tutuyor
   ama personel yalnizca ilk 30 ve son 15 dakikada mesgul."

   Bunu RENKLE degil DOKUYLA soyluyoruz: bekleme penceresi blogun icinde
   cizgili bir bant. Renk kodu panelde zaten dolu (altin = bizim motor,
   notr = DD, kirmizi = simdi, kesikli = iptal); bekleme icin altinci bir
   renk eklemek tabloyu okunmaz yapardi. Doku ise "burasi baska bir sey"
   demenin en ucuz yolu — ve yazdirilan/dusuk kontrastli ekranda da kaliyor. */
.blk-appt.has-gap { border-left-color: var(--ok); }
/* Bitirme blogu tek satir: 15 dakika = 20 piksel. Ikinci satir sigmaz,
   sigdirmaya calismak metni kirpardi. */
.blk-appt.has-gap.finish { padding: 2px 7px; font-size: 11px; line-height: 1.35; }
.blk-appt.has-gap.finish .n { color: var(--ink-3); }

/* OMURGA: iki blogun ayni randevu oldugunu tasiyan ince dikey cizgi.
   Olmasa iki ayri musteri gibi okunurdu. */
.gap-span {
  position: absolute; left: 4px; width: 2px;
  background: linear-gradient(
    to bottom,
    var(--ok) 0 2px,
    rgba(var(--ok-rgb), 0.35) 2px
  );
  border-radius: 4px; pointer-events: none; z-index: 1;
}
.gap-zone {
  position: absolute; left: 4px; right: 4px;
  background: repeating-linear-gradient(
    -45deg,
    rgba(var(--ok-rgb), 0.14) 0 5px,
    rgba(var(--ok-rgb), 0.03) 5px 10px
  );
  border-top: 1px dashed rgba(var(--ok-rgb), 0.45);
  border-bottom: 1px dashed rgba(var(--ok-rgb), 0.45);
  pointer-events: none; z-index: 1;
}
/* Etiket DIKEY ve sol olukta: pencerenin icine yatay yazilinca ilk paketlenen
   randevu onu ortuyordu (QA'da goruldu). Oluk her zaman bos, cunku paketlenen
   bloklar 24 pikselden basliyor. */
.gap-label {
  position: absolute; left: 3px; top: 3px; bottom: 3px; width: 15px;
  writing-mode: vertical-rl; text-orientation: mixed;
  font-size: 9px; letter-spacing: 0.09em; text-transform: uppercase;
  font-weight: 600; color: var(--ok-ink); white-space: nowrap; overflow: hidden;
}

/* PAKETLENMIS randevu: bekleme penceresinin ICINDE duruyor. Iceri kacirma
   (left) + kendi golgesi, "bu blok o blogun icinde" demenin standart yolu;
   ust uste binen iki esit blok, isletmeciye cakisma gibi gorunurdu. */
.blk-appt.packed {
  left: 24px; right: 6px; z-index: 4;
  border-left-color: var(--ok);
  background: var(--blk-packed);
  box-shadow: -1px 0 0 rgba(var(--ok-rgb), 0.45), 0 2px 10px -4px rgba(var(--shadow-rgb), 0.8);
}
/* KOLTUK EKSENINDE ICERI KACIRMA YOK (M11).
   `.packed` iceri kacirmasi "bu blok o blogun ICINDE" demek ve personel
   sutununda dogru: paketlenen randevu, ebeveyninin bekleme penceresinin
   icinde duruyor. Koltuk sutununda ise ebeveyn BASKA BIR SUTUNDA — orada
   iceri kacik duran bir blok, olmayan bir ic-ice-likle isaret ederdi.
   Ayni sinif, iki eksende iki farkli gercek; kural burada duzeltiliyor.
   `.packed`ten SONRA tanimli, yani onu eziyor. */
.blk-appt.packed.seat-blk {
  left: 4px; right: 4px;
  box-shadow: 0 2px 10px -4px rgba(var(--shadow-rgb), 0.8);
}

/* Ebeveyni iptal edilmis paketlenmis randevu — kayit KORUNUYOR, uyari cikiyor. */
.blk-appt.orphan { border-left-color: var(--warn); }
.blk-appt.orphan.packed { box-shadow: -1px 0 0 rgba(var(--warn-rgb), 0.6), 0 2px 10px -4px rgba(var(--shadow-rgb), 0.8); }
.orphan-mark {
  display: inline-block; min-width: 15px; text-align: center;
  font-size: 11px; font-weight: 700; line-height: 15px;
  border-radius: var(--radius-pill); color: var(--accent-ink); background: var(--warn);
}
.lg-gap {
  background: repeating-linear-gradient(
    -45deg,
    rgba(var(--ok-rgb), 0.3) 0 4px,
    rgba(var(--ok-rgb), 0.08) 4px 8px
  );
  border: 1px dashed rgba(var(--ok-rgb), 0.5);
}
.lg-packed { background: var(--blk-packed); border: 1px solid var(--line-2); border-left: 3px solid var(--ok); }

/* Randevu diyalogundaki ara sure uyarisi. Iptale BASMADAN once okunmali,
   bu yuzden eylem satirinin ustunde ve renkli. */
.gap-note {
  margin: 0 0 12px; padding: 9px 11px; font-size: 12.5px; line-height: 1.45;
  border-radius: var(--radius); color: var(--ink-2);
  border: 1px solid rgba(var(--ok-rgb), 0.4);
  background: rgba(var(--ok-rgb), 0.09);
  border-left: 3px solid var(--ok);
}
.gap-note strong { color: var(--ink); }
.gap-note.warn {
  border-color: rgba(var(--warn-rgb), 0.45);
  background: rgba(var(--warn-rgb), 0.1);
  border-left-color: var(--warn);
}

/* =========================================================================
   GUN SONU / GELIR OZETI (Dalga 1 #7)

   Dort kart, tek bakista okunacak sekilde: her kartin BIR buyuk sayisi ve
   altinda onu aciklayan kirilim var. Panelin geri kalaniyla ayni token'lar;
   yeni gorsel dil icat edilmedi.
   ========================================================================= */
.sum-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
.sum-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); padding: var(--s6); box-shadow: var(--shadow);
}
.sum-card h3 {
  margin: 0 0 6px; font-family: var(--font-body);
  font-size: 10.5px; letter-spacing: 0.12em; text-transform: uppercase;
  font-weight: 700; color: var(--ink-3);
}
.sum-card .big {
  display: block; font-family: var(--font-display);
  font-size: 34px; font-weight: 600; line-height: 1.05; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.sum-card .big.muted { color: var(--ink-3); }
.sum-card p { margin: 4px 0 10px; }
.sum-card.gap { border-color: rgba(var(--ok-rgb), 0.34); }
.sum-card.gap .big { color: var(--ok); }

.sum-list { list-style: none; margin: 10px 0 0; padding: 0; font-size: 12.5px; }
.sum-list li {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 4px 0; border-top: 1px solid var(--line);
}
.sum-list li span { color: var(--ink-3); }
.sum-list li b { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 600; }
.sum-list li em { color: var(--ink-3); font-style: normal; font-size: 11.5px; }
.sum-list li.warn b { color: var(--warn); }

/* COCUK SATIR (Tur 4C · UI/UX §1.2). Nakit/Kart, "Tahsil edilen"in acilimi;
   kardes satirlarla ayni hizada durunca goz onlari yeni bir kalem saniyordu.
   Girinti + kucuk punto + ust cizginin silinmesi, uc ayri sinyalle ayni
   seyi soyluyor: bu satir bir UST satira ait. Ust cizgiyi silmek ozellikle
   onemli — `.sum-list li`'nin `border-top`u her satiri esit derecede
   "yeni kalem" gibi gosteren sey oydu. */
.sum-list li.sub {
  border-top: 0; padding: 2px 0 2px 14px;
  font-size: 11.5px; position: relative;
}
.sum-list li.sub::before {
  content: ''; position: absolute; left: 4px; top: 0; bottom: 0;
  border-left: 1px solid var(--line);
}
.sum-list li.sub span, .sum-list li.sub b { color: var(--ink-3); font-weight: 500; }

/* TAHMINI CIRO IKINCIL (Tur 4C · UI/UX §1.1 — turun tek YUKSEK bulgusu).
   Gercek ciro adisyondan gelen bir OLGU, tahmini ciro etiketten uretilen
   bir PROJEKSIYON. Ikisi ayni 34px serifte, ayni renkte durunca ekran
   "hangisine guveneyim" sorusunu isletmeciye birakiyordu — ve tahmini
   sayi cogu gun daha buyuk oldugu icin goz once ona gidiyordu.
   Kart KALDIRILMADI (kapsama %100 olmadan tek sayi eksik kalir), yalnizca
   sesi kisildi: punto 34 -> 25, renk `--ink` -> `--ink-2`. */
.sum-card.tahmin .big { font-size: 25px; color: var(--ink-2); font-weight: 500; }
/* Tahmini ciro kartinin SESI KISIK kalmali (Tur 4C karari): gercek ciro bir
   OLGU, tahmini ciro bir PROJEKSIYON. Yeni dilde `background: transparent`
   tek basina yetmiyordu — `.sum-card` artik golge tasiyor ve seffaf zeminli
   bir kart yine "kart gibi" duruyordu (kare `07-raporlar/acik.png`).
   Golge kaldirildi, kenarlik bir kademe belirginlesti: kart hala bir kutu
   ama YUKSELMIYOR. */
.sum-card.tahmin {
  background: transparent;
  box-shadow: none;
  border-color: var(--line-2);
}

/* YAS ROZETI (Tur 4C · UI/UX §1.4) — tarihin YANINDA, yerine degil.
   30 gunu gecen alacak `old` ile uyari rengine geciyor: "9 gun" ile
   "94 gun" ayni sey degil ve tabloyu tarayan gozun ikincisinde durmasi
   lazim. Esik SUNUCUDA degil burada, cunku bu bir GORSEL vurgu; sayinin
   kendisi sunucudan geliyor. */
.age-tag {
  display: inline-block; margin-left: 6px; padding: 1px 6px;
  border-radius: var(--radius-pill); font-size: 11px; font-weight: 600;
  background: rgba(var(--ink-rgb), 0.07); color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.age-tag.old { background: rgba(var(--warn-rgb), 0.14); color: var(--warn); }

/* SISTEM KAYDI ROZETI (Tur 4C · UI/UX §1.3). Silinemez bir satirin
   yanindaki BOSLUK bilgi degil; kilit + sozcuk, sebebi de `title` ile
   tasiyor. Ayni ekranin "Hesap ac" dugmesine zaten uygulanmis olan
   kuralin ("dugmenin yoklugu tek basina bilgi degil") kapora satirindaki
   karsiligi. */
.lock-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--ink-3); cursor: help;
}
.lock-tag svg { width: 13px; height: 13px; flex: none; }

/* Oran cubugu: sayinin yaninda GORSEL bir karsilik. Tek basina "%38"
   bir isletmeci icin soyut; cubuk onu bir bakista bir hisse ceviriyor. */
.meter {
  display: block; height: 5px; border-radius: var(--radius-pill);
  background: rgba(var(--ink-rgb), 0.09); overflow: hidden;
}
.meter > span { display: block; height: 100%; background: var(--ink-3); }
.meter.gold > span { background: var(--accent); }
.meter.green > span { background: var(--ok); }

/* I-025 — GUN EKRANININ DOLULUK CIFTI.
   `.meter` blok bir oge (Gun Sonu kartinda satirin tamamini kapliyor); gun
   ekraninin ust cubugunda tarih ve randevu sayisiyla AYNI satirda durmasi
   gerekiyor, o yuzden burada dar ve satir ici. Ayri bir cubuk bicimi
   YAZILMADI, var olani daraltiyoruz — iki yerde iki cubuk, zamanla iki
   farkli yukseklik demekti. */
#dayDoluluk { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 18px; }
.daymeta .doluluk { display: inline-flex; align-items: center; gap: 6px; }
.daymeta .doluluk .meter { width: 56px; flex: none; }

/* Gun / Son 7 gun secici — ayni hap kabi kalibi. Yapisik kenarlikli
   segment dili (negatif margin, koseleri kirpilmis dugmeler) kalkti:
   yeni dilde secim DOLGUYLA anlatiliyor ve bitisik kenarlik hilesi
   16px kose yaricapinda zaten cirkin bir birlesim veriyordu. */
.seg {
  display: inline-flex; gap: var(--s1);
  background: var(--surface-2); border-radius: var(--radius-pill); padding: 4px;
}
.seg .btn {
  border-radius: var(--radius-pill); background: none; border-color: transparent;
  height: 32px; font-size: 13px; color: var(--ink-2);
}
.seg .btn:hover { background: none; color: var(--ink); }
/* Segment secicisi (gun/hafta/ay) — sekmeyle AYNI kalip, ayni kural.
   Eski fark 1,10; yeni 16,30. */
.seg .btn.on {
  background: var(--accent); color: var(--accent-ink); z-index: 1;
}
.blk-off {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(45deg, var(--hatch2-a) 0 8px, var(--hatch2-b) 8px 16px);
  display: grid; place-items: center; color: var(--ink-3); font-size: 12px;
  letter-spacing: 0.08em; text-transform: uppercase;
}
.now-line { position: absolute; left: 0; right: 0; height: 2px; background: var(--danger); z-index: 3; }
.now-line::before {
  content: ''; position: absolute; left: -3px; top: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--danger);
}

/* kiyas seritleri: sol serit bizim motor (altin, dolu), sag serit DD
   (notr, kesik) — ust ozet kutulariyla ayni renk kodu. */
.lane { position: absolute; top: 0; bottom: 0; }
.lane-ours { left: 4px; width: 46%; }
.lane-dd { right: 4px; width: 46%; }
.tick { position: absolute; left: 0; right: 0; border-radius: 4px; }
/* I-072 — isaret tiklanabilir: walk-in formunu o saat/personel/hizmetle acar.
   Imlec bunu SOYLEMELI; "tiklanabilir ama imleci ok" bir bilmecedir. */
.tick[data-time] { cursor: pointer; }
.tick-ours { background: rgba(var(--accent-rgb), 0.17); border: 1px solid rgba(var(--accent-rgb), 0.55); }
.tick-dd { background: rgba(var(--ink-rgb), 0.04); border: 1px dashed rgba(var(--ink-rgb), 0.26); }
.tick span {
  position: absolute; top: 1px; left: 4px; font-size: 10px;
  font-variant-numeric: tabular-nums; color: var(--ink-2);
}
.tick-ours span { color: var(--accent); font-weight: 600; }

/* ================================================= AY GORUNUMU (M8)
   Yedi sutunlu ızgara. `aspect-ratio` YOK: kutu yuksekligi icerikten
   geliyor, cunku sabit oranli bir kutu 390 pikselde iki satirlik sayiyi
   tasirdi (mobil istemcide GridView'in ayni sebeple reddedilmesiyle
   birebir ayni gerekce). */
.month-grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px;
  margin: 4px 0 14px;
}
.mo-wd {
  font-size: 11px; color: var(--ink-3); text-align: center;
  padding: 4px 0; font-weight: 600; letter-spacing: 0.03em;
}
.mo-pad { border: 0; background: none; }
.mo-cell {
  appearance: none; font: inherit; cursor: pointer; text-align: left;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
  padding: var(--s2); min-height: 64px;
  display: flex; flex-direction: column; justify-content: space-between; gap: 4px;
  transition: border-color var(--dur-1) var(--ease-out);
}
.mo-cell:hover { border-color: var(--line-2); }
.mo-cell:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.mo-day { font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.mo-n {
  font-size: 17px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink);
}
.mo-x { font-size: 11px; color: var(--ink-3); }

/* YOGUNLUK BANTLARI. Zemin ALFA ile biniyor, dolgun renkle degil: dolgun
   zemin bes bant icin bes ayri metin rengi hesaplamak demekti (takvim
   renk kodunun, S7, birebir ayni karari). Metin rengi degismedigi icin
   kontrast her bantta ayni ve olculebilir kaliyor. */
.mo-b0 { background: var(--surface); }
.mo-b1 { background: rgba(var(--accent-rgb), 0.12); border-color: rgba(var(--accent-rgb), 0.25); }
.mo-b2 { background: rgba(var(--accent-rgb), 0.26); border-color: rgba(var(--accent-rgb), 0.42); }
.mo-b3 { background: rgba(var(--accent-rgb), 0.42); border-color: rgba(var(--accent-rgb), 0.6); }
.mo-b4 { background: rgba(var(--accent-rgb), 0.6); border-color: var(--accent); }
/* KAPALI GUN RENK DEGIL DESEN. Doluluk skalasinin icine konsaydi "cok
   bos gecmis bir gun" gibi okunurdu; oysa olcu disi. Molanin takvimde
   dokuyla isaretlenmesiyle ayni karar. */
.mo-closed {
  background: repeating-linear-gradient(45deg, var(--hatch-a) 0 5px, var(--hatch-b) 5px 10px);
  color: var(--ink-3); border-style: dashed;
}
/* BUGUN: renk degil CERCEVE. Bugunun rengi doluluk tasiyor ve onu
   ezmek, bugunun ne kadar dolu oldugunu gizlemek olurdu. */
.mo-today { box-shadow: inset 0 0 0 2px var(--accent); }
.mo-key {
  display: inline-block; width: 14px; height: 10px; border-radius: 4px;
  margin-right: 6px; vertical-align: -1px; border: 1px solid var(--line-2);
}
.month-title { font-size: 15px; min-width: 9.5em; text-align: center; }

/* ============================================ SAAT HARITASI (Ç1+Ç5, Faz 3)
   Hafta gunu x saat bandi izgarasi. YENI TOKEN YOK, YENI RENK RAMPASI YOK:
   hucreler ustteki `.mo-cell` + `.mo-b0..mo-b4` sinifiarini AYNEN tasiyor.
   Ikinci bir rampa acmak, ayni dolulugun iki ekranda iki farkli renkle
   gorunmesi demekti — bandi sunucunun atmasiyla (S7) ayni gerekce.

   `.hm-cell` ZEMIN VE KENAR RENGI YAZMIYOR: o degerler band sinifindan
   geliyor. Yazsaydi bu blok dosyada `.mo-b*`ten SONRA durdugu icin rampayi
   sessizce ezer ve butun izgara tek renk cikardi. */
/* 390 PIKSELDE YEDI SUTUN DA SIGIYOR — olculdu ve DUZELTILDI. Ilk yazimda
   sutun tabani 44px'ti ve dar ekranda Cmt/Paz kesiliyordu: yatay kaydirilan
   bir izgarada kesilen sutun, kullanicinin varligini bilmedigi sutundur
   ("Cumartesi doluluğu" tam da bu ekranin en cok bakilan sutunu).
   `overflow-x` yine de duruyor: daha dar bir cihazda kesilmek, tasmaktan
   iyidir. */
.hm-wrap { overflow-x: auto; }
.hm-grid {
  display: grid;
  grid-template-columns: auto repeat(7, minmax(30px, 1fr));
  gap: var(--s1);
  margin: var(--s1) 0 var(--s3);
  min-width: 320px;
}
.hm-hour {
  font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums;
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: var(--s2); white-space: nowrap;
}
/* Yukseklik ay gorunumunden KUCUK: orada bir kutuda iki satir sayi var,
   burada hicbir metin yok ve 10-12 satirlik izgara ekrana sigmali. */
.hm-cell { min-height: 30px; padding: 0; }
/* AZ VERI — UCUNCU DURUM, dolulugun bir tonu DEGIL. Ozgullugu (0,2,0)
   band sinifini (0,1,0) bilerek yeniyor: bir hucre hem "az veri" hem
   "yogun" olamaz, ve ikisi carpisirsa dogru cevap az veridir. */
.hm-az,
.hm-cell.hm-az {
  background: var(--surface-2);
  border: 1px dashed var(--line-field);
}
/* Secili bant: renk degil CERCEVE (`.mo-today` ile ayni karar) — secim
   dolulugu ezmemeli. */
.hm-cell[aria-pressed='true'] { box-shadow: inset 0 0 0 2px var(--accent); }
.hm-detay { color: var(--ink-2); min-height: 1.5em; margin: var(--s2) 2px; }
.hm-eylem {
  display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center;
  margin-top: var(--s3);
}
.hm-eylem p { flex: 1 1 100%; margin: 0 0 var(--s1); color: var(--ink-2); }

/* `hidden` NITELIGI YAZAR `display` KURALINDAN ZAYIFTIR ve bu satir onu
   geri kazandiriyor. Kural M11 icin (eksene gore degisen efsane) eklendi
   ama VAR OLAN BIR KUSURU da kapatiyor: `#calColorLegend` `hidden` ile
   gelip `display:flex` yuzunden yine de kutu uretiyordu — renk kodu
   kapaliyken takvimin altinda ~24 piksellik sebepsiz bir bosluk vardi.
   Icerigi bos oldugu icin kimse gormemis, olcen de olmamis. */
.legend[hidden] { display: none; }
.legend {
  display: flex; gap: 18px; align-items: center; font-size: 12px;
  color: var(--ink-3); margin: 12px 2px; flex-wrap: wrap;
}
/* Koltuk ekseninin efsanesindeki aciklama cumlesi — renk kutucugu degil
   metin, o yuzden kendi satirini alabiliyor. */
.axis-note { flex: 1 1 100%; color: var(--ink-3); line-height: 1.5; }
.axis-note strong { color: var(--ink-2); font-weight: 600; }
.lg { display: inline-block; width: 14px; height: 10px; border-radius: 4px; margin-right: 6px; vertical-align: -1px; }
.lg-appt { background: var(--surface); border: 1px solid var(--line-2); border-left: 3px solid var(--accent); }
.lg-break { background: repeating-linear-gradient(45deg, var(--hatch-a) 0 4px, var(--hatch-b) 4px 8px); border: 1px dashed var(--line); }
.lg-ours { background: rgba(var(--accent-rgb), 0.2); border: 1px solid rgba(var(--accent-rgb), 0.6); }
.lg-dd { background: rgba(var(--ink-rgb), 0.04); border: 1px dashed rgba(var(--ink-rgb), 0.3); }

.closed-note {
  padding: 44px 20px; text-align: center; color: var(--ink-3);
  background: repeating-linear-gradient(45deg, var(--hatch2-a) 0 10px, var(--hatch2-b) 10px 20px);
}

/* ------------------------------------------------------------- tablolar */

/* TABLO (spec §7.2). Tablo tek bir 24px kartin icinde yasiyor; kart dikey
   8px, yatay 0 dolgu tasiyor ki satirlar kartin kenarina kadar gitsin ve
   satir arasi cizgiler kesilmesin. */
.table-wrap {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); overflow: auto; box-shadow: var(--shadow);
  padding: var(--s2) 0;
}
.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
/* Sutun basligi = ISLEV kalibi (12/600/buyuk harf/+0,05em), satir
   yuksekligi 40, altinda 1px `line-2`. */
.tbl th {
  text-align: left; font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--ink-3); padding: 0 var(--s4); height: 40px;
  border-bottom: 1px solid var(--line-2);
  white-space: nowrap; position: sticky; top: 0; background: var(--surface); font-weight: 600;
}
/* Veri satiri 52px (spec §7.2), hucre yatay dolgu 16. */
.tbl td { padding: var(--s3) var(--s4); border-bottom: 1px solid var(--line); vertical-align: middle; }
.tbl tbody tr { transition: background-color var(--dur-1) var(--ease-out); }
.tbl tbody tr:hover { background: var(--surface-2); }
.tbl tbody tr td { height: 52px; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl tr.cancelled td { color: var(--ink-3); text-decoration: line-through; }
.tbl.compact th, .tbl.compact td { padding: var(--s2) var(--s3); font-size: 13px; }
.tbl.compact tbody tr td { height: 44px; }
.tbl .num { font-variant-numeric: tabular-nums; }
/* PARA SUTUNU SAGA HIZALI (Tur 3 — UI/UX'in para ekrani kurali 1).
   Sola hizali tutarlar farkli hane sayilarinda birbirini tutmuyor ve
   "hangisi buyuk" sorusu okumadan cevaplanamiyor; sag hizalama +
   `tabular-nums` basamaklari alt alta getiriyor. Yalniz PARA sutunlari:
   adet ve tarih sayilari sola hizali kaliyor cunku onlar karsilastirma
   degil kimlik bilgisi. */
.tbl .money, .tbl th.money { text-align: right; font-variant-numeric: tabular-nums; }
/* DURUM HAPI (spec §7.1): renkli nokta degil hap cip — 999px kose,
   4/10 dolgu, 12/600 buyuk harf +0,05em, zemin durum renginin YUMUSAK
   karsiligi, metin durum renginin kendisi.

   ZEMIN ARTIK ISIMLI TOKEN, `rgba(...,.12)` TINTI DEGIL. Olculdu:
   `--warn` kendi %12 tintinde 4,25 (AA alti), spec'in verdigi
   `--warn-soft` (#FFFBEB) uzerinde 4,84. Kenarlik kalkti — dolgulu bir
   hapin ayrica cerceveye ihtiyaci yok ve 999px kosede ince kenarlik
   tirtikli goruunuyordu. */
.pill {
  display: inline-block; padding: 4px 10px; border-radius: var(--radius-pill);
  font-size: 12px; line-height: 16px;
  font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
  background: var(--surface-2); color: var(--ink-2); border: 0;
}
.pill.active { background: var(--ok-soft); color: var(--ok); }
.pill.cancelled { background: var(--danger-soft); color: var(--danger); }
/* `warn` varyanti panelde IKI YERDE zaten kullaniliyordu (koltuk tablosunun
   "pasif" rozeti, Tur 4) ama TANIMLI DEGILDI: nötr `.pill`e dusuyor, yani
   "aktif" ile "pasif" ayni griyi tasiyordu. Tur 5'te kritik stok rozeti
   ayni sinifi isteyince ortaya cikti. Renk uydurulmadi — `--warn` token'i
   zaten var ve `.pill.cancelled`in `--danger` ile kurdugu desenin aynisi.
   UC AYRI SEVIYE, UC AYRI RENK: kritik stok `warn` (siparis ver), biten/eksi
   stok `cancelled` (satma / sayim yanlis), normal `.pill` (bilgi). */
.pill.warn { background: var(--warn-soft); color: var(--warn); }
.pill.walkin { background: rgba(var(--walkin-rgb), 0.1); color: var(--walkin-ink); }
/* I-111 — RANDEVU LISTESININ "Kaynak" HUCRESI BUYUK HARFE CEVRILMIYOR.
   Belge `lang="tr"` oldugu icin tarayici `text-transform: uppercase`i
   Turkce haritayla uyguluyor: `i` -> `İ`. Dogru davranis Turkce metinde;
   ama bu hucrenin degerleri marka/kanal adlari ("Walk-in", "Online") ve
   onlar Turkce sozcuk degil — ekranda "WALK-İN" / "ONLİNE" cikiyordu.
   Yalniz BU hucre muaf: rozet ailesinin geri kalani (durum, stok, kuyruk)
   Turkce ve buyuk harf onlarda dogru. Yeni bir ham deger eklenmedi. */
.pill.kaynak-rozet { text-transform: none; }
.pill.demo { background: rgba(var(--demo-rgb), 0.1); color: var(--demo-ink); }
.wa {
  color: var(--ok); text-decoration: none; font-weight: 600; font-size: 13px;
  white-space: nowrap; border-bottom: 1px solid transparent;
}
.wa:hover { border-bottom-color: currentColor; }

/* --------------------------------------------------------------- kartlar */

.cols { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(330px, 1fr)); align-items: start; }

/* KATLAMA SONRASI DUZEN (Tur 2). Izgara satirlari hizaladigi icin, kartlarin
   boyu birbirinden cok farkli oldugunda son satirda buyuk bir bosluk kaliyor.
   Saatler katlaninca "Çalışma saatleri" 180 pikselluk bir kart oldu ve
   "Online randevu kuralları" tek basina ikinci satira dustu: ekranin sag ust
   ucte biri BOSALDI ve sayfa yarim yuklenmis gibi duruyordu (olculdu, QA
   kare 01).

   Cozum sutun akisi: kartlar satir satir degil SUTUN SUTUN diziliyor ve
   tarayici yuksekligi kendisi dengeliyor. Okuma sirasi sutun-onceli oluyor —
   birbirinden bagimsiz ayar kartlari icin dogru takas; bunlar bir anlati
   degil, dort ayri kapi.
   ⚠ KURALLAR PANELI BU KURALDAN CIKTI (U2): o ekran artik `.cols` izgarasi
   degil, tek seviyeli bir baslik listesi + tam ekran devralma (dosyanin
   sonundaki "U2" blogu). Secici burada birakilsaydi, hicbir seyi
   secmeyen olu bir kural olurdu. */
.panel[data-panel='data'] .cols {
  display: block;
  columns: 330px 3;
  column-gap: 16px;
}
.panel[data-panel='data'] .cols > .card {
  break-inside: avoid;
  margin: 0 0 16px;
}
/* KART (spec §5/§6): 24px kose, 24px ic dolgu, `surface` zemin, 1px
   `line` kenarlik + TEK golge kademesi. Kartla zemin arasindaki fark
   yalnizca 1,05 oldugu icin ayrimi golge + kenarlik BIRLIKTE tasiyor;
   ikisinden biri kalkarsa kart zeminde kayboluyor. */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero);
  padding: var(--s6); box-shadow: var(--shadow);
}
.card > .muted { margin-top: 0; }
.inline-form {
  display: flex; gap: 6px; flex-wrap: wrap; margin-top: 12px;
  padding-top: 12px; border-top: 1px solid var(--line);
}
.inline-form input, .inline-form select { flex: 1 1 auto; min-width: 90px; }
/* Saat alanlari icerigi kadar yer kaplasin — aksi halde 4 kontrollu mola
   formunda ikinci saat tek basina alt satira dusuyordu. */
.inline-form input[type='time'] { flex: 0 1 104px; min-width: 104px; }
/* SUTUNLAR KUCULEBILIR OLMALI (olculdu: sw 393 / cw 339 — 54 piksel tasma).
   Bu kart uc sutunlu bir `columns` duzeninin icinde yasiyor ve sutun 339
   piksel; sabit 96+78 + iki `1fr` saat alani oraya sigmiyordu. `1fr`
   varsayilan olarak icerigin en kucuk boyutunun ALTINA inmez ve saat
   alaninin kendi asgari genisligi var — yani `1fr` yazmak "sigdir"
   demek degil. `minmax(0, 1fr)` + alanin `min-width: 0`i birlikte
   gercekten kuculuyor.
   Yatay dolgu 12 -> 8: dar alanda "10:00" metni kirpilmadan sigsin.
   Tasma sayfaya cikmiyordu (kart `overflow` kirpiyordu), yani ekranda
   "biraz dar" gorunuyor ama yanlis gorunmuyordu — olcumle bulundu. */
.hours-row {
  display: grid;
  grid-template-columns: minmax(0, 76px) minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 6px;
  align-items: center; margin-bottom: var(--s2);
}
/* Yatay dolgu 6px: saat alaninin icinde "10:00" METNI ve native saat
   simgesi yan yana duruyor. 8px dolguda deger simgenin altinda
   kirpiliyordu ("10:0C" gibi okunuyordu — kare
   `08-isletme/acik-saatler.png` ilk cekimi). Simge GIZLENMEDI: onu
   kaldirmak native secicinin tek acilis yolunu da kaldiriyor. */
.hours-row input[type='time'] { min-width: 0; width: 100%; padding: 0 6px; }
.hours-row .dayname { font-size: 13px; color: var(--ink-2); }
.hours-row.is-closed .dayname { color: var(--ink-3); }
.hours-row.is-closed input[type='time'] { opacity: 0.35; }
.hours-row label.small { color: var(--ink-3); cursor: pointer; }
.ok-msg { color: var(--ok); font-size: 13px; margin-left: 10px; }
.stats { display: grid; gap: 10px; grid-template-columns: repeat(3, 1fr); }
.stat {
  border: 0; border-radius: var(--radius);
  padding: var(--s4) var(--s3); text-align: center; background: var(--surface-2);
}
.stat b {
  display: block; font-family: var(--font-display); font-size: 27px;
  font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums;
  color: var(--accent);
}
.stat span {
  display: block; margin-top: 5px; font-size: 10.5px; color: var(--ink-3);
  letter-spacing: 0.09em; text-transform: uppercase; font-weight: 600;
}

/* -------------------------------------------------------------- dialog */

/* DIALOG = alt sayfa (bottom sheet) kalibi, 24px kose (spec §2). */
dialog {
  border: 1px solid var(--line); border-radius: var(--radius-hero); padding: var(--s6);
  width: min(560px, 94vw); background: var(--surface); color: var(--ink);
  box-shadow: 0 24px 60px -12px rgba(var(--shadow-rgb), 0.18), var(--shadow);
}
dialog::backdrop { background: var(--backdrop); }
/* Alan etiketi ISLEV kalibinda ve alandan 8px yukarida (spec §7.3).
   Yer tutucu etiket yerine gecmiyor. */
dialog label {
  display: block; font-size: 12px; font-weight: 600; color: var(--ink-3);
  margin-bottom: var(--s4); letter-spacing: 0.05em; text-transform: uppercase;
}
dialog input, dialog select { width: 100%; margin-top: var(--s2); font-weight: 500; }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s3); }

.toast {
  position: fixed; bottom: var(--s6); left: 50%; transform: translateX(-50%);
  background: var(--hero); color: var(--hero-ink); border: 0;
  padding: var(--s3) var(--s5); border-radius: var(--radius-pill);
  font-size: 14px; font-weight: 500; z-index: 60;
  box-shadow: 0 12px 32px -8px rgba(var(--shadow-rgb), 0.28), var(--shadow);
}
/* Hata bildirimi: hapin tamami durum rengine donuyor. Eski surumde sol
   kenar cizgisiydi; 999px kosede sol kenar cizgisi bir yay olarak
   kirpiliyor ve kaza gibi duruyordu.

   Metin rengi sabit beyaz DEGIL `--accent-ink`: acik temada `--danger`
   koyu bir kirmizi (beyaz metin 6,28 ✓), koyu temada acik bir mercan
   (`#FB7185`) ve orada beyaz metin 1,9'a duserdi. `--accent-ink` iki
   temada da "dolu bir yuzeyin uzerindeki metin" anlamini tasiyor. */
.toast.bad { background: var(--danger); color: var(--accent-ink); }

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; }
}

/* DIZUSTU ARALIGI. On sekme + cok kiracili oturumda gorunen kiraci secici,
   1440 pikselde seridi 46 piksel tasiriyordu (olculdu). Yatay dolguyu
   12 -> 8 piksele indirmek on dugmede ~80 piksel geri kazandiriyor ve 1440
   TAM sigiyor. 1366 ve altinda serit hala kayiyor — orada kenar solmasi
   devrede, cunku etiketleri daha da kisaltmak (ornegin "Saatler") bir
   masaustu aracinda anlam kaybi olurdu. */
@media (min-width: 721px) and (max-width: 1500px) {
  .tabs button { padding: 8px 8px; }
}

@media (max-width: 720px) {
  .top {
    gap: 8px;
    padding: 6px 10px;
    height: auto;
    min-height: 54px;
    flex-wrap: wrap;
  }
  .brand .mark { width: 88px; }
  /* 390px'te kiraci adi seridi asagi itmesin: kirpma sarmadan once gelir. */
  .brand .tenant-name { font-size: 15px; max-width: 140px; }
  .tabs { flex: 1; justify-content: flex-end; }
  .tabs button { padding: 7px 7px; font-size: 12.5px; white-space: nowrap; }
  .panel { padding: 12px 10px 32px; }
  .stats { grid-template-columns: 1fr; }
  .cmp-summary { margin-left: 0; width: 100%; gap: 8px; }
  .cmp-metric { flex: 1; min-width: 0; padding: 6px 10px; }
  .cmp-metric b { font-size: 22px; }
  /* 390px'te dort kutu yan yana sigmaz: kazanim kutusu alt satira,
     tam genislikte gecer (kirpilmis bir sayi hicbir sey anlatmaz). */
  .cmp-summary.with-gap { grid-template-columns: 1fr auto 1fr; }
  .cmp-summary.with-gap .cmp-metric.gap { grid-column: 1 / -1; }
}

/* =========================================================================
   ISLETMELER + ONBOARDING (cok-kiracililik, Dalga 1 #1-#2)

   Panelin geri kalaniyla ayni token'lar; yeni gorsel dil icat edilmedi.
   `.btn.small` burada tanimli cunku mevcut `.tiny` bu satirlar icin fazla
   kucuk kaliyordu (dokunma hedefi).
   ========================================================================= */

.btn.small { padding: 6px 11px; font-size: 13px; }

.tenant-list { display: grid; gap: 10px; min-height: 60px; }

/* ==== ACIK PALETTE UC HEX CAKISMASI (spec Addendum-3) ====================
   `accentSoft` == `surface2` == `line` (#F1F5F9) ve `line2` == `surface3`
   (#E2E8F0). Iki sonucu var ve IKISI DE YALNIZ GUNDUZ MODUNDA cikiyor
   (koyu palette bu ciftlerin degerleri ayri):

   1) `surface2` dolgulu bir blogun `line` kenarligi KENDI DOLGUSUYLA AYNI
      HEX — olculen kontrast 1,00, yani kenarlik hic boyanmiyor. Bu blok
      ailesinin tamami (kiraci, oturum, bekleme, kiyas, zincir, mesaj)
      ayni kusuru tasiyordu.
   2) "Secili = accentSoft / secili degil = surface2" kalibinda iki durum
      BIREBIR AYNI (1,00). `.tenant-row.on` ve `.wl-row.on` tam olarak bu
      kalipti: durumu tasiyan tek sey 1px'lik bir cerceve rengiydi.

   COZUM (Addendum-3 baglayici kurali): secili durum ARTIK DOLGU tasiyor —
   `accent` + `accentInk`, spec §1.5. Taban kenarlik `line2`ye alindi ki
   kendi dolgusuyla ayni hex OLMASIN; blogun kenarini zaten dolgunun beyaz
   karta karsi 1,10'u ciziyor, kenarlik dekoratif (spec §1.1 line'i boyle
   tanimliyor). ETKILESIMLI sinir bunun DISINDA: form alanlari `lineField`
   kullanir (spec §7.3) — asagida `.cust-form`.
   ========================================================================= */
.tenant-row {
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: 12px 14px;
  background: var(--surface-2);
}
/* TEK ISTISNA — VE DOLGUYU DENEYIP KAREYE BAKTIKTAN SONRA VERILDI.
   Bu aile bir KART: icinde kendi dugmeleri (`Randevu sayfasi`, hayalet
   `Veriyi indir`), kendi `.tag` rozeti ve `muted` sube satiri var. `accent`
   dolgu denendi ve kare cekildi: sube satiri antrasit uzerinde okunmuyor
   (`ink-2` #475569 / #2D2D2D = 1,30), hayalet dugme kayboluyor, `.tag`
   bos bir seride donusuyor. Bes ogeyi tek tek ters renge cevirmek, bir
   kartin icine ikinci bir tema kurmak olurdu.

   Durum sinyali bu yuzden DOLGU degil 2px `accent` HALKA. Addendum-3'un
   yasakladigi sey "iki esit hex"e dayanan bir durum farkiydi; halka kendi
   dolgusuna karsi 12,57 (acik) / 12,98 (koyu) olculuyor — 1.4.11'in durum
   gostergesi icin istedigi 3:1'in cok ustunde. Kompakt kontrollerde
   (sekme, segment, eksen, musteri/bekleme satiri) kural degismedi: dolgu. */
.tenant-row.on {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 2px var(--accent);
}
.tenant-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.tenant-head code { font-size: 12px; }
.tenant-row .btn-row { margin-top: 10px; }

/* ACIK OTURUMLAR. Kaburga `tenant-row` ile ayni bilerek: ikisi de isletmeci
   yuzeyi, ayni serit uzerinde yan yana duruyorlar ve iki farkli kart dili
   kullanmak paneli iki ayri urun gibi gosterirdi. Ayrilan tek sey zaman
   satirlari: ucu de etiket + deger ve rakamlar tabular. */
.session-list { display: grid; gap: 10px; min-height: 60px; }
/* Kenarlik `line` -> `line2`: yukaridaki cakisma blogu, madde 1. */
.session-row {
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: 12px 14px;
  background: var(--surface-2);
}
/* Sunucu suresi gecmis satiri zaten listelemiyor (`listSessions` filtreliyor);
   bu kural savunma amacli — jeton omru bir gun uzatilirsa ekran sessizce
   yanlis okunmasin. */
.session-row.is-expired { opacity: 0.6; }
.session-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.session-head strong { font-size: 14.5px; }
/* MASKELI NUMARA. Tabular rakam: alt alta duran satirlarda maskelerin
   hizalanmasi, hangi kismin gizlendigini tek bakista okutuyor. */
.session-phone {
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.session-scope { color: var(--ink-3); margin-top: 2px; }
/* Isletmeci kapsami rozetle degil RENKLE isaretleniyor: satirin kendisi
   zaten "İşletmeci · tüm işletmeler" diyor, rozet o cumleyi tekrar ederdi. */
.session-scope.is-operator { color: var(--accent); }
.session-times {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));
  gap: 3px 16px;
  margin: 10px 0 0;
}
.session-times > div { display: flex; gap: 8px; align-items: baseline; }
/* Etiket SABIT genislik (mobildeki `SizedBox(width: 84)` ile ayni sayi):
   `min-width` iken "Son görülme" kendi sutununu genisletiyor ve uc zaman
   satirinin degerleri birbirini tutmuyordu — ayni bicimdeki uc damga
   uc farkli yerden basliyorsa goz onlari kiyaslayamaz. */
.session-times dt { color: var(--ink-3); font-size: 12px; flex: 0 0 84px; }
.session-times dd {
  margin: 0; color: var(--ink-2); font-size: 13px; font-variant-numeric: tabular-nums;
}
.session-row .btn-row { margin-top: 10px; }

.tag {
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent-deep);
  border-radius: var(--radius-pill);
  padding: 1px 8px;
}

.onb-set {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px 14px;
  margin: 14px 0 0;
  /* `min-width: 0` — `<fieldset>`in UA kurali `min-inline-size: min-content`
     ve bu, ogenin kabindan DAR olmasini engelliyor: 332 px'lik kabinda
     fieldset 334 px kaliyor ve 2 px yatay tasma doguyor. Baska hicbir
     kutuda gorulmuyor cunku bu ozel kural yalnizca fieldset'te var.

     OLCULDU, TAHMIN EDILMEDI: once `.onb-hrow`un ciplak `1fr`i suclandi
     (dosyanin kendi izgara notu tam bu tuzagi anlatiyor), degistirildi ve
     tasma DEGISMEDI — degisiklik geri alindi. Tasan cocuk olculunce
     fieldset'in kendisi cikti (kap 332, cocuk 334, fark tam 2 = iki kenar).

     NIYE BUGUNE KADAR GORULMEDI: butun-urun basitlik supurmesi 1440x900'de
     kosuyor; bu tasma yalnizca dar ekranda doguyor. Karne sonrasi pakette
     Isletmeler ekrani 390'da da olculunce ortaya cikti (390 px: tasan oge
     1 -> 0). Katlamadan ONCE de vardi, yalnizca `#onbForm` uzerinde
     raporlaniyordu. */
  min-width: 0;
}
.onb-set legend {
  padding: 0 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.onb-set > .btn { margin-top: 10px; }

/* Izgara sutunlari `1fr` DEGIL `minmax(0, 1fr)`: cIplak `1fr` = `minmax(auto,
   1fr)` ve `auto` tabani izgara ogesinin MIN-CONTENT'i, yani bir `<input>` icin
   tarayicinin varsayilan ~175px'lik icsel genisligi. Iki sutunlu `.cols`
   duzeninde kart 486px kaliyor ve satir 532px'e sisip sekmeyi 1024'te yatay
   tasitiyordu (Tur 2 entegrasyon olcumu, Isletmeler sekmesi). Ogenin kendi
   `min-width:auto` tabani da ayni sekilde kaldirilmali, yoksa track daralsa
   bile oge tasmaya devam eder. Iki alt kuraldaki `.onb-gaprow` bu deseni
   zaten kullaniyordu. */
.onb-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  gap: 8px;
  align-items: center;
  margin-bottom: 8px;
}
.onb-row > * { min-width: 0; }
.onb-row[data-kind='service'] { grid-template-columns: minmax(0, 1fr) 80px minmax(0, 1fr) auto; }
.onb-row[data-kind='staff'] { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto auto; }
/* Sube satiri M-5 ile UC alan tasiyor (ad · adres · cep telefonu).
   Numara sutunu SABIT: numara hicbir zaman uzamiyor, ad ve adres uzuyor.
   Ad sutunu 1,2fr — OLCULDU, tahmin degil: yer tutucu "Şube adı (örn.
   Merkez)" 14px Plus Jakarta'da 147px ve esit paylasimda alana 136px ic
   genislik dusuyordu, yani ucuncu alani ekleyince YER TUTUCU KIRPILIYORDU
   (kare kaniti: `panel-sube-telefon-1440.png` ilk cekimi). 1,2/1/128 ile
   1440'ta ucu de tam: 153 / 123 / 104 ic genislik. */
.onb-row[data-kind='branch'] { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) 128px auto; }
/* Silme dugmesi olmayan ilk satirda izgara kaymasin diye ayni genislikte
   bos bir hucre duruyor (aksi halde ilk satir digerlerinden genis olurdu). */
.onb-del-space { width: 32px; }

/* ARA SURE alanlari: varsayilan KAPALI, kutu isaretlenince aciliyor.
   `hidden` niteligi yerine sinif + `display:none`: bu projede `display:grid`
   tasiyan kapsayicilar `hidden`'i iki kez ezmisti (paket 1 notu). */
.onb-row-wrap { margin-bottom: 10px; }
.onb-row-wrap .onb-row { margin-bottom: 4px; }
/* `.onb-check` bu dosyada DAHA SONRA tanimli ve `white-space:nowrap` tasiyor;
   tek sinifla ezmeye calismak sessizce basarisiz oluyordu (390px'te satir
   kirilmiyor, sekme yatay tasiyordu — QA olcumunde yakalandi). */
.onb-check.gap-toggle {
  font-size: 12px; color: var(--ink-3); margin-bottom: 4px;
  white-space: normal; align-items: flex-start;
}
.onb-check.gap-toggle input { margin-top: 2px; }
.onb-gaprow { display: none; }
.onb-row-wrap.gap-on .onb-gaprow {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
  gap: 8px; align-items: end;
  padding: 8px 10px; margin-bottom: 6px;
  border-radius: var(--radius);
  border: 1px solid rgba(var(--ok-rgb), 0.34);
  background: rgba(var(--ok-rgb), 0.07);
}
.onb-gaprow label { font-size: 12px; color: var(--ink-3); display: grid; gap: 3px; }
.onb-gaprow .s-total { align-self: center; white-space: nowrap; color: var(--ok); }
.onb-row-wrap.gap-on .s-dur { opacity: 0.45; }

@media (max-width: 640px) {
  .onb-row-wrap.gap-on .onb-gaprow { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .onb-gaprow .s-total { grid-column: 1 / -1; }
}

.onb-check {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ink-2);
  white-space: nowrap;
}
.onb-check input { width: auto; }

/* BEKLEME KAYIT FORMU — "Gün fark etmez" TAM SATIR (kucuk paket 2026-08-28).
   Onay kutusu kendi hizasindaki `Gün` alanini GIZLIYOR; iki sutunun birinde
   durursa gizlenince yaninda bir bosluk kalir ve satir yamalik gorunur. Tam
   satira almak hem o boslugu kaldiriyor hem "bu kutu asagidakini kapatir"
   iliskisini gosteriyor. `.onb-hrow > .onb-check` ile ayni desen.

   ⚠ KURAL TABAN `.onb-check`TEN SONRA DURMAK ZORUNDA. Yalnizca cascade
   yuzunden degil: `para-ekrani-yerlesimi.test.js` taban kurali
   `/\.onb-check \{/` ile ILK ESLESMEDEN okuyor. Kural yukariya konunca o
   test taban yerine BU kurali okudu ve `npm test` kirmizi verdi (olculdu,
   2026-08-28). Test gevsetilmedi; kural dogru yerine tasindi. */
.two.wl-gun > .onb-check { grid-column: 1 / -1; }

/* HIZMET SECIM LISTESI (`#polServices`) — TASMA SAHIPSIZ KALMISTI.
   Tur 4A'nin gorsel turu bu yuzeyde 10 (1440) / 21 (390) tasan eleman
   olctu ve `git stash` ile kanitladi ki tasma o paketten gelmiyor: panelin
   `rules` bolumu daha once HIC olculmemisti. Sahibi yoktu; Tur 4C
   sahipleniyor.
   Sebep: kutunun kendisi hic duzenlenmemisti (cıplak bir <div>, icinde
   `inline-flex` + `nowrap` etiketler) — yani her etiket kendi genisligini
   dayatiyordu ve kiracinin uzun hizmet adi karti tasiriyordu.
   Cozum bir izgara: her etiket bir hucre, hucre daralabilir, metin
   kirilabilir. `nowrap` yalnizca BURADA eziliyor.

   ⚠ U3'TE IKINCI LISTE DE KAPSAMA ALINDI. `#polSeatlessServices` ayni sekilde
   uretiliyor (hizmet basina bir `.onb-check`) ama bu duzeltme yazildiginda
   BASKA BIR KARTIN icindeydi ve kapsama girmemisti — yani ayni tasma orada
   hâlâ duruyordu, yalnizca kimse bakmiyordu. U3 koltuk kartini cekince iki
   liste AYNI bolumde yan yana geldi ve fark karede goruldu: biri izgara,
   oteki tek satirlik `nowrap` dizisi. Ayni sey ayni gorunmeli. */
#polServices,
#polSeatlessServices {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 4px 14px;
  margin-top: 6px;
}
#polServices .onb-check,
#polSeatlessServices .onb-check {
  white-space: normal;
  align-items: start;
  min-width: 0;
}
#polServices .onb-check > span,
#polSeatlessServices .onb-check > span { min-width: 0; overflow-wrap: anywhere; }
#polServices .onb-check input { margin-top: 2px; flex: none; }

.onb-hours { display: grid; gap: 6px; }
.onb-hrow {
  display: grid;
  grid-template-columns: 1fr 120px 120px;
  gap: 8px;
  align-items: center;
}

/* GORUNUM ADIMI (D8) — sihirbazin yedinci adimi.
   =========================================================================
   Iki kademe tek ekranda: sablon karti (Aydinlik 4 / Koyu 2), secilince
   kartin ICINDE uc ton dairesi.

   BU DOSYADA TEK BIR HAM RENK DEGERI YOK (VISION.md S3). Ton rengi
   `--ton-renk`, kartin vurgusu `--gorunum-vurgu` olarak SATIR ICI `style`
   ile geliyor — degerin kaynagi `admin.js`teki sablon katalogu, o da
   `scripts/vitrin-uretec/tonlar.mjs`ten olculerek kopyalanmis
   (`server/test/sablon-secimi.test.js`). Panelin kendi paleti degismiyor.

   ONIZLEME KARESI ICIN YER AYRILMADI — bilerek. Gercek gorseller sablon
   kiracida render edildikten sonra uretilecek; simdi bos/sahte bir kare
   koymak, olmayan bir seyi varmis gibi gostermek olurdu. */
.gorunum-grup + .gorunum-grup { margin-top: var(--s4); }
.gorunum-grup-ad {
  margin: 0 0 var(--s2);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-2);
}
/* `minmax(0, 1fr)` — bu dosyanin `.onb-row` izgara notundaki ayni kural:
   ciplak `1fr` kart metnini min-content'e zorlar ve dar kapta tasitir. */
.gorunum-kartlar {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s2);
}
.gorunum-kart {
  /* Secili degilken vurgu YOK: sablonun rengi ancak secildikten sonra
     goruluyor — plan §4 "secilince kartin vurgusu ANINDA degisir". */
  --gorunum-vurgu: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--surface);
  min-width: 0;
}
.gorunum-kart.is-secili {
  border-color: var(--gorunum-vurgu);
  /* Vurgu SOL KENARDA opak bir kanal olarak duruyor; renk metnin altindan
     gecmiyor. Takvim renk kodunun (bu dosya §"TAKVIM RENK KODU PALETI")
     ayni karari: sekiz — burada on sekiz — renk icin ayri metin rengi
     hesaplamak yerine tasiyici kanal. Secim TEK BASINA renge de bagli
     degil (1.4.1): radyo dugmesi zaten isaretli. */
  box-shadow: inset 3px 0 0 var(--gorunum-vurgu);
}
.gorunum-kart-ust {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s2);
  align-items: start;
  padding: var(--s3);
  margin: 0;
  cursor: pointer;
}
.gorunum-kart-ust input { width: auto; margin: 2px 0 0; }
.gorunum-kart-metin { display: grid; gap: 2px; min-width: 0; }
.gorunum-ad { font-weight: 600; color: var(--ink); }
.gorunum-ozet { display: block; }

/* Ton satiri HER kartta DOM'da ama yalniz secilide gorunuyor. `hidden`
   niteligi DEGIL sinif + `display`: bu depoda `display` tasiyan kapsayicilar
   `hidden`i iki kez ezdi (`.onb-gaprow` ayni deseni kullaniyor).
   `display:none` ayni zamanda gizli dugmeleri sekme sirasindan cikariyor. */
.gorunum-tonlar { display: none; }
.gorunum-kart.is-secili .gorunum-tonlar {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s1);
  padding: 0 var(--s3) var(--s3);
}
.gorunum-ton {
  --ton-renk: transparent;
  display: grid;
  justify-items: center;
  gap: 3px;
  min-width: 0;
  padding: var(--s2) 4px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-2);
  font: inherit;
  font-size: 12px;
  text-align: center;
  cursor: pointer;
}
.gorunum-ton:hover { border-color: var(--ink-3); }
.gorunum-ton.is-secili {
  border-color: var(--ink-2);
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 600;
}
.gorunum-ton-daire {
  width: 22px;
  height: 22px;
  border-radius: var(--radius-pill);
  background: var(--ton-renk);
  /* Cok acik bir ton (F'nin asidi) beyaz zeminde kaybolmasin diye kenarlik
     KOSULSUZ; degeri jetondan, tonun kendisinden turetilmiyor. */
  border: 1px solid var(--line-2);
}
.gorunum-ton-ad { min-width: 0; overflow-wrap: anywhere; }
.gorunum-ton-etiket { display: block; min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 720px) {
  .gorunum-kartlar { grid-template-columns: 1fr; }
}

.onb-done {
  border: 1px solid var(--accent-deep);
  background: var(--accent-soft);
  border-radius: var(--radius);
  padding: 16px 18px;
}
.onb-done h3 { margin: 0 0 6px; font-size: 18px; }
.onb-done h3:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.onb-done code { font-size: 12.5px; word-break: break-all; }

/* VITRIN ADIMI (CP3-G) — son adimin ikinci yarisi: randevu sayfasi zaten
   canli, tanitim SITESI ayri bir is. Kendi kutusu YOK ve olmamali: ayni
   sonuc kartinin devami oldugu icin yalnizca bir cizgiyle ayriliyor.
   Tum degerler degiskenden (VISION.md S3). */
.onb-vitrin {
  margin-top: var(--s4);
  padding-top: var(--s4);
  border-top: 1px solid var(--accent-deep);
}
.onb-vitrin h4 {
  margin: 0 0 var(--s1);
  font-family: var(--font-display);
  font-weight: 700;
}
.onb-vitrin p { margin: var(--s2) 0 0; }
.onb-vitrin .snippet { margin: var(--s3) 0; }
/* KOYU TEMADA DUGME KAYBOLUYORDU — canli panelde olculdu: `.btn` zemini bu
   kutuda hesaplanan `#2a3446`, kutunun kendi zemini de `#2a3446` (koyu temada
   `--accent-soft` ile ayni deger) ve `.btn` kenarligi saydam. Yani indirme
   dugmesi duz metin gibi goruniyordu. Token DEGISMIYOR (S3: eslesme baska
   yerlerde dogru) — yalnizca bu tintli kutudaki dugme kendi yuzeyini ve
   kenarligini aciyor. `ghost` disarida: o bilerek kenarliksiz, ikincil. */
.onb-vitrin .btn:not(.ghost) {
  background: var(--surface);
  border-color: var(--line-2);
}
.onb-vitrin .btn:not(.ghost):hover { background: var(--surface-2); }

/* SUBE SATIRI 1200px ALTINDA ALT ALTA — ve bu, D8 ONCESINDEN DE IYI.
   Isletmeler ekrani iki sutunlu `.cols` yerlesiminde; kart 1200'un altinda
   daralmaya basliyor. OLCULDU (yer tutucunun canvas `measureText` genisligi
   ile alanin ic genisligi karsilastirildi):
     yerlesim          1440           1024          800
     D8 oncesi (2 alan) ad 206 tam     ad 146 KIRPIK ad/adres 90 KIRPIK
     D8 (3 alan yan yana) ad 136 KIRPIK ad 76 KIRPIK  ad/adres 20 KIRPIK
   Yani ucuncu alan var olan bir sikismayi UCE katliyordu. Alt alta inince
   her alan kabin tam genisligini aliyor: uc esikte de KIRPIK YOK — yani bu
   satir artik D8 oncesinde bile kirpik oldugu iki esikte de temiz.
   720px kirilimi (asagida) yerinde duruyor; bu onun bir kademe erkeni ve
   YALNIZ sube satirini kapsiyor. */
@media (max-width: 1200px) {
  .onb-row[data-kind='branch'] { grid-template-columns: minmax(0, 1fr); }
  .onb-row[data-kind='branch'] .onb-del-space { display: none; }
  .onb-row[data-kind='branch'] .onb-del { justify-self: end; }
}

@media (max-width: 720px) {
  .onb-row,
  .onb-row[data-kind='service'],
  .onb-row[data-kind='branch'],
  .onb-row[data-kind='staff'] { grid-template-columns: 1fr; }
  .onb-del-space { display: none; }
  /* `minmax(0, 1fr)` — bu dosyanin `.onb-set` izgara notunda yazili kuralin
     atlanmis SON uygulamasi. Ciplak `1fr` = `minmax(auto, 1fr)` ve `auto`
     tabani ogenin min-content'i: saat girdisinin icsel genisligi ~96 px,
     dar ekranda sutuna dusen pay (302-16)/3 = 95,3 px. Uc sutun 96,08'e
     sisiyor, satir 304,23 oluyor ve kabini 2 px tasiyor.

     UC KATMANLI BIR TASMANIN EN ALT KATMANI — ve sirasi ogreticiydi:
       1. Once `.onb-hrow`un TABAN kurali suclandi. Degisti, tasma degismedi:
          taban kural dar ekranda zaten bu media query ile EZILIYOR.
          Degisiklik geri alindi.
       2. Sonra `<fieldset>`in UA `min-inline-size` kurali olculdu ve
          kapatildi (`.onb-set { min-width: 0 }`). Tasma yine 1 kaldi ama
          RAPORLAYAN oge degisti — ust katman kapaninca alt katman gorunur
          oldu.
       3. Bu kural. `getComputedStyle` "96,08 96,08 96,08" dedi, yani
          yururlukteki kural taban degil BU'ydu.
     Ders: tasma sayisi degismeden RAPORLAYAN ogenin degismesi ilerlemedir;
     "duzelttim ama sayi ayni" cogu zaman "altta bir katman daha var"
     demek. Her adimda hangi ogenin tasidigi olculmeseydi, uc katman da
     tahmine kalirdi. */
  /* DAR EKRANDA UC SUTUN SIGMIYOR — ve "sigdirmaya calismak" iki denemede
     de kusuru baska bir yere tasidi, yok etmedi:
       1. `minmax(0, 1fr)` x3        -> satir sigdi, GIRDILER tasti (1 -> 4).
       2. + `input { min-width: 0 }` -> sayac 0 dedi ama KARE, uzun adli
          gunlerin (Çarşamba, Perşembe, Cumartesi) onay KUTUSUNUN bir
          noktaya ezildigini gosterdi: isaretli mi degil mi okunamiyordu.
          Sayac memnundu, ekran bozuktu.
     Aritmetik zaten "hayir" diyordu: kap 302, iki bosluk 16, geriye 286
     kaliyor; iki saat girdisinin ICSEL tabani 2x96 = 192 ve gun etiketi
     ("Cumartesi" + kutu) ~110 — toplam 302'yi asiyor.

     Dogru cozum sikistirmak degil KATLAMAK: gun satiri kendi satirina,
     iki saat girdisi altina yan yana. Bu, ayni media query'nin oteki
     kurallarinin (`.onb-row { grid-template-columns: 1fr }`) zaten
     yaptigi sey — desen tutarli, kusur da gercekten kapaniyor. */
  .onb-hrow { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .onb-hrow > .onb-check { grid-column: 1 / -1; margin-right: 0; }
  /* Iki sutunda her girdiye ~143 px dusuyor, icsel taban 96 — daraltmaya
     gerek YOK. `min-width: 0` denendi ve geri alindi: onay kutusunu da
     daraltilabilir yaptigi icin uzun adli gunlerin kutusunu eziyordu. */
}

/* =========================================================================
   MUSTERI KARTI + BILDIRIMLER (Dalga 1 paket 2).

   Yeni gorsel dil ICAT EDILMEDI: ayni altin, ayni ince cizgi, ayni kart
   geometrisi. Iki yeni sekme panelin mevcut yogunluk disiplinini koruyor —
   gun boyu acik duracak bir ekran hala hizli okunmali.
   ========================================================================= */

/* Iki sutun: solda liste (dar), sagda detay (genis). `.cols`'tan farki
   sutunlarin esit OLMAMASI — liste taranir, detay okunur. */
.split {
  display: grid;
  gap: 16px;
  grid-template-columns: minmax(280px, 380px) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
}

.bar.tight { margin: 12px 0 8px; gap: 10px; }
.hr { border-top: 1px solid var(--line); margin: 18px 0 14px; }
.card-sub { font-family: var(--font-display); font-size: 15px; margin: 0 0 4px; }
.quiet-row { display: flex; gap: 6px; margin-top: 4px; }
.quiet-row input { flex: 1 1 auto; min-width: 0; }

/* --------------------------------------------------------- musteri listesi */

.cust-list { display: grid; gap: 6px; margin-top: 12px; max-height: 62vh; overflow: auto; }
.cust-row {
  display: grid;
  gap: 2px;
  width: 100%;
  text-align: left;
  padding: 9px 11px;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-left: 3px solid transparent;
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  transition: border-color var(--dur-1) var(--ease-out), background-color var(--dur-1) var(--ease-out);
}
.cust-row:hover { background: var(--surface-3); }
/* SECILI SATIR ILE UZERINE GELINEN SATIR AYNI ZEMINDEYDI (ikisi de
   `surface-3`), yani listede gezinirken imlecin altindaki satir secili
   olanla ayni goruunuyordu; ustelik secili/secili-degil farki olculunce
   1,13 cikiyordu. Simdi secili DOLGU tasiyor (16,30) ve uzerine gelme
   kendi basina kaliyor — iki durum artik ayni sinyali kullanmiyor. */
.cust-row.on,
.cust-row.on:hover {
  border-left-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}
.cust-row .cn { font-weight: 600; }
/* Ikincil meta secili satirda `accentInk`in %72'si — sabit gri
   (`ink-3`) dolu antrasit uzerinde okunmuyordu (olculdu: 1,54). */
.cust-row.on .cm { color: var(--accent-ink); opacity: 0.72; }
.cust-row .cm {
  font-size: 12.5px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}
.cust-empty { padding: 8px 0 4px; }
.cust-hit {
  margin: 0 0 12px;
  padding: 8px 10px;
  font-size: 13px;
  border-left: 2px solid var(--accent);
  background: var(--accent-soft);
  color: var(--ink-2);
}
.cust-hit strong { color: var(--ink); }

/* Kart basligi: ad + telefon + sayac seridi */
.cust-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.cust-head h2 { margin: 0; }
.cust-head .phone { font-variant-numeric: tabular-nums; color: var(--ink-2); font-size: 14px; }
.cust-stats { display: grid; gap: 8px; grid-template-columns: repeat(4, 1fr); margin: 14px 0 4px; }
.cust-stats .stat b { font-size: 20px; }
.cust-stats .stat.warn b { color: var(--warn); }
.cust-stats .stat.bad b { color: var(--danger); }
.cust-meta { font-size: 13px; color: var(--ink-2); margin: 6px 0 0; }
/* I-109 — MUSTERI OZETI ETIKET-DEGER. `.cust-meta` DOKUNULMADI: puan
   ortalamasi satiri gercekten bir kosu cumlesi ve oyle kalmali. Bu
   liste ise sorulara verilen cevaplarin listesi — `.kv`nin ayni izgarasi,
   kart icinde daha dar bir ritimle. */
.cust-ozet {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 14px;
  font-size: 13px; margin: var(--s2) 0 0;
}
.cust-ozet dt { color: var(--ink-3); }
.cust-ozet dd { margin: 0; color: var(--ink-2); }
.cust-form { display: grid; gap: 10px; margin-top: 4px; }
.cust-form label { display: grid; gap: 4px; font-size: 12px; color: var(--ink-3); letter-spacing: 0.04em; }
/* ETKILESIMLI SINIR — cakisma blogunun en pahali maddesi. Bu alanlar
   `surface-2` dolgulu ve kenarligi `line` idi: AYNI HEX, olculen 1,00.
   Yani panelde metin girilen bir kutunun HIC KENARI YOKTU; kutunun
   nerede bittigi yalnizca dolgunun karta karsi 1,10'undan okunuyordu.
   Spec §7.3 etkilesimli siniri `lineField` diye veriyor ve WCAG 1.4.11
   bu sinifi 3:1'e tabi tutuyor (dekoratif kart kenarligi degil). */
.cust-form input, .cust-form textarea {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line-field);
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  padding: 8px 10px;
}
.cust-form textarea { min-height: 62px; resize: vertical; line-height: 1.45; }

/* I-146 — ZIYARET ROZETI ILE DURUM ETIKETI GORSEL OLARAK AYRISIYOR.
   Ikisi de vurgu renginde bir hapti (`.tag` ve `.visit-badge`): takvim
   blogunda "seri · onay · kapora · 9." tek bir rozet dizisi gibi okunuyor,
   isletmeci sayaci bir durum sanip uzerine tikliyordu. Biri SAYAC (notr
   cizgi), otekiler DURUM (vurgu). Ucuncu bir renk uretilmedi — kanal
   `--line-2`/`--ink-2`, yani var olan notr kademe.
   `margin-left` bir bosluk jetonu: rozet artik etiketlerin SAGINDA ve
   aradaki ayrik aralik ikisinin ayri sey oldugunu ikinci kez soyluyor. */
.visit-badge {
  display: inline-block;
  font-size: 11px;
  letter-spacing: 0.04em;
  padding: 1px 6px;
  margin-left: var(--s2);
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-2);
  color: var(--ink-2);
  background: var(--surface);
  font-variant-numeric: tabular-nums;
}

/* I-069 — KULVAR TAVANINDA TASAN RANDEVULARIN ROZETI.
   Uc kulvardan sonrasi cizilmiyor; `+N` o saatte kac randevunun daha
   oldugunu soyluyor ve dokununca listesini aciyor. `.visit-badge`/`.tag`
   siniflari BILEREK kullanilmadi: ucuncu bir hap, I-146'nin yeni ayirdigi
   iki hapi tekrar birbirine karistirirdi. Kanal `.wl-tag`in olculeri. */
.serit-tasan {
  position: absolute;
  z-index: 2;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-field);
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-2);
  background: var(--surface);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.serit-tasan:hover { background: var(--surface-2); }

/* ------------------------------------------------------------- bildirimler */

.notif-counts { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.nc {
  display: flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 12.5px;
  color: var(--ink-3);
}
.nc b { font-size: 15px; color: var(--ink); font-variant-numeric: tabular-nums; }
.nc.ok b { color: var(--ok); }
.nc.wait b { color: var(--warn); }
.nc.bad b { color: var(--danger); }

.pill.scheduled { background: rgba(var(--warn-rgb), 0.12); color: var(--warn); border-color: rgba(var(--warn-rgb), 0.3); }
.pill.sending   { background: rgba(var(--warn-rgb), 0.12); color: var(--warn); border-color: rgba(var(--warn-rgb), 0.3); }
.pill.sent      { background: rgba(var(--accent-rgb), 0.12); color: var(--accent); border-color: rgba(var(--accent-rgb), 0.32); }
.pill.delivered { background: rgba(var(--ok-rgb), 0.12); color: var(--ok); border-color: rgba(var(--ok-rgb), 0.3); }
.pill.failed    { background: rgba(var(--danger-rgb), 0.12); color: var(--danger); border-color: rgba(var(--danger-rgb), 0.3); }
.pill.done      { background: rgba(var(--ok-rgb), 0.12); color: var(--ok); border-color: rgba(var(--ok-rgb), 0.3); }
.pill.no_show   { background: rgba(var(--warn-rgb), 0.12); color: var(--warn); border-color: rgba(var(--warn-rgb), 0.3); }
/* ONAY BEKLIYOR + KAPORA BEKLIYOR — mobil `StatusChip` ile AYNI karar
   (`mobile/lib/ui/widgets/common.dart`): ikisi de `warn` tonunda, cunku ikisi
   de "henuz kesinlesmedi" demek ve ayri bir renk isletmeciye ezberlenecek
   altinci bir durum rengi eklerdi. Ayirt eden sey SOZCUK. Panelde bu iki
   sinif hic tanimli degildi; rozet notr `.pill` govdesiyle ciziliyordu. */
.pill.pending,
.pill.pending_payment { background: rgba(var(--warn-rgb), 0.12); color: var(--warn); border-color: rgba(var(--warn-rgb), 0.3); }

/* Yedek kanaldan gittiginin isareti — zincirin gorunur kaniti. */
.fellback { color: var(--warn); font-size: 11.5px; white-space: nowrap; }

.msg-body {
  white-space: pre-wrap;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.5;
  margin: 0 0 12px;
}
.chain { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.chain li {
  display: grid;
  grid-template-columns: 92px 1fr auto;
  gap: 8px;
  align-items: baseline;
  padding: 7px 9px;
  /* `line` -> `line2`: dolgusuyla ayni hex olan kenarlik, "kuyrukta"
     durumundaki halkayi CERCEVESIZ birakiyordu; `failed`/`sent`
     kardeslerinin renkli cercevesi vardi, notr olanin hicbir seyi. */
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: 12.5px;
}
.chain li.failed { border-color: rgba(var(--danger-rgb), 0.32); }
.chain li.sent, .chain li.delivered { border-color: rgba(var(--ok-rgb), 0.28); }
.chain .ch { font-weight: 600; color: var(--ink); }
.chain .er { color: var(--danger); }
.chain time { color: var(--ink-3); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------- takvimdeki hayalet blok
   Iptal/gelmedi kayitlari musaitlik hesabindan cikar ama ekrandan TAMAMEN
   silinmezler: "iptal ettim, hicbir iz yok" isletmecinin guvenini bozar. */
.blk-void {
  background: transparent;
  border: 1px dashed var(--line-2);
  color: var(--ink-3);
  opacity: 0.75;
}
.blk-void .t { text-decoration: line-through; }
.lg-void { background: transparent; border: 1px dashed var(--line-2); }

/* Randevu detay diyalogu */
#apptDlg, #notifDlg { max-width: 520px; }
.kv { display: grid; grid-template-columns: auto 1fr; gap: 4px 14px; font-size: 13.5px; margin: 0 0 14px; }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; color: var(--ink); }
.dlg-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.cust-form .lbl { display: block; }

/* Bildirim panelinde AGIRLIK listede: kuyruk taranan yuzey, ayar arada bir
   dokunulan yuzey. `.split`in tersi. */
.split.wide-first { grid-template-columns: minmax(0, 1fr) minmax(300px, 400px); }
@media (max-width: 900px) {
  .split.wide-first { grid-template-columns: 1fr; }
}

/* Fieldset icindeki metin alanlari: baslik ustte, alan altta. Onceden satir
   ici akiyorlardi ve sayi kutusu metnin arasinda sikisiyordu. */
.onb-set .two > label,
.onb-set > label:not(.onb-check) {
  display: grid;
  gap: 4px;
  font-size: 12px;
  color: var(--ink-3);
  letter-spacing: 0.04em;
}
.onb-set .two > label input,
.onb-set .two > label select,
.onb-set > label:not(.onb-check) input,
.onb-set > label:not(.onb-check) select { width: 100%; }
.onb-set .onb-check { margin-right: 14px; margin-bottom: 6px; }

/* Bildirim tablosu: telefon ve zaman kirilmasin, "Detay" hep gorunur kalsin. */
#notifTbl td.num, #notifTbl th { white-space: nowrap; }
#notifTbl td:last-child { text-align: right; }

/* Ekran okuyucuya var, goze yok. Bos <th> ekran okuyucuda "sutun 6" diye
   okunur; islev adini vermek daha dogru. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

/* Sekme seridi dar ekranda TASIYORDU: paket 2'de iki sekme daha eklendi
   (Musteriler, Bildirimler) ve 390px'te yediye cikan serit sayfayi yatay
   kaydiriyordu. Yatay kaydirici yerine SARMA secildi: kaydiricida son
   sekmeler gorunmez kalir ve kullanici onlarin varligini bilemez. */
@media (max-width: 720px) {
  .tabs { flex-wrap: wrap; justify-content: flex-start; row-gap: 2px; }
  .top-right { margin-left: 0; width: 100%; }
  .top-right select { flex: 1 1 auto; min-width: 0; }
  .cust-stats { grid-template-columns: repeat(2, 1fr); }
  .chain li { grid-template-columns: 1fr; gap: 2px; }
  .notif-counts { gap: 6px; }
}

/* Grid cocugunun varsayilan `min-width: auto` degeri, icindeki tablonun
   min-content genisligini KAPSAYICIYA tasiyor: dar ekranda kart 667px'e
   cikip sayfayi yatay kaydiriyordu. Kaydirma tablonun kendi kutusunda
   kalmali. Ayni tuzak `.cols` icin de gecerli. */
.split > *, .cols > * { min-width: 0; }
.table-wrap { overflow-x: auto; }

@media (max-width: 720px) {
  /* Saatler satiri: gun adi + iki saat + "kapali" tek satira sigmiyordu. */
  .hours-row { grid-template-columns: 1fr 1fr; row-gap: 4px; }
  .hours-row .dayname { grid-column: 1 / -1; }
}

/* KONTRAST NOTU: `--ink-3` panele ozel, bilincli bir sapma — vitrinin
   tokeni (#7a7060) AA'yi karsilamiyor. Vitrinin kendi tokeni DEGISMEDI
   (build ciktisi byte-es kalmak zorunda, kirmizi cizgi); sapma panelde,
   acikca, olculmus haliyle duruyor. Deger ve olcum tablosu dosyanin
   basindaki `:root` blogunda — burada IKINCI bir bildirim yok, cunku iki
   bildirim okuyaninin yanlis sayiyi raporlamasina yol acti. */

/* =========================================================================
   SITE ISTATISTIKLERI (Dalga 1 kapanis paketi)

   Yeni gorsel dil YOK: kartlar `.sum-card`, oranlar `.meter`, tablolar
   `.tbl.compact` — Gun Sonu sekmesiyle ayni belirtecler. Tek yeni oge huni
   cubugu, cunku bir huninin daralmasini sayilarla anlatmak mumkun degil.
   ========================================================================= */

/* Instagram koprusu karti: yesil kenar, "kazanc" kutularinin (bekleme
   penceresi) dilini paylasiyor — ayni sinifi vermek yerine kendi sinifi,
   cunku ikisi ayri sekmede ve biri digerinin turevi degil. */
.sum-card.ig { border-color: rgba(var(--ok-rgb), 0.34); }
.sum-card.ig .big { color: var(--ok); }
.sum-card.ig > p:last-child { margin: 10px 0 0; font-size: 11.5px; }

.funnel { display: grid; gap: 12px; margin-top: 4px; }
.fn-step { min-width: 0; }
.fn-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 10px; font-size: 13px; margin-bottom: 5px;
}
.fn-head span { color: var(--ink-2); min-width: 0; }
.fn-head b { color: var(--ink); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Oran, sayinin yaninda ikincil: "8 <%12,5>" — hangi sayinin taşıyıcı
   oldugu bir bakista belli olsun. */
.fn-head em { color: var(--ink-3); font-style: normal; font-size: 11.5px; }
/* Cubuk genisligi ILK adima gore: huninin daralmasi gorsel olarak okunmali.
   `min-width` bilincli — 0 randevulu bir adim tamamen kaybolursa huni uc
   basamakli gorunur ve "o adim yok" diye okunur. */
.fn-bar {
  height: 10px; border-radius: 3px; min-width: 3px;
  background: var(--accent-soft); border: 1px solid rgba(var(--accent-rgb), 0.42);
}
.fn-bar.first { background: var(--accent); border-color: var(--accent); }

/* Iki kart yan yana ama 330px yerine 280px'ten kirilir: bu iki tablo dar
   (uc kolon), 330px esigi 390px'lik ekranda gereksiz yere alt alta atiyordu. */
.cols.two-up { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* 390px'te "7 Ağustos 2026, Cuma" hucre icinde uc satira sariyordu; tarih
   satirin TASIYICI bilgisi, kirilmasi degil kaymasi dogru. Tablo zaten
   `.table-wrap` icinde yatay kayiyor (panelin diger tablolariyla ayni desen). */
#stDaysTbl td:first-child, #stDaysTbl th:first-child { white-space: nowrap; }

/* =========================================================================
   ANA EKRAN — ALTI KATEGORI (Tur 2C)

   NE DEGISTI VE NEDEN. Onceki surum 11-12 duz kutucuktu ve Melih tarafindan
   reddedildi ("100 tane kutucuk olmamis"). Yeni kural (cerceve §2b):
   ana ekranda MAX 6 / MIN 4 kutucuk ve her kutucuk bir KATEGORI; kategorinin
   islevleri kategoriye tiklayinca gidilen ekrandan yonetiliyor.

   Alti kutucuk: kahraman "Bugun" + bes kategori karti. Sekme seridi de
   ayni alti kategoriyi tasiyor (on iki sekme -> alti) — 1280 pikselde seridin
   yarisinin gorunmemesi (Tur 2 denetim bulgu #6) boylece KAYNAGINDA cozuldu,
   ayri bir kaydirma cozumu gerekmedi.

   Uc modernlik maddesi bu blokta somutlasiyor:
     - YOGUNLUK (madde 2): kahraman kart genis nefesli, kategori kartlari
       kompakt. Yogunluk farki = onem farki; kullanici okumadan nereye
       bakacagini biliyor.
     - RADIUS (madde 4): kahraman da kategori kartlari da `--radius-hero`
       tasiyor; ayrimi yogunluk ve yuzey rengi veriyor, radius degil.
     - KATMAN (madde 3): kahraman TERS YUZEY (koyu blok, beyaz murekkep)
       oldugu icin ayrisiyor. Golge tek kademe: kategori kartlari da
       `--shadow` tasiyor, accent kenarlik yok (kenar notr `--line`).
   ========================================================================= */
/* MAX-WIDTH KALKTI (olculdu). Eski 1160px siniri, kutucuklarin en dar
   izi 206px iken ust cubukla hizayi tutturmak icin konmustu. Yeni tasarim
   dilinde iz 224px'e cikti ve 1160 pikselde bes kategoriden yalnizca DORDU
   siğiyor — besincisi tek basina ikinci satira dusuyordu (olculdu:
   `gridTemplateColumns` = 4x278px). Hizalama sorunu da artik yok: `.panel`
   kendisi 1280 maks. genislik + spec §3'un kenar dolgusunu tasiyor, yani
   icerik adasi ust cubukla zaten ayni eksende. Bes kart 1200 piksellik
   iceride ~227'ser piksel aliyor. */
.home-grid { max-width: none; }

/* ---------------------------------------------------------- kahraman kart
   TUR 3C: kart artik bir `<div>`, tiklanabilir olan icindeki `.home-hero-main`
   dugmesi. Sebep yapisal: kartin altina gunun ilk randevularinin mini-listesi
   girdi (UI/UX #1) ve bir `<button>` icine liste koymak — ozellikle icinde
   rozet/etkilesim olan bir liste — gecersiz HTML olurdu. Kart cercevesi
   (kenarlik, zemin, golge, radius) `<div>`e; hizalama ve basma geri bildirimi
   dugmeye tasindi. Gorunum degismedi, kapsayici degisti. */
/* KAHRAMAN KART (spec §6.2). Acik temada sayfanin TERS YUZEYI: koyu
   antrasit blok, beyaz murekkep. Eski surumde kategori renginin degradesi
   + `surface-3` zeminiydi ve yeni dilde ana ekranin en guclu ogesi
   olmasi gerekirken kutucuklardan ayrisamiyordu.

   `overflow: hidden` + `position: relative` dekoratif isik dairesi icin
   sart (asagida `::after`). */
.home-hero {
  position: relative; overflow: hidden;
  margin: 0 0 var(--s8); padding: var(--s6);
  color: var(--hero-ink);
  border-radius: var(--radius-hero);
  border: 0;
  background: var(--hero);
  box-shadow: var(--shadow);
}
/* DEKORATIF ISIK DAIRESI — tasarimin imzasi (spec §6.2, §9-B).
   128x128, sag -16 / ust -16, 40px blur. Dekoratif: metin tasimiyor,
   kontrasti etkilemiyor. Istenmezse bu tek kural silinir.
   `pointer-events: none` cunku dugmenin uzerinde duruyor. */
.home-hero::after {
  content: ''; position: absolute; right: -16px; top: -16px;
  width: 128px; height: 128px; border-radius: 50%;
  background: var(--hero-glow); filter: blur(40px);
  pointer-events: none; transition: background var(--dur-2) var(--ease-out);
}
.home-hero:hover::after { background: rgba(255, 255, 255, 0.1); }
.home-hero-main {
  position: relative; z-index: 1;
  display: flex; align-items: flex-start; gap: var(--s4); width: 100%;
  padding: 0; margin: 0; border: 0; background: none;
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  transition: transform 90ms var(--ease-out);
}
/* DOKUNMA GERI BILDIRIMI (madde 9): basista 1px ice gocme.
   Yalnizca `transform` — duzen hic hesaplanmadigi icin CLS'e dokunmuyor,
   cercevenin "CLS 0, bozulamaz" kuralina birebir uyuyor. */
.home-hero-main:active { transform: scale(0.985); }
/* Odak halkasi koyu blogun UZERINDE duruyor — `--accent` (acik temada
   #2D2D2D) burada kaybolurdu. `--hero-ink` iki temada da kahraman kartin
   kendi murekkebi. */
.home-hero-main:focus-visible { outline: 2px solid var(--hero-ink); outline-offset: 3px; }

/* MINI-LISTE — gunun ilk dort randevusu (UI/UX #1, Secenek A).
   Izgara: saat sabit genislikte (tabular-nums ile hizali), musteri ve hizmet
   esnek, rozet sagda. Sabit genislikli saat sutunu "tarama ritmi"ni
   koruyor — ayni kusurun kategori satirlarinda olculen hali (#5). */
.home-hero-list {
  position: relative; z-index: 1;
  list-style: none; margin: var(--s5) 0 0; padding: var(--s4) 0 0;
  /* Ayrac kahraman kartin KENDI murekkebinden turuyor: kategori rengi
     koyu blok uzerinde yabanci duruyordu. */
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex; flex-direction: column; gap: var(--s2);
}
/* SUTUNLAR ICERIGE GORE, ESNEMEZ. Ilk yazimda sutunlar `1fr`/`1.15fr` idi ve
   1440 pikselde satir ekranin genisligine YAYILIYORDU: saat solda, musteri
   ortada, hizmet ~500 piksel otede. Uc parca tek bir cumle gibi degil, uc
   ayri sutun gibi okunuyordu — kare alinmadan gorulmeyen bir kusur, olcumler
   (tasma 0) tertemizdi.
   `max-content` ile sutunlar EN GENIS hucreye gore olculuyor: satirlar hala
   birbirine hizali (tarama ritmi korunuyor) ama satir icerigin bittigi yerde
   bitiyor. */
.home-hero-list li {
  display: grid;
  grid-template-columns: 4.6em minmax(0, max-content) minmax(0, max-content) auto;
  align-items: baseline; column-gap: 18px; font-size: 13.5px; line-height: 1.35;
}
/* Kahraman kartin ICINDEKI metinler `--ink*` DEGIL `--hero-ink*` tasiyor:
   koyu blok uzerinde `--ink` (acik temada #0F172A) okunmazdi. Bu, ters
   yuzeyin tum kuralini tek yerde toplayan ayrim. */
.hh-t { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--hero-ink); }
.hh-m { color: var(--hero-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hh-s { color: var(--hero-ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hh-d { justify-self: start; }
.home-hero-list li.hh-more {
  display: block; color: var(--hero-ink-2); font-size: 13px;
}

/* I-073 — DUN KASA SATIRI (Melih karari 2026-09-02 = "1a"). Kahraman kartin
   en altinda tek satir: "Dün kasa: 8.400 TL". Kendi ayraci YOK — mini-liste
   zaten bir cizgi ciziyor, ikincisi karti uc bolmeli bir kutuya cevirirdi.
   Yeni olcu/renk YAZILMADI (S3): bosluk `--s3`, murekkep `--hero-ink-2`,
   punto kartin kendisinden miras. */
.home-hero-dun {
  position: relative; z-index: 1;
  margin: var(--s3) 0 0;
  color: var(--hero-ink-2);
}

/* Dar ekranda (panel de 900 pikselin altina inebiliyor) hizmet sutunu
   dusuyor: saat + musteri okunur kalmali, kirpilmis iki sutun degil. */
@media (max-width: 720px) {
  .home-hero-list li { grid-template-columns: 4.6em minmax(0, 1fr) auto; }
  .hh-s { display: none; }
}

/* Simge kutusu 48x48, 16px kose, %10 beyaz kuyu, simge 20px (spec §6.2).
   Kutu = simge boyutunun 2,4 kati (48/20) — spec §10'un optik kurali. */
.home-hero-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; flex: 0 0 auto;
  border-radius: var(--radius); background: rgba(255, 255, 255, 0.1);
  color: var(--hero-ink);
}
.home-hero-ico svg { width: 20px; height: 20px; }
/* `display: flex` SUS DEGIL. Icindeki iki oge `<span>` (dugmenin icinde
   blok eleman olamaz) ve satir ici kaldiklarinda BASLIK ile ozet satiri yan
   yana akiyordu: "Bugün · 14 Ağustos 2026, Cuma5 randevu". Ilk ekran
   goruntusunde goruldu; hicbir test yakalayamazdi, cunku metin dogruydu. */
.home-hero-txt { min-width: 0; flex: 1; display: flex; flex-direction: column; }
/* TIPOGRAFI OLCEGI (madde 1): kahraman baslik display fontunda ve 24px;
   kategori kartlari 15,5px govde fontunda. Onceki surumde 11 kutucugun 11'i
   AYNI 15,5px'ti — hiyerarsiyi tek basina olcek atlamasi tasiyor, renk ya
   da boyut oyunu gerekmeden. */
/* Kahraman baslik 18/600/1,25 (spec §4 "Kahraman kart başlığı") — eski
   24px display degil. Hiyerarsiyi artik punto degil ZEMIN tasiyor: koyu
   blok zaten sayfanin en guclu ogesi. */
.home-hero-ad {
  font-family: var(--font-display); font-size: 18px; font-weight: 600;
  line-height: 1.25; letter-spacing: 0; color: var(--hero-ink);
}
.home-hero-not {
  margin-top: var(--s1); font-size: 14px; font-weight: 400; line-height: 1.429;
  color: var(--hero-ink-2);
}
/* CTA ters yuzeyin USTUNDE: dolgusu beyaz, metni kartin zemini. Eski
   `--accent` dolgu (#2D2D2D) kahraman kartin kendi zemini oldugu icin
   yeni palette gorunmez olurdu. */
.home-hero-cta {
  flex: 0 0 auto; white-space: nowrap; align-self: center;
  padding: 10px var(--s5); border-radius: var(--radius-pill);
  background: var(--hero-ink); color: var(--hero);
  font-size: 13px; font-weight: 700;
}

/* ------------------------------------------------------- kategori kartlari
   SUTUN SAYISI SABIT DEGIL (Tur 3). Dort sabit sutun, Tur 2C'nin DORT
   kategorisi icin dogruydu; Kasa gelince kart sayisi BESE cikti ve izgara
   4+1 kirildi — besinci kart tek basina ikinci satira dusuyor ve ekran
   yarim yuklenmis gibi duruyordu (Tur 1a'da tam bu sinifta bir kusur
   olculmustu, orada da izgara bir tam sutunu bos birakiyordu). `auto-fit`
   sutun sayisini KART SAYISINA degil GENISLIGE bagliyor: 1440'ta bes kart
   tek satirda, 1024'te uc + iki, dar ekranda iki + iki + bir.

   Ust sinir ARTIK YOK: `.home-grid` `max-width: none` tasiyor (yukarida,
   olcum gerekcesiyle). Genisligi `.panel`in 1280 maks. genisligi belirliyor;
   bes kart 1200 piksellik iceride ~227'ser piksel aliyor ve etiketler
   ("Musteriler & Pazarlama") iki satira sigiyor. */
/* KATEGORI KUTUCUGU (spec §6.3). Tasarimda kare kutucuk 180px sabit
   yukseklikte ve iki sutunlu; masaustunde sutun sayisi genislige gore
   akiyor (bes kategori 1280'de tek satira siğiyor) ama YUKSEKLIK ve ic
   duzen tasarimin aynisi: simge ustte, metin altta, `space-between`.
   Izgara boslugu 16 (spec §3). */
.home-cats { display: grid; gap: var(--s4); grid-template-columns: repeat(auto-fit, minmax(224px, 1fr)); }

/* Ust kenardaki 2px renk cizgisi KALKTI: yeni dilde kategori kimligini
   PASTEL SIMGE KUTUSU tasiyor, kartin kenari degil. Ikisi birden "renk
   burada" demek olurdu ve tasarimda kart kenari her zaman notr. */
/* `space-between` KULLANILMIYOR, `margin-top: auto` kullaniliyor.
   Tasarimin ic duzeni "simge ustte, metin altta" ve bu iki BLOK arasinda
   bir bosluk; ama kutucugun dogrudan cocuklari DORT duz kardes
   (simge · ad · not · sayac). `space-between` dordunu birden esit
   dagitirdi, yani baslik ile sayac arasi da acilirdi. Bosluk tek yere,
   simge ile metin blogu arasina konuyor (`.home-cat-ad`'da). */
.home-cat-card {
  display: flex; flex-direction: column; align-items: flex-start;
  min-height: 180px; padding: var(--s6);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-hero); cursor: pointer; text-align: left; font: inherit;
  box-shadow: var(--shadow);
  transition: border-color var(--dur-1) var(--ease-out),
    box-shadow var(--dur-1) var(--ease-out),
    transform 90ms var(--ease-out);
}
/* Uzerine gelme = kenarlik bir kademe koyulasiyor (spec §6.3:
   `line` -> `line2`). Zemin DEGISMIYOR — kart zaten beyaz ve zemini
   oynatmak 1,05'lik bir farkta titreme gibi okunuyordu. */
.home-cat-card:hover { border-color: var(--line-2); }
.home-cat-card:active { transform: scale(0.985); box-shadow: var(--shadow-press); }
.home-cat-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* PIKTOGRAM KUYUSU — harf monogramin yerini aldi (madde 7).
   "VR"/"AO" gibi iki harf okuma gerektiriyordu; tek-cizgi piktogram
   on-dikkatli (pre-attentive) taniniyor. Kuyu kategori renginin %16'si,
   ikon rengin kendisi: olculen en dusuk kontrast 3,95 (acik tema, bugun). */
/* PASTEL SIMGE KUTUSU (spec §6.3): 48x48, 16px kose, zemin kategorinin
   PASTEL kutu rengi, simge 20px kategorinin kendi rengi.

   Kuyu artik `rgba(--c-rgb, .16)` DEGIL isimli `--c-box` tokeni. Sebep
   olcum: alfali kuyu zemine gore degisiyordu ve koyu temada kart yuzeyine
   harmanlanan deger Flutter'da ayni sayiyi vermiyordu — iki istemci ayni
   kutuyu farkli renkte cizerdi. `--c-box` iki tarafta da opak, tek karar.
   Degiskeni `admin.js` kategoriyle birlikte basiyor (`katBox`). */
.home-cat-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; margin-bottom: var(--s4);
  border-radius: var(--radius);
  background: var(--c-box); color: rgb(var(--c-rgb));
}
.home-cat-ico svg { width: 20px; height: 20px; }
.home-cat-ad { margin-top: auto; font-size: 16px; font-weight: 700; line-height: 20px; }
.home-cat-not {
  margin-top: var(--s1); font-size: 13px; line-height: 1.45; color: var(--ink-3);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
/* Sayac SAYIYI degil GERCEGI yaziyor: rol kapisi bir islevi gizlediyse
   sayi da duser. "5 islev" yazip dordunu gostermek, kutucugun kendisini
   yalanci yapardi. */
/* Sayac = ISLEV kalibi (spec §4): 12/500 buyuk harf +0,05em `--ink-3`.
   Renk kategori rengi DEGIL: tasarimda sayac notr gri ve kategori rengi
   YALNIZ simgede yasiyor. Renkli sayac, kutucukta rengi iki kez
   soylemek olurdu.
   `text-transform` gorsel: alttaki dize "3 işlev" olarak kaliyor
   (spec §9 madde 5) ve `<html lang="tr">` sayesinde `i -> İ`. */
.home-cat-n {
  margin-top: var(--s1);
  font-size: 12px; font-weight: 500; line-height: 16px;
  letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink-3);
}

/* =========================================================================
   KATEGORI ICI EKRAN — SATIR LISTESI

   Karar (UI/UX spec Bolum 3): kart izgarasi DEGIL satir listesi. Ana ekran
   "kesif" modu (bes buyuk secenek), kategori ici "yardimci program" modu
   (ne aradigini biliyorsun, hizli tara). Izgara icine izgara koymak
   Melih'in reddettigi kutucuk enflasyonunu bir kat asagi tasimak olurdu.

   SPEC'TEN TEK SAPMA: onizleme dosyasi iki bolmeli (300px sol ray + icerik)
   ciziyordu. Burada satir listesi TAM GENISLIK, secim ekrani degistiriyor.
   Sebep olculebilir: 1024 pikselde 300 piksellik bir ray icerige ~700 piksel
   birakiyor ve panelin gun takvimi/isletme formlari o genislikte tasiyor
   (Tur 2 entegrasyonunda `.onb-row` tam bu sinifta bir kusur vermisti).
   Mobil zaten "liste -> itilen ekran" yapiyor; tam genislik iki istemciyi
   yapisal olarak AYNI hale getiriyor.
   ========================================================================= */
.cat-screen { max-width: 1160px; }
/* IC SARMALAYICILAR FLEX SUTUN. Bu blogun tum metin ogeleri `<span>`
   (dugmenin icinde blok eleman olamaz); satir ici kaldiklarinda baslik ile
   alt satir yan yana akiyor ve ekranda "Randevu listesiTarih araligi..."
   gorunuyordu. Hicbir test yakalayamaz — metin dogru, YERLESIM yanlis.
   Ilk ekran goruntusunde goruldu. */
/* Kategori basligi: tam genislik satir kalibinin (spec §6.4) baslik
   hali — 56x56 pastel kutu, 24px simge, 18/700 baslik. */
.cat-head { display: flex; align-items: center; gap: var(--s5); margin-bottom: var(--s6); }
.cat-head > span:last-child { display: flex; flex-direction: column; min-width: 0; }
.cat-head-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 56px; height: 56px; flex: 0 0 auto;
  border-radius: var(--radius);
  background: var(--c-box); color: rgb(var(--c-rgb));
}
.cat-head-ico svg { width: 24px; height: 24px; }
.cat-head-ad {
  font-family: var(--font-display); font-size: 24px; font-weight: 700;
  line-height: 32px; letter-spacing: -0.025em;
}
.cat-head-not { font-size: 14px; font-weight: 500; color: var(--ink-3); margin-top: 0; }

/* Bolum basligi KARTIN DISINDA (spec §7.2), ISLEV kalibinda, alt boslugu
   12px — boylece kartin ici yalnizca veri kaliyor. */
.cat-group {
  margin: var(--s8) 0 var(--s3); font-size: 12px; font-weight: 600;
  letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-3);
}
/* SATIR LISTESI (spec §7.1, ">6 satir" hali): TEK kart (24px kose, dikey
   8px dolgu) icinde satirlar; satir arasi 1px `line-2` sac cizgisi,
   soldan 16px girintili (simge sutununu kesmiyor). Zebra serit YOK.
   Onceki surumde satirlar kartsizdi ve ust/alt cizgilerle yuzuyordu —
   yeni dilde her liste bir kartin icinde yasiyor. */
.cat-rows {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); box-shadow: var(--shadow);
  padding: var(--s2) 0; overflow: hidden;
}
.cat-row {
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  min-height: 72px; padding: var(--s3) var(--s4);
  text-align: left; font: inherit; color: var(--ink);
  background: none; border: 0; cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out);
}
/* Sac cizgisi `border-bottom` yerine `::after`: 16px girinti
   `border`la yapilamiyor ve son satirda cizgi kalmamali. */
.cat-row { position: relative; }
.cat-row + .cat-row::before {
  content: ''; position: absolute; left: var(--s4); right: 0; top: 0;
  border-top: 1px solid var(--line-2);
}
.cat-row:hover { background: var(--surface-2); }
.cat-row:active { background: var(--surface-3); }
.cat-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* Oncu oge: 40x40 `radius-sm` pastel kutu, simge 20px (spec §7.1).
   Kategori rengi ARTIK BEKLEMEDE DEGIL: eski surumde kuyu notrdu ve renk
   yalnizca uzerine gelindiginde geliyordu, yani tarama sirasinda hicbir
   sey soylemiyordu. */
.cat-row-ico {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; flex: 0 0 auto;
  border-radius: var(--radius-sm);
  background: var(--c-box); color: rgb(var(--c-rgb));
}
.cat-row-ico svg { width: 20px; height: 20px; }
.cat-row-txt { min-width: 0; flex: 1; display: flex; flex-direction: column; }
.cat-row-ad { font-size: 16px; font-weight: 600; line-height: 20px; }
.cat-row-not { font-size: 14px; font-weight: 400; color: var(--ink-3); line-height: 20px; margin-top: 2px; }
.cat-row-chev { flex: 0 0 auto; color: var(--ink-3); }
.cat-row-chev svg { width: 16px; height: 16px; display: block; }

/* KIRINTI (breadcrumb) — islev ekrani acikken nerede olundugunu ve nasil
   cikilacagini soyleyen tek satir. Mobilde bunun karsiligi geri dugmesi
   olan baslik cubugu; iki istemcide de "kategori / islev" ayni sozcuklerle
   yaziliyor. */
.fn-crumb {
  display: flex; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s5); font-size: 13px; color: var(--ink-3);
}
.fn-crumb button {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 var(--s3) 0 10px; height: 32px; border-radius: var(--radius-pill);
  background: var(--surface-2); border: 0;
  color: var(--ink-2); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    transform 90ms var(--ease-out);
}
.fn-crumb button:hover { background: var(--surface-3); color: var(--ink); }
.fn-crumb button:active { transform: scale(0.985); }
.fn-crumb button svg { width: 14px; height: 14px; }
.fn-crumb b { color: var(--ink); font-weight: 600; }

@media (max-width: 900px) {
  .home-cats { grid-template-columns: repeat(2, 1fr); }
  /* Sarma kurali kartin kendisinden DUGMEYE tasindi (Tur 3C yapisal degisim):
     kart artik bir `<div>` ve flex degil; saran sey ikon+metin+CTA satiri. */
  .home-hero-main { flex-wrap: wrap; }
}

/* Acik tema ARTIK `:root` (dosyanin basi). `[data-theme='light']` bir
   belirtec BLOGU tasimiyor cunku tasimasina gerek yok: `:root` zaten
   `<html>` elemani ve acik palet oradan geliyor. Nitelik yine de yaziliyor
   (`admin.js` -> `applyTheme`) — koyu blogu bir `[data-theme='dark']`
   secicisiyle acip kapatmak, temayi "yoklukla" degil ACIK BIR DEGERLE
   anlatmak icin. */

/* ==========================================================================
   ÜRÜN TURU 2 — bekleme listesi, personel hesapları, rol rozeti.
   Dosyanın SONUNA eklendi (ortasına değil): açık tema/tasarım paketi aynı
   dosyada paralel yürüyor ve iki ajanın aynı satırlarda buluşması, ürünün
   kendisinden pahalı bir çakışma çözümü demek olurdu.
   Renkler değişken üzerinden; sabit hex yok — açık tema kendiliğinden gelsin.
   ========================================================================== */

.role-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 12px;
  white-space: nowrap;
}
.role-badge b { color: var(--ink); font-weight: 600; }

/* `display: inline-flex` yazan her kural `hidden` OZNITELIGINI EZER — tarayici
   varsayilani `display:none` yalnizca author kurali yokken gecerli. Bu kural
   olmadan sahip/isletmeci oturumunda BOS bir rozet kabugu (kenarlik + dolgu)
   ust cubukta duruyordu. Olcumle bulundu: `hidden` true iken computed display
   hala `flex` idi. */
.role-badge[hidden] { display: none; }

.wl-row {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--s3) var(--s4);
  margin: var(--s2) 0;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--ink);
  cursor: pointer;
}
.wl-row:hover { border-color: var(--accent); }
/* Secili satir: cerceve degil DOLGU (Addendum-3). Eski hali zemin olarak
   `surface-2` idi, yani secili ve secili olmayan satir 1,00 — bekleme
   listesinde ve kasa adisyonunda hangi satirin acik oldugu yalnizca
   1px'lik bir cerceveden okunuyordu. `inset` halka artik gereksiz. */
.wl-row.on {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-ink);
}
.wl-row .wl-top { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.wl-row .wl-name { font-weight: 600; }
.wl-row .wl-meta { color: var(--ink-2); font-size: 12.5px; }
.wl-row .wl-line { display: block; color: var(--ink-2); font-size: 12.5px; margin-top: 2px; }
/* Secili satirin ikincil metinleri — `ink-2` dolu antrasit uzerinde
   okunmuyor; `accentInk` %72 iki temada da gecerli tek kural. */
.wl-row.on .wl-meta, .wl-row.on .wl-line { color: var(--accent-ink); opacity: 0.72; }

.wl-tag {
  display: inline-block;
  padding: 2px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line-2);
  font-size: 11.5px;
  color: var(--ink-2);
  background: var(--surface);
}
.wl-tag.waiting { border-color: var(--accent); color: var(--accent); }
.wl-tag.offered { border-color: var(--walkin); color: var(--walkin-ink); }
.wl-tag.claimed { border-color: var(--ok); color: var(--ok-ink); }
.wl-tag.expired, .wl-tag.cancelled { opacity: .75; }

.wl-slots { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.wl-slots .btn { min-width: 74px; }

.staff-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-end;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.staff-row:last-child { border-bottom: 0; }
.staff-row .staff-name { flex: 1 1 130px; font-weight: 600; }
/* `flex: 0 0 auto` — KUCULMESIN. Onceki `0 1 auto` etiketin kendi
   icerigininden dar olmasina izin veriyordu: "Rol" etiketi + 130px'lik
   secici 156 piksel istiyor ama kutu 150 piksele sikisiyordu ve ETIKET
   METNI kirpiliyordu ("Rol" -> "Ro"). Kare `08-isletme/acik.png` ile
   goruldu, sonra olculdu: satir 339, cocuklar 150/74/83 + 16 bosluk.
   Kucultmeyi kapatinca satir 329'a oturuyor ve sigiyor; daha dar bir
   sutunda `flex-wrap` zaten devrede (ve 520px altinda hepsi tam
   genislige geciyor). */
.staff-row label { flex: 0 0 auto; margin: 0; }
.staff-row input[type="text"], .staff-row input[type="password"] { width: 110px; }
.staff-row select { width: 130px; }

/* TELEFONLA GIRIS SATIRLARI (Faz 1 / 1a). Kaburga `.staff-row` ile AYNI ve
   bu bilincli: ikisi de "bu kisi iceri nasil giriyor?" sorusunun parcasi ve
   ayni kartta yan yana duruyorlar. Ikinci bir satir dili, ayni sorunun iki
   ayri yer oldugunu ima ederdi. */
.id-block { margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--line-2); }
.id-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-end;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.id-row:last-child { border-bottom: 0; }
.id-row .staff-name { flex: 1 1 130px; font-weight: 600; }
.id-row label { flex: 0 0 auto; margin: 0; }
.id-row input[type="tel"] { width: 150px; }
.id-state { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.id-mask { color: var(--ink-2); font-size: 13px; font-variant-numeric: tabular-nums; }

/* BIR KEZ GOSTERILEN SIR. Uyari zemini (`--warn-soft`) bilincli: bu kutu bir
   basari mesaji degil, ekranda kalmasi istenmeyen bir sey. */
.id-secret {
  margin-top: var(--s4);
  padding: var(--s4);
  border: 1px solid var(--warn);
  border-radius: var(--radius);
  background: var(--warn-soft);
}
.id-secret .card-sub { margin-bottom: var(--s2); }
.id-secret-list { display: flex; flex-wrap: wrap; gap: var(--s2); margin-bottom: var(--s2); }
.id-secret-list code {
  padding: 4px 10px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.12em;
  font-variant-numeric: tabular-nums;
}

/* PERSONEL IZINLERI (plan Is 7). Kaburga `.id-block` ile AYNI ve ayni
   gerekceyle: ikisi de "Personel hesaplari" kartinin alt bolumu, ayri bir
   ekran degil. Ucuncu bir bolum dili, ayni karti uc parcaya bolerdi.
   ⚠ HAM DEGER YOK — renk ve olcunun tamami degiskenden (S3). */
.izin-block { margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--line-2); }
.izin-soru { padding: var(--s3) 0; border-bottom: 1px solid var(--line); }
.izin-soru:last-child { border-bottom: 0; }
.izin-baslik { margin: 0 0 var(--s2); font-weight: 600; color: var(--ink); }
/* Iki secenek ALT ALTA, yan yana degil: secenek cumleleri tam cumle ve
   yan yana dizilince 390 pikselde ikisi de kirpilirdi. */
.izin-secenek { display: flex; align-items: flex-start; white-space: normal; margin-bottom: var(--s1); }
.izin-secenek input { margin-top: 3px; }
/* Uyari SESSIZ: isletmeciyi bilgilendiriyor, islemi durdurmuyor (urun
   tasarimi §4). Bu yuzden `--warn` zemini degil, yalniz sakin bir ton. */
.izin-uyari { margin: var(--s2) 0 0; font-size: 13px; color: var(--ink-2); }

.cap-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.cap-table th, .cap-table td { padding: 5px 6px; border-bottom: 1px solid var(--line); text-align: left; }
.cap-table td.yes { color: var(--ok-ink); font-weight: 600; }
.cap-table td.no { color: var(--ink-2); }

/* 390 pikselde iki sütun sığmıyor: satırlar alt alta geçiyor, yatay taşma yok. */
@media (max-width: 520px) {
  .staff-row { align-items: stretch; }
  .staff-row label, .staff-row .staff-name { flex: 1 1 100%; }
  .staff-row input[type="text"], .staff-row input[type="password"], .staff-row select { width: 100%; }
  .id-row { align-items: stretch; }
  .id-row label, .id-row .staff-name { flex: 1 1 100%; }
  .id-row input[type="tel"] { width: 100%; }
}

/* ============================================== KAPORA + GÖMME (Tur 3)
 *
 * YENİ RENK YOK, YENİ BİLEŞEN DİLİ YOK. Ödeme listesi `.wl-row`ı, durum
 * rozetleri `.pill`i, katlama `.fold`u yeniden kullanıyor. Para ekranı için
 * ayrı bir görsel dil kurmak, ürünün içinde ikinci bir ürün gibi görünürdü
 * (pazar liderinin "SalonPAY" deseni) — ve çerçevedeki "para ekranı sade"
 * kuralı tam olarak bunu yasaklıyor.
 */

/* `.wl-row` bir <button> için yazılmıştı; ödeme listesinde <div> olarak
   kullanılıyor ve tıklanabilir DEĞİL — imleç de öyle söylemeli. */
div.wl-row { cursor: default; }
/* Uzerine gelme bu satirlarda BIR SEY YAPMAMALI — taban kenarlikla ayni
   token, yoksa "tiklanabilir" sinyali verir. Token `line`den `line2`ye
   alindi ki taban kuralla ayni sey kalsin (cakisma blogu). */
div.wl-row:hover { border-color: var(--line-2); }
div.wl-row.on:hover { border-color: var(--accent); }

/* Hizmet başına kapora satırı: anahtar · hesaplanan tutar · sabit tutar.
   Üçü tek satırda, çünkü işletme "bu hizmet ne kadar" sorusunu işaretlerken
   soruyor — iki ekran arasında gidip gelerek değil. */
.dep-list { margin: 6px 0 0; }
.dep-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  border-bottom: 1px solid var(--line);
}
.dep-row:last-child { border-bottom: 0; }
/* TASMA (Tur 4C) — `.onb-check`in `white-space: nowrap`i burada YANLIS.
   O kural kisa bir "Onayliyorum" etiketi icin dogru; bu listede etiket
   HIZMET ADI + SUBE ADI ve ikisi kiracinin yazdigi serbest metin. Uzun bir
   ad (`min-width: 0` sayesinde grid hucresi daralabiliyor ama metin
   kirilamiyor) satiri kartin disina tasiriyordu.
   Sinif GEVSETILMEDI, burada KAPSAMLI eziliyor — `.cust-form label.onb-check`
   duzeltmesinde (Tur 4A) verilen ayni karar. */
.dep-row .onb-check {
  margin: 0;
  min-width: 0;
  white-space: normal;
  align-items: start;
}
.dep-row .onb-check > span { min-width: 0; overflow-wrap: anywhere; }
.dep-row .onb-check input { margin-top: 2px; flex: none; }
.dep-amount { white-space: nowrap; font-variant-numeric: tabular-nums; }
.dep-fixed { display: flex; align-items: center; gap: 5px; margin: 0; }
.dep-fixed input { width: 78px; }
/* Hesaplanamayan fiyatın açıklaması SATIRIN ALTINDA, tam genişlikte:
   kısaltılmış bir hata metni, çözümü ("sabit tutar girin") gizlerdi. */
.dep-row .dep-note { grid-column: 1 / -1; margin: 0 0 4px; }
.dep-row.has-err { background: rgba(var(--danger-rgb), 0.06); }

/* Kopyala-yapıştır kodu. Kaydırılabilir ama SARMALANMIYOR: kırılan bir
   <script> satırı kopyalandığında çalışır, ama okuyan kişiye iki satır gibi
   görünür ve yarısını kopyalama riski doğar. */
.snippet {
  margin: 8px 0;
  padding: 10px 12px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--ink);
  font: 12.5px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  overflow-x: auto;
  white-space: pre;
  -webkit-user-select: all;
  user-select: all;
}

@media (max-width: 640px) {
  /* Dar ekranda üç sütun sığmaz; sabit tutar alt satıra iniyor ve hizasını
     koruyor. Kırpmak, kiracının okunamayan fiyat için tek çözümünü görünmez
     yapardı. */
  .dep-row { grid-template-columns: minmax(0, 1fr) auto; }
  .dep-fixed { grid-column: 1 / -1; justify-content: flex-end; }
}

/* PAZARLAMA ONAYI SATIRI (M5, Tur 4) — SINIF CAKISMASI DUZELTMESI.
   `.cust-form label` bir GRID (0,1,1 ozgulluk) ve `.onb-check`in
   `display:inline-flex`ini (0,1,0) EZIYOR; ustune `.cust-form input`
   `width:100%` verdigi icin onay kutusu satirin tamamina yayiliyor ve
   `.onb-check`ten gelen `white-space:nowrap` ile birlesince satir 4 piksel
   tasiyordu. Tasma `#custForm` ve `#custDetail`e kadar yukseliyordu.
   Olcumle bulundu (tasma teshisi), gozle degil.
   Sinifi GEVSETMEK yerine burada KAPSAMLI eziliyor: `.onb-check`in nowrap'i
   kisa etiketler icin dogru, bu satir icin degil. */
.cust-form label.onb-check {
  display: flex;
  align-items: center;
  gap: 8px;
  white-space: normal;
  letter-spacing: 0;
  font-size: 13px;
  color: var(--ink-2);
}
.cust-form label.onb-check input {
  width: auto;
  flex: none;
  margin: 0;
  padding: 0;
}

/* ====================================================== ASISTAN (H9 / Faz 3+4)
 *
 * S3 SOZU: bu blokta TEK BIR ham renk degeri yok. Renk, bosluk, kose, sure,
 * gecis egrisi — hepsi var olan belirtecler. Yeni tanimlanan tek sey
 * YERLESIM (konum, genislik, animasyon adi), yani bir DEGER degil bir kural.
 *
 * `420px` / `100vw` / `100dvh` birer GORUNUM olcusu (viewport), belirtec
 * adayi degil: panelde dialog GENISLIGI hicbir zaman jetonlanmadi, mevcut
 * `dialog{}` kurali da `min(560px, 94vw)` tasiyor. Bu, var olan oruntunun
 * devami; yeni bir istisna acmiyor.
 */

/* CEKMECE: `dialog{}` temel kuralini DEGISTIRMEDEN, yalniz bu secici
   altinda saga yasli tam-boy panele donusuyor. Uc mevcut dialog
   (addDlg/apptDlg/notifDlg) etkilenmiyor — olcusu de bu: temel kurala
   dokunan bir surum ucunu birden kaydirirdi. */
dialog#asistanDlg {
  position: fixed; inset: 0 0 0 auto; margin: 0;
  height: 100vh; height: 100dvh;
  width: min(var(--asistan-genislik, var(--asistan-en)), 100vw); max-width: 100vw;
  /* Yalniz SOL koseler yuvarlak: cekmece ekranin sag kenarina yapisik. */
  border-radius: var(--radius-hero) 0 0 var(--radius-hero);
  border-right: 0;
  padding: 0; overflow: hidden;
  /* ---- U1 PENCERE GEOMETRISI — TEK TANIM (spec §1.1/§1.2) ----------------
     Bu sayilar HEM cizimi (bu dosya) HEM kelepceyi (admin.js `pencereMotoru`)
     ilgilendiriyor. JS onlari `getComputedStyle` ile BURADAN okuyor
     (`pencereOlcu`); JS'te ikinci bir kopya tutulsaydi kullanicinin
     surukledigi pencere ile CSS'in cizdigi pencere iki ayri sinira tabi
     olurdu ve ayrisma ancak ekranda gorunurdu.

     Neden jeton olcegine (`--s*`, `--radius-*`) girmiyorlar: bunlar bir
     TASARIM degeri degil bir GORUNUM (viewport) olcusu — ustteki blok
     basliginin `420px/100vw/100dvh` icin yazdigi ayrimin devami. Bir
     pencerenin en dar hali, bosluk ritmiyle ayni ailede degil. */
     ⚠ IKI AILE, KARISTIRILMASIN. Asagidakiler TANIMLI sinirlar ve JS onlari
     yalniz OKUR. Kullanicinin surukleyerek urettigi ANLIK olculer ayri
     adlarla (`--asistan-genislik`, `--asistan-yukseklik`, `--asistan-x`,
     `--asistan-y`) ve yalniz satir ici yaziliyor; ayni ada yazilsalardi JS
     bir sonraki acilista kendi yazdigi degeri "varsayilan" diye okurdu. */
  --asistan-en: 420px;        /* varsayilan genislik (§1.4) */
  --asistan-en-dar: 360px;    /* kurallar ekraninin varsayilani (§1.4) */
  --asistan-en-alt: 360px;    /* sürükleyerek inilebilecek en dar (§1.1) */
  --asistan-en-ust: 720px;    /* ... ve en genis */
  --asistan-en-oran: 90;      /* ... ama gorunumun en fazla %90'i (§1.1) */
  --asistan-boy: 560px;       /* serbest pencerenin varsayilan boyu */
  --asistan-boy-alt: 400px;   /* serbest pencerenin en kisa hali (§1.1) */
  --asistan-boy-oran: 90;     /* ... ve gorunumun en fazla %90'i */
  --asistan-ayrilma: 40px;    /* sag kenardan ayrilma esigi (§1.1) */
  --asistan-miknatis: 60px;   /* birakinca yapisma bolgesi (§1.1) */
  --asistan-gorunur: 80px;    /* pencerenin ekranda kalmasi gereken en az payi (§1.2 kelepce) */
  /* DAR EKRAN BAYRAGI: esik SADECE asagidaki `@media`de yaziyor, JS de bu
     ozelligi okuyarak ogreniyor (`matchMedia` icine ikinci bir 720 yazmak,
     kirilma noktasini iki yerde tutmak olurdu). */
  --asistan-dar: 0;
}
/* ⚠ `display` NIYE BU SATIRDA VE USTTEKINDE DEGIL (D1/4, 2026-08-27 — OLCULDU).
 *
 * Tarayicinin kendi kurali `dialog:not([open]) { display: none }`. Ustteki
 * blok kosulsuz `display: flex` yazdiginda o kurali EZIYORDU: cekmece
 * ACILMADAN da, kapatildiktan SONRA da sayfanin sagindaki 420 pikseli
 * kaplamaya devam ediyordu.
 *
 * OLCUM (taze sayfa, cekmece hic acilmamis): `#asistanDlg.open === false`
 * iken `getComputedStyle(...).display === 'flex'`, `visibility === 'visible'`,
 * kutu 420x900 ve `document.elementFromPoint(1200, 450)` -> `asistanAkis`.
 * Yani kapali cekmece hem GORUNUYOR hem de altindaki panelin tiklamalarini
 * yutuyordu.
 *
 * Melih'in "asistanı kapatma düğmesi" bulgusunun olculebilen ayagi bu:
 * dugmeye basmak `close()` cagiriyor, `open` niteligi dusuyor ama EKRAN
 * DEGISMIYOR — kullanicinin gordugu sey "kapatma dugmesi calismiyor".
 *
 * `flex` yalnizca `[open]`de: kapaliyken tarayicinin `display: none` kurali
 * geri kazaniyor. Ustteki blokta kalan olculer (konum, genislik, kose)
 * zararsiz — gorunmeyen bir kutuya uygulaniyorlar. */
dialog#asistanDlg[open] {
  display: flex; flex-direction: column;
  animation: asistan-gir var(--dur-2) var(--ease-out);
  /* ⚠ `z-index` NON-MODAL'IN BEDELI — OLCULDU (U1, 2026-08-28).
   *
   * `showModal()` pencereyi tarayicinin UST KATMANINA (top layer) koyuyordu:
   * sayfadaki hicbir `z-index` onu asamazdi, bu bedavaydi. `show()` bunu
   * VERMIYOR — pencere normal yigin sirasina donuyor.
   *
   * OLCUM (ilk kare turu, 1440x900): `document.elementFromPoint` pencerenin
   * ICINDEKI bir dugmenin tam ortasinda panelin `.hh-more` ogesini dondurdu.
   * Yani pencere gorunuyordu ama tiklamalari PANEL yutuyordu — kullanicinin
   * gordugu sey "asistan donmus" olurdu.
   *
   * 50 nereden: panelin en yuksek katmani yapisan baslik seridi (20) ve
   * takvim katmanlari (≤4); toast 60'ta KALIYOR ve bu bilincli — bir bildirim
   * asistan penceresinin arkasinda kaybolmamali. Modal uc dialog zaten ust
   * katmanda, onlar bu siralamadan etkilenmiyor (§1.7). */
  z-index: 50;
}
@keyframes asistan-gir { from { transform: translateX(100%); } to { transform: translateX(0); } }
/* Global `prefers-reduced-motion` kurali yalniz `transition-duration`
   zorluyor; bu bir `animation`, o yuzden AYRICA kapatiliyor. Kurali
   "gelistirici hallederse" birakmak, hareket hassasiyeti olan kullanicinin
   her acilista ekranin kaydigini gormesi demekti. */
@media (prefers-reduced-motion: reduce) {
  dialog#asistanDlg[open] { animation: none; }
}
/* SERBEST/HAP durumunda giris animasyonu YOK: `asistan-gir` sagdan kayarak
   girer ve ekranin ORTASINDA duran bir pencerenin sagdan suzulmesi, kullanicinin
   az once BIRAKTIGI yerden baska bir yerden geldigini soylerdi. */
dialog#asistanDlg[open].konum-serbest, dialog#asistanDlg[open].hap { animation: none; }

/* ========================= U1 — PENCERE DURUMLARI (spec §1.1) ===============
 *
 * Uc yerlesim durumu bir SINIFLA anlatiliyor (`konum-sag` varsayilan ve
 * sinifsiz da dogru cizer, `konum-serbest`, `hap`). Durumun kendisi
 * `admin.js` -> `pencereMotoru` icinde yasiyor; buradaki kurallar yalniz
 * onun ciktisini ciziyor.
 *
 * NIYE `inset` DEGIL de `top/left`: serbest pencerede konum kullanicinin
 * biraktigi noktadir, yani bir VERI — CSS onu `var()` ile okuyor, JS satir ici
 * yaziyor. Boylece ne JS'te bir yerlesim kurali, ne CSS'te bir koordinat var.
 */
dialog#asistanDlg.konum-serbest {
  inset: auto; top: var(--asistan-y, 0); left: var(--asistan-x, 0);
  /* BOY KELEPCESI BURADA DEGIL JS'te (`pencereMotoru.kelepce`): burada bir
     `min(..., 90vh)` daha yazmak, ayni tavani iki yerde tutmak olurdu ve
     ikisi ayrisinca kullanici surukledigi pencerenin son 40 pikselini
     "tutmuyor" diye okurdu. CSS yalniz cizer, sinir JS'in. */
  height: var(--asistan-yukseklik, var(--asistan-boy));
  border-radius: var(--radius-hero);
  border-right: 1px solid var(--line);
}
/* HAP: 40x40'lik simge + etiket. Pencere KAPANMIYOR, yalniz kuculuyor —
   sohbet akisi, bekleyen onay karti ve acik mikrofon DOM'da kaliyor (§1.6). */
/* HAP KONUMU KOSEDEN VERILIYOR (`right/bottom`), `top/left`ten degil: hap
   genisligini ICERIKTEN aliyor, sol ust kosesinden yerlestirmek icin once
   olculmesi gerekirdi. Yatayda pencerenin birakildigi yan, dikeyde HER ZAMAN
   alt — ust serit panelin kendi canli kontrollerini tasiyor ve oraya konan
   bir hap onlari ortuyordu (U1 kare turunda olculdu). */
dialog#asistanDlg.hap {
  inset: auto; top: auto; left: auto;
  bottom: var(--s5);
  width: auto; height: auto;
  border-radius: var(--radius-pill);
  border-right: 1px solid var(--line);
  cursor: pointer;
}
dialog#asistanDlg.hap.hap-sag { right: var(--s5); }
dialog#asistanDlg.hap.hap-sol { left: var(--s5); }
dialog#asistanDlg.hap .asistan-bas { border-bottom: 0; padding: var(--s2) var(--s4); }
dialog#asistanDlg.hap .asistan-akis,
dialog#asistanDlg.hap .asistan-giris,
dialog#asistanDlg.hap .asistan-not,
dialog#asistanDlg.hap .asistan-onay-serit,
dialog#asistanDlg.hap .asistan-kapat-onay,
dialog#asistanDlg.hap .asistan-ses-not,
dialog#asistanDlg.hap #asistanEller,
dialog#asistanDlg.hap #asistanKucult,
dialog#asistanDlg.hap #asistanSabitle,
/* ⚠ (×) DE GIZLI — OLCULDU. Hap tek amacli bir kontrol: tiklamak pencereyi
   GERI ACAR. Uzerinde ikinci bir dugme birakmak iki soruna yol aciyordu:
   (1) geri acmak isteyen kullanici 40 pikselin yarisinda yanlislikla
   kapatabiliyordu, (2) kare turunda (×) panelin kendi seciciyle ust uste
   dusup "bozuk dugme" gibi okundu. Kapatma yolu kaybolmuyor: pencere geri
   acilir, (×) ya da Esc oradadir — ve kapatma korumasi (§1.7b) ancak orada
   dogru calisir. */
dialog#asistanDlg.hap #asistanKapat,
dialog#asistanDlg.hap .asistan-tutamac { display: none; }
dialog#asistanDlg.hap .asistan-bas-ico { display: inline-flex; }
dialog#asistanDlg.hap .asistan-bas h2 { font-size: 14px; font-weight: 600; }

/* TUTAMAÇLAR. Sag-yasli pencerede yalniz SOL kenar (genislik), serbest
   pencerede yalniz SAG-ALT kose (iki eksen) — §1.2. Ikisi de ayni sinifi
   paylasiyor ki hap durumunda tek satirla kalksinlar (yukarida). */
.asistan-tutamac { position: absolute; z-index: 1; touch-action: none; }
.asistan-tutamac-en {
  inset: 0 auto 0 0; width: var(--s3); cursor: ew-resize;
}
.asistan-tutamac-kose {
  right: 0; bottom: 0; width: var(--s4); height: var(--s4);
  cursor: nwse-resize; display: none;
}
dialog#asistanDlg.konum-serbest .asistan-tutamac-en { display: none; }
dialog#asistanDlg.konum-serbest .asistan-tutamac-kose { display: block; }
/* Kose tutamaci GORUNUR olmali: gorunmeyen bir tutamac, kullanicinin
   kesfetmek zorunda kaldigi bir jesttir (§1.1'in ayni gerekcesi). */
.asistan-tutamac-kose::after {
  content: ''; position: absolute; right: var(--s1); bottom: var(--s1);
  width: var(--s2); height: var(--s2);
  border-right: 2px solid var(--line-field); border-bottom: 2px solid var(--line-field);
}
/* Serbest pencerede baslik seridi surukleme tutamaci (§1.2). */
dialog#asistanDlg.konum-serbest .asistan-bas-satir { cursor: grab; }
dialog#asistanDlg.konum-serbest.tasiniyor .asistan-bas-satir { cursor: grabbing; }
/* Sag-yasli pencerede de baslik seridinden SOLA sürükleyerek ayrilinabiliyor;
   imlec bunu soylemezse jest kesfedilmez. */
dialog#asistanDlg.konum-sag .asistan-bas-satir { cursor: grab; }
/* Tasima/boyutlandirma sirasinda gecis animasyonu YOK: her kare JS'ten
   geliyor, ustune bir gecis eklemek imlecin arkasinda kalan bir pencere
   cizerdi. */
dialog#asistanDlg.tasiniyor { transition: none; user-select: none; }

/* Panelde genel bir `.btn svg` kurali YOK (simgeler bugune kadar hep bir
   kabin icindeydi); asistan dugmeleri icin burada kapsamli tanimlaniyor.
   Genel bir kural yazmak, 60 dugmeyi olcmeden degistirmek olurdu. */
#asistanAc svg, #asistanKapat svg, #asistanGonder svg, #asistanMik svg,
#asistanSabitle svg, #asistanKucult svg, .asistan-bas-ico svg {
  width: 20px; height: 20px; display: block;
}

/* Baslik seridi — altinda cizgi, akisla kaymiyor. */
.asistan-bas {
  flex: none; padding: var(--s4) var(--s6);
  border-bottom: 1px solid var(--line); background: var(--surface);
}
.asistan-bas-satir { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); }
.asistan-bas h2 { margin: 0; font-size: 18px; font-weight: 700; }
/* Pencere kontrolleri (sabitle/serbest bırak · küçült · kapat) TEK grupta:
   baslikla aralarindaki bosluk `space-between`den, kendi aralarindakiler
   buradan. Ucu ayri ayri dagilirsa "kapat"in yeri pencere durumuna gore
   kayardi. */
.asistan-bas-dugmeler { display: flex; align-items: center; gap: var(--s1); flex: none; }
/* Baslik simgesi YALNIZ hap durumunda gorunur (yukarida acilir): genis
   pencerede baslik zaten "Asistan" yaziyor, simge ikinci bir kez soylerdi. */
.asistan-bas-ico { display: none; color: var(--ink-2); align-items: center; flex: none; }
.asistan-bas-sol { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
/* DURUST CUMLE. Kullanici ilk harfi yazmadan ONCE goruyor; mesaj
   yazildiktan sonra bir yere gomulmuyor (S16'nin urune yansiyan sozu). */
.asistan-not { margin: var(--s2) 0 0; font-size: 13px; color: var(--ink-3); }

/* Mesaj listesi. */
.asistan-akis {
  flex: 1; overflow-y: auto; padding: var(--s4) var(--s5);
  display: flex; flex-direction: column; gap: var(--s3);
}

/* IKI BALON AYNI RENK AILESINDE. Ayrim renkte DEGIL hizada + kenarlikta:
   kullanici balonu "kart" (kenarlikli), asistan balonu "gomulu" (duz zemin).
   Klise mavi-baloncuk YOK ve `--accent` burada harcanmiyor — accent zaten
   kahraman kartin kimligi; ikinci bir yerde tekrarlanirsa o kartin tekligi
   zayiflar. */
.asistan-balon {
  max-width: 85%; padding: var(--s3) var(--s4);
  border-radius: var(--radius-hero); font-size: 14px; line-height: 1.5;
  color: var(--ink); white-space: pre-wrap; overflow-wrap: anywhere;
}
.asistan-balon.bot {
  align-self: flex-start; background: var(--surface-2); border: 1px solid transparent;
  border-bottom-left-radius: var(--radius-sm);
}
/* KENARLIK `--line` DEGIL `--line-2` — GOZLE OLCULDU (G-16, 1. tur).
   Cekmecenin zemini `--surface` (beyaz) ve kullanici balonu da `--surface`;
   ayrimi TASIYAN tek sey kenarlik. `--line` acik temada #f1f5f9, yani beyazin
   uzerinde neredeyse gorunmuyordu ve balon "kart" degil bosluga yazilmis bir
   cumle gibi duruyordu — tarifin "kullanici balonu KART, asistan balonu
   GOMULU" ayrimi tam da bu kenarlikta yasiyor. `--line-2` var olan bir
   belirtec (kategori kartinin uzerine gelme kenarligi), iki temada da bir
   kademe daha guclu. Yeni deger uretilmedi. */
.asistan-balon.ben {
  align-self: flex-end; background: var(--surface); border: 1px solid var(--line-2);
  border-bottom-right-radius: var(--radius-sm);
}
/* "Yaziyor…" — ayri bir bilesen DEGIL, asistan balonunun soluk hali.
   MVP'de nabiz/parilti animasyonu YOK (CEO karari 2 ve 4): yeni bir spinner
   ailesi acmak, tek bir durum icin projenin ilk donen carkini getirmekti. */
.asistan-balon.bekle { color: var(--ink-3); }

/* Bos durum — ortalanmis kucuk blok. */
.asistan-bos {
  margin: auto; text-align: center; display: grid; gap: var(--s3);
  justify-items: center; padding: var(--s6) var(--s4);
}
.asistan-bos-ico {
  width: 48px; height: 48px; border-radius: var(--radius-pill);
  background: var(--surface-2); color: var(--ink-2);
  display: inline-flex; align-items: center; justify-content: center;
}
.asistan-bos-ico svg { width: 24px; height: 24px; }
.asistan-bos p { margin: 0; font-size: 14px; color: var(--ink-3); }

/* NIYET KARTI — konusma balonu DEGIL duz kart: bu bir cumle degil bir OZET
   NESNESI. Kap, urunun her yerdeki kart kalibi. */
.asistan-kart {
  align-self: stretch; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); box-shadow: var(--shadow); padding: var(--s4);
}
.asistan-kart-bas {
  font-size: 12px; font-weight: 600; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 var(--s3);
}
.asistan-kart dl { margin: 0; }
.asistan-kart-satir { display: flex; gap: var(--s4); align-items: baseline; margin-bottom: var(--s2); }
/* Etiket BUYUK HARF DEGIL: "Kim/Ne zaman/Hizmet" zaten taranabilir kisa
   Turkce kelimeler; buyuk harf israri burada okunabilirligi dusururdu.
   Yalniz ustteki "ONAY BEKLIYOR" basligi buyuk harf kalibini tasiyor. */
.asistan-kart-satir dt { flex: 0 0 92px; font-size: 12px; color: var(--ink-3); margin: 0; }
.asistan-kart-satir dd { flex: 1; font-size: 14px; font-weight: 600; color: var(--ink); margin: 0; }
.asistan-kart-ayrac { border-top: 1px solid var(--line); margin: var(--s3) 0; }
/* Durum hapi ICAT EDILMEDI: randevu durumunu gosteren `.pill` ailesi oldugu
   gibi kullaniliyor (CEO karari 1). Yeni bir hap stili, ayni kavramin
   panelde iki gorsel diline sahip olmasi demekti. */
.asistan-kart .btn-row { margin-top: var(--s4); }
/* I-081 — onay kartinin zorunlu alan hatasi. Toast DEGIL: duzeltilecek yer
   neresiyse cumle orada durmali (`.err`in ayni rengi, kart ritmi). */
.gonay-hata { color: var(--danger); font-size: 13px; margin: var(--s2) 0 0; }
/* Onay sonrasi: YENI kart acilmiyor, ayni kart mutasyona ugruyor. Kart kabi
   rengi DEGISMIYOR — kutlama efekti yok, sakin bir durum degisimi. */
.asistan-kart-sonuc { margin: var(--s4) 0 0; font-size: 14px; color: var(--ink-2); }
/* Metinde `--ok` DEGIL `--ok-ink`: `--ok` yalniz grafik/simge esigi (3:1)
   icin guvenli; bu bir CUMLE (admin.css'in kendi olcum notu). */
.asistan-kart-sonuc b { color: var(--ok-ink); }
/* Vazgecilen kart SILINMIYOR — sohbet akisinda iz kaliyor. */
.asistan-kart.dustu { opacity: 0.6; transition: opacity var(--dur-1) var(--ease-out); }

/* MIKROFON — DORT DURUM, SIFIR YENI DEGER (H9 / Faz 6a).
 *
 * Dugmenin kendisi `.btn.icon` (40px, ayni kalip). Durum sinifini `admin.js`
 * yaziyor; renkler mevcut jetonlardan geliyor ve HICBIRI kirmizi degil —
 * `--danger` bu urunde "hata/tehlike", "kayit" degil (tarif §5). Kirmizi bir
 * mikrofon, isletmecinin bir seyi bozdugunu sandigi tek gorsel olurdu.
 *
 * NABIZ ANIMASYONU YOK (Melih karari, Faz 6a): dinleme hali DOLU dugmeyle
 * isaretleniyor — `.btn.primary`nin AYNI degerleri. Dolu/bos ayrimi, nabizdan
 * daha guclu ve hareket hassasiyeti olan kullaniciya bir sey borclu degil.
 * SPINNER DA YOK: "ceviriyor" hali soluk + PASIF dugme (tarif §8/2'nin actigi
 * karar, "Yaziyor…" icin verilen kararla ayni aile — projenin ilk donen carki
 * tek bir gecis icin acilmadi). Dort durumu ayirt eden asil sey renk degil,
 * `aria-label`: her durumda ayri bir cumle. */
.asistan-mik { flex: none; color: var(--ink-2); }
.asistan-mik.dinliyor {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.asistan-mik.dinliyor:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.asistan-mik.ceviriyor { color: var(--ink-3); cursor: default; }
.asistan-mik.ceviriyor:hover { background: var(--surface); }
.asistan-mik.seslendiriyor { color: var(--ink-2); border-color: var(--line-2); }

/* ELLER SERBEST CIPI (Faz 6b) — OTURUM DUZEYI GOSTERGE.
 *
 * TEK ELEMAN, IKI HAL: kapaliyken davet ("Eller serbest"), acikken KALICI
 * gosterge ("Eller serbest açık"). Ayri bir "ac" dugmesi + ayri bir cip
 * olsaydi kapatma dokunusu ikinci bir yere duserdi; mod tek dokunusla
 * acilip tek dokunusla kapanmali.
 *
 * `.btn.tiny` mevcut hap kalibinin ta kendisi (sihirbaz haplariyla ayni) —
 * yeni bir dugme boyu YOK. Acik hali `--ok` ailesinde: yesil "acik/calisiyor"
 * demek, `--accent` ise kahraman kartin kimligi ve ikinci bir yerde
 * harcanamaz. KIRMIZI YOK — bu bir hata degil bir hal.
 *
 * ZEMIN DEGISMIYOR (`--ok-soft` DEGIL): metin `--ok-ink`, kenarlik `--ok`.
 * Yumusak yesil bir zemin, mobilde karsiligi olmayan bir jeton isterdi
 * (`palette.dart` bu gorevin disinda) ve iki yuzey ayni bileseni iki farkli
 * doygunlukta gosterirdi. */
.asistan-eller {
  flex: none; align-self: flex-start;
  margin: var(--s3) var(--s4) 0;
}
.asistan-eller.acik { color: var(--ok-ink); border-color: var(--ok); }
.asistan-eller.acik:hover { border-color: var(--ok-ink); }

/* SES NOTU — tek seferlik durust cumle ve izin reddi. `.asistan-not`
   (baslik seridindeki "Sohbet gecmisi kaydedilmez.") ile AYNI olcu/renk:
   ikisi de ayni sinifta bir soz, iki farkli gorsel dil kazanmasinlar. */
.asistan-ses-not {
  flex: none; margin: 0; padding: var(--s3) var(--s4) 0;
  font-size: 13px; color: var(--ink-3); background: var(--surface);
}

/* Giris cubugu. Mikrofon (varsa) BU satirin ilk elemani; desteklenmeyen
   tarayicida DOM'a hic girmiyor ve satir [metin][gonder] ikilisine dusuyor. */
.asistan-giris {
  flex: none; display: flex; gap: var(--s2); align-items: center;
  padding: var(--s4); border-top: 1px solid var(--line); background: var(--surface);
}
/* `dialog input` kurali `width:100%` + `margin-top` veriyor; satir icinde
   ikisi de yanlis. Sinifi gevsetmek yerine burada KAPSAMLI eziliyor. */
.asistan-giris input {
  flex: 1; width: auto; margin-top: 0;
  border: 1px solid var(--line-field); border-radius: var(--radius);
  font-size: 14px; padding: var(--s3);
}
.asistan-giris .btn.icon { flex: none; }

/* ================================ KURULUM SIHIRBAZI (H9 / Faz 5)
 *
 * Yeni JETON YOK (S3): asagidaki her deger mevcut degiskenlerden geliyor
 * (`--accent`, `--line`, `--surface`, `--s*`, `--radius*`). Sihirbaz gorsel
 * olarak yeni bir dil DEGIL — sohbetin ustune ince bir serit ve mevcut
 * `.btn.tiny` hap dugmeleri.
 *
 * ⚠ BU BLOK NIYE BURADA, `.asistan-mik` ILE `.asistan-giris` ARASINDA DEGIL.
 * `asistan-ses.test.js` mikrofon kurallarini KONUMLA suzuyor: `.asistan-mik {`
 * ile `.asistan-giris {` ARASINI okuyup icinde `--danger` aramiyor (kirmizi
 * bir mikrofon "bir sey bozdum" demek olurdu). Blok ilk yazimda o pencereye
 * dusmustu ve `.asistan-balon.hata` kuralindaki `--danger` yuzunden ses
 * testini KIRDI — kusur ses tarafinda degil, pencerede. Testi gevsetmek
 * yerine blok pencerenin DISINA alindi: kapinin olctugu sey degismedi.
 */

/* ADIM SERIDI — alti nokta, mesaj listesinin ustunde SABIT (ui-ux §6).
   `sticky` cunku akis uzadikca "kacinci adimdayim" sorusu kaybolmamali;
   ayri bir baslik cubugu acmak cekmecenin dikey butcesini yerdi. */
.asistan-serit {
  position: sticky; top: 0; z-index: 1; align-self: stretch;
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s2) 0 var(--s3); background: var(--surface);
}
.asistan-serit .asistan-nokta {
  flex: 1 1 0; height: 3px; border-radius: var(--radius-pill); background: var(--line);
}
/* Tamamlanan/aktif adimlar vurgulu. Nokta DEGIL CUBUK: alti daire 320
   piksellik bir cekmecede birbirine girer, esit bolunmus cubuk hem
   "kacinci" hem "ne kadar kaldi" sorusunu ayni anda cevapliyor. */
.asistan-serit .asistan-nokta.dolu { background: var(--accent); }

/* HAP SATIRI — mevcut `.btn.tiny` ailesi; yeni dugme boyu YOK. */
.asistan-haplar {
  align-self: stretch; display: flex; flex-wrap: wrap; gap: var(--s2);
  margin-top: calc(var(--s2) * -1);
}

/* DUZELTME ALANLARI — sohbet akisinin icinde, modal DEGIL (ui-ux §6). */
.asistan-alanlar {
  align-self: stretch; display: grid; gap: var(--s3);
  padding: var(--s4); border: 1px solid var(--line);
  border-radius: var(--radius-hero); background: var(--surface-2);
}
.asistan-alan { display: grid; gap: var(--s1); font-size: 12px; color: var(--ink-3); }
.asistan-alanlar input, .asistan-alanlar select {
  width: 100%; margin-top: 0; font-size: 14px; padding: var(--s3);
  border: 1px solid var(--line-field); border-radius: var(--radius);
  background: var(--surface); color: var(--ink);
}
/* Onay kutusu satiri esnemesin: `width:100%` bir checkbox'i ekran genisligi
   kadar buyutuyordu (`dialog input` kuralinin yan etkisi). */
.asistan-alanlar input[type="checkbox"] { width: auto; justify-self: start; }
.asistan-alanlar .btn-row { margin-top: var(--s2); }

/* HATA BALONU — yeni renk yok, mevcut `--danger` ailesi. */
.asistan-balon.hata { background: var(--danger-soft); color: var(--danger); }

/* ANA EKRAN DAVET SATIRI — kategori kartiyla AYNI kap. Round-pill arama
   cubugu DEGIL: arama motoru klisesi + ekrandaki diger kartlarla ritim
   uyusmazligi. Kutucuk degil; kategori izgarasinin bir hucresi degil. */
.asistan-sor {
  display: flex; align-items: center; gap: var(--s4); width: 100%; text-align: left;
  margin: 0 0 var(--s8); padding: var(--s4) var(--s5);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--radius-hero);
  box-shadow: var(--shadow); cursor: pointer; font: inherit;
}
.asistan-sor:hover { border-color: var(--line-2); }
.asistan-sor:active { transform: scale(0.985); box-shadow: var(--shadow-press); }
.asistan-sor:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Simge CIPLAK durur — pastel kutusu YOK. Alti kategorinin her biri kendi
   `--cat-*-box` kutusunu tasiyor; asistan o ailenin uyesi degil ve bu ayrim
   "bu yedinci bir kategori mi?" tereddudunu simge seviyesinde onluyor. */
.asistan-sor-ico { flex: none; color: var(--ink-3); display: inline-flex; }
.asistan-sor-ico svg { width: 20px; height: 20px; }
.asistan-sor-txt {
  flex: 1; min-width: 0; font-size: 14px; color: var(--ink-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.asistan-sor-ok { flex: none; color: var(--ink-3); display: inline-flex; }
.asistan-sor-ok svg { width: 16px; height: 16px; }

/* ================== U1 — BEKLEYEN ONAY + DINLEME GOSTERGESI (spec §1.7) ====
 *
 * ⚠ BU BLOK NIYE BURADA, `.asistan-mik`/`.asistan-eller` KURALLARININ ARASINDA
 * DEGIL. `asistan-ses.test.js` ses kurallarini KONUMLA suzuyor: `.asistan-mik {`
 * ile `.asistan-giris {` arasini ve `.asistan-eller {` ile `.asistan-ses-not {`
 * arasini okuyup icinde `--danger`/`--accent`/`animation` ariyor. Asagidaki
 * nabiz animasyonu o araliklardan BIRINE dusseydi, ses testi bu turla hicbir
 * ilgisi olmayan bir gerekceyle kirilirdi (`.asistan-serit` blogunun basindaki
 * ayni tuzagin kaydi). Konum bir uslup tercihi degil, bir KAPI.
 */

/* Bekleyen onay rozeti — YALNIZ hap durumunda. Pencere aciksa kart zaten
   akista gorunuyor (ve gormuyorsa serit uyariyor, asagida); hapta ekranda
   kartin TEK izi bu nokta. */
.asistan-rozet {
  display: none; flex: none;
  width: var(--s2); height: var(--s2);
  border-radius: var(--radius-pill); background: var(--accent);
}
dialog#asistanDlg.hap.kart-bekliyor .asistan-rozet { display: block; }

/* DINLEME GOSTERGESI — pencere durumundan BAGIMSIZ (§1.7d). Mikrofon dugmesi
   hapta gizli, `dinliyor` glifi de onunla birlikte kayboluyordu; kullanici
   "hala dinliyor mu" sorusunu HER durumda ekrandan cevaplayabilmeli. */
.asistan-isik {
  display: none; flex: none; align-items: center; gap: var(--s1);
  font-size: 12px; color: var(--ink-3);
}
dialog#asistanDlg.ses-dinliyor .asistan-isik { display: inline-flex; }
.asistan-isik::before {
  content: ''; width: var(--s2); height: var(--s2);
  border-radius: var(--radius-pill); background: var(--accent);
  animation: asistan-nabiz 1.4s var(--ease-out) infinite;
}
/* "Yaziyor…" balonunda nabiz YASAKTI (CEO karari 2 ve 4) ve bu onunla
   CELISMIYOR: orada animasyon bir BEKLEMEYI susleyecekti, burada acik bir
   mikrofonun canli oldugunu soyluyor — susarsa kullanici dinlendigini
   bilemez. */
@keyframes asistan-nabiz { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }
@media (prefers-reduced-motion: reduce) {
  .asistan-isik::before { animation: none; }
}

/* "BEKLEYEN ONAY VAR ↓" SERIDI (§1.7b). Kullanici yukari kaydirip gecmisi
   okuyorsa akis ZORLA en alta atilmiyor; onun yerine akisin altinda ince bir
   serit beliriyor. Slack/iMessage'in "yeni mesaj" kalibi: gorunurlugu
   garanti eder, kaydirmayi calmaz. */
.asistan-onay-serit {
  flex: none; margin: 0; width: 100%; text-align: left;
  padding: var(--s2) var(--s5);
  border: 0; border-top: 1px solid var(--line);
  background: var(--surface-2); color: var(--ink-2);
  font: inherit; font-size: 13px; font-weight: 600; cursor: pointer;
}
.asistan-onay-serit:hover { background: var(--surface-3); }
.asistan-onay-serit:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* KAPATMA KORUMASI (§1.7b) — bekleyen onay varken (×)/Esc hemen kapatmiyor,
   tek satirlik bir onay cikiyor. Ayri bir dialog DEGIL: pencerenin icinde
   duran bir satir, cunku kapatilmak uzere olan seyin USTUNDE bir kat daha
   acmak, kullanicinin kacmaya calistigi yigina bir kat eklemek olurdu. */
.asistan-kapat-onay {
  flex: none; display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  padding: var(--s3) var(--s5);
  /* ⚠ ZEMIN `--surface-2`, `--danger-soft` DEGIL — OLCULDU. Ilk surumde serit
     `--danger-soft` tasiyordu; `.btn.danger`in zemini de AYNI belirtec, yani
     "Onay iptal olur" dugmesi kendi zeminine karisip cerceve siz bir BAGLANTI
     gibi okundu (koyu temada acikca goruldu). Serit notr kaliyor, tehlike
     rengini yalniz dugme tasiyor — hiyerarsi de zaten bu: bu bir HATA degil
     bir SORU. */
  border-top: 1px solid var(--line); background: var(--surface-2);
  font-size: 13px; color: var(--ink);
}
.asistan-kapat-onay p { margin: 0; flex: 1; min-width: 0; }
.asistan-kapat-onay .btn-row { margin: 0; flex: none; }

@media (max-width: 720px) {
  /* Dar ekranda `min()` cekmeceyi zaten tam ekran yapiyor; kose
     yuvarlakligi kenarda anlamsiz kaliyor. */
  dialog#asistanDlg { border-radius: 0; }
  /* DAR EKRAN TAVANI (§1.2): serbest pencere ve boyutlandirma KAPALI —
     telefon genisliginde "tasinabilir pencere" kavraminin fiziksel karsiligi
     yok, mobilin tam-sayfa modeliyle ortusen tek dogru bicim tam-ekran
     saga-yasli. Bayragi JS de bu ozellikten okuyor (ustteki blok). */
  dialog#asistanDlg { --asistan-dar: 1; --asistan-genislik: 100vw; }
  dialog#asistanDlg.konum-serbest {
    inset: 0 0 0 auto; top: auto; left: auto;
    width: 100vw; height: 100dvh; border-radius: 0;
  }
  .asistan-tutamac { display: none; }
}

/* ==========================================================================
   U2 — SAATLER & KURALLAR: TEK SEVİYELİ BAŞLIK LİSTESİ + TAM EKRAN DEVRALMA
   (tasarım spec §2.2-2.3, §2.6)

   Dosyanın SONUNA eklendi (ortasına değil): panelin CSS'i paralel turlarda
   dokunulan bir dosya ve iki ajanın aynı satırlarda buluşması, ürünün
   kendisinden pahalı bir çakışma çözümü demek olurdu.

   ÖLÇÜLER SATIR KALIBININ AYNISI (`.cat-row`, spec §7.1): 72px satır, 16px
   iç dolgu, satır arası 1px saç çizgisi. Yeni bir liste dili ICAT EDILMEDI —
   kullanıcı kategori satırlarını zaten tanıyor ve iki liste birbirine
   benzemezse "aynı ürün mü" sorusu doğuyor. Fark tek: ÖZET SAĞDA (kategori
   satırında açıklama adın ALTINDA); çünkü buradaki özet bir açıklama değil
   bir DEĞER ("Pzt–Cum 09:00–19:00"), ve değerler hizalanınca taranabiliyor.

   HAM DEĞER YOK: her renk/ölçü mevcut değişkenlerden (S3).
   ========================================================================== */

.kural-liste, .kural-devral { max-width: 820px; }

/* KOLTUK BİLGİ ÇUBUĞU (U3 · spec §2.5 · Melih kararı K4+K7).
   On dört başlığın da ÜSTÜNDE ve bir liste satırı GİBİ GÖRÜNMÜYOR: kartın
   kendi zemini (`--surface`) yerine ince bir bilgi şeridi (`--surface-2`,
   çerçevesiz) — çünkü tıklanamaz bir satırın tıklanabilirlerle aynı görünmesi,
   kullanıcıyı ölü bir satıra tıklamaya davet eder. Chevron da yok, aynı sebep.
   HAM DEĞER YOK: her renk/ölçü mevcut değişkenlerden (S3). */
.koltuk-cubuk {
  display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap;
  margin: 0 0 var(--s3); padding: 10px var(--s4);
  background: var(--surface-2); border-radius: var(--radius-sm);
  font-size: 14px; line-height: 20px; color: var(--ink-2);
}
.koltuk-cubuk-metin { flex: 1 1 auto; min-width: 0; }
.koltuk-cubuk button { flex: 0 0 auto; color: var(--ink-2); }
.koltuk-cubuk button svg { width: 16px; height: 16px; flex: none; color: var(--ink-3); }

.kural-rows {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-hero); box-shadow: var(--shadow);
  padding: var(--s2) 0; overflow: hidden;
}
.kural-row {
  position: relative;
  display: flex; align-items: center; gap: var(--s3); width: 100%;
  min-height: 72px; padding: var(--s3) var(--s4);
  text-align: left; font: inherit; color: var(--ink);
  background: none; border: 0; cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out);
}
/* Saç çizgisi `border-bottom` yerine `::before`: 16px girinti border'la
   yapılamıyor ve son satırda çizgi kalmamalı (`.cat-row` ile aynı çözüm). */
.kural-row + .kural-row::before {
  content: ''; position: absolute; left: var(--s4); right: 0; top: 0;
  border-top: 1px solid var(--line-2);
}
.kural-row:hover { background: var(--surface-2); }
.kural-row:active { background: var(--surface-3); }
.kural-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.kural-row-ad { flex: 1 1 auto; min-width: 0; font-size: 16px; font-weight: 600; line-height: 20px; }
/* ÖZET TAŞMAZ, KISALIR. Yedi günlük saat özeti dar ekranda satırı ikiye
   bölerdi ve liste "her satır aynı yükseklikte" ritmini kaybederdi. */
.kural-row-ozet {
  flex: 0 1 auto; min-width: 0; max-width: 46%;
  font-size: 14px; font-weight: 400; line-height: 20px; color: var(--ink-3);
  text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kural-row-chev { flex: 0 0 auto; color: var(--ink-3); display: inline-flex; }
.kural-row-chev svg { width: 16px; height: 16px; display: block; }

/* GERİ SATIRI. Görsel olarak panelin kırıntısının (`.fn-crumb`) aynısı ama
   AYRI BİR SINIF: `renderCrumb` panelin kendi kırıntısını `.fn-crumb` ile
   arayıp SİLİYOR; aynı sınıfı taşısaydı işlev ekranı her açılışta bu satır
   da silinirdi. */
.kural-geri {
  display: flex; align-items: center; gap: var(--s2);
  margin: 0 0 var(--s5); font-size: 13px; color: var(--ink-3);
}
.kural-geri button {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0 var(--s3) 0 10px; height: 32px; border-radius: var(--radius-pill);
  background: var(--surface-2); border: 0;
  color: var(--ink-2); font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
  transition: background-color var(--dur-1) var(--ease-out),
    color var(--dur-1) var(--ease-out),
    transform 90ms var(--ease-out);
}
.kural-geri button:hover { background: var(--surface-3); color: var(--ink); }
.kural-geri button:active { transform: scale(0.985); }
.kural-geri button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kural-geri button svg { width: 14px; height: 14px; }
.kural-geri b { color: var(--ink); font-weight: 600; }

.kural-bolum > h2 { margin-top: 0; }
.kural-bolum .card-sub { margin-top: var(--s6); }

/* ASİSTANA DEVRET SATIRI (§2.6 — K7 gereği ZORUNLU, her başlıkta).
   Açıklama cümlesinin ALTINDA, forma girmeden ÖNCE duruyor: kullanıcı
   alanları doldurmaya başladıktan sonra gösterilen bir "bunu asistan da
   yapabilirdi" satırı, yapılmış işi boşa çıkarmış gibi okunur. */
.kural-devret { margin: var(--s4) 0 var(--s5); }
.kural-devret button {
  display: inline-flex; align-items: center; gap: var(--s2);
  max-width: 100%; text-align: left; white-space: normal; height: auto;
  min-height: 32px; padding: 6px var(--s3);
  color: var(--ink-2);
}
.kural-devret button svg { width: 16px; height: 16px; flex: none; color: var(--ink-3); }

@media (max-width: 640px) {
  /* Dar ekranda değer adın ALTINA iniyor: 390 pikselde başlık ve özet yan
     yana sığmıyordu ve özet "…" olup hiçbir şey söylemiyordu — kısaltılmış
     bir değer, olmayan bir değerden kötüdür. */
  .kural-row { align-items: flex-start; flex-wrap: wrap; }
  .kural-row-ad { flex: 1 1 100%; }
  .kural-row-ozet { flex: 1 1 100%; max-width: 100%; text-align: left; }
  .kural-row-chev { position: absolute; right: var(--s4); top: 50%; transform: translateY(-50%); }
}
