İSG Risk Analizi – ETA (Olay Ağacı Analizi)

1. Uygulamanın Amacı

ETA (Event Tree Analysis – Olay Ağacı Analizi), bir başlangıç olayının meydana gelmesinden sonra güvenlik sistemlerinin, koruyucu önlemlerin ve müdahale mekanizmalarının başarılı veya başarısız olması durumunda ortaya çıkabilecek sonuçları sistematik olarak değerlendiren bir risk analizi yöntemidir.

Risk UI – ETA Masaüstü HTML Uygulaması, bu analiz yönteminin bilgisayar ortamında uygulanması, sonuç senaryolarının hesaplanması, görsel olay ağacının oluşturulması ve analizlerin kayıt altına alınması amacıyla geliştirilmiştir.

Uygulama; özellikle yangın, patlama, kimyasal sızıntı, ekipman arızası, proses kazaları ve diğer endüstriyel olaylarda kullanılabilir.

HTML tabanlı olması sayesinde bilgisayara ayrıca program kurulmasına gerek kalmadan internet tarayıcısı üzerinden çalıştırılabilir. İnternet bağlantısı gerektirmez. Analiz verileri Excel dosyası olarak bilgisayara kaydedilebilir ve daha sonra yeniden uygulamaya aktarılabilir.

2. Formun Genel Yapısı

ETA formu, birbirini tamamlayan altı ana bölümden oluşmaktadır. Bu bölümler; başlangıç olayının tanımlanmasından analiz sonuçlarının değerlendirilmesine kadar bütün süreci kapsar.

01 – Analiz ve Başlangıç Olayı Bilgileri

Bu bölümde analiz çalışmasına ilişkin temel bilgiler ve incelenecek başlangıç olayı tanımlanır. Analiz/doküman numarası, analiz tarihi, tesis veya birim adı, analizi hazırlayan kişi, olay türü, proses veya faaliyet, başlangıç olayının yıllık sıklığı ve revizyon bilgileri doldurulur.

Başlangıç Olayı alanına, analiz edilmek istenen olay açık ve anlaşılır şekilde yazılır. Örneğin, bir üretim tesisinde yanıcı madde sızıntısı sonucunda yangın başlaması.

Kapsam, Varsayımlar ve Sınırlar alanında ise analizin hangi sistemleri ve koşulları kapsadığı, kullanılan verilerin dayanakları ve değerlendirme dışı bırakılan durumlar belirtilir.

Başlangıç olayı sıklığı, olay/yıl birimiyle girilmelidir. Örneğin 0,1 olay/yıl, başlangıç olayının uzun dönem ortalamasında yaklaşık 10 yılda bir meydana gelmesi beklentisini ifade eder. Bu değer mümkün olduğunca olay kayıtları, güvenilirlik verileri veya teknik değerlendirmelerle desteklenmelidir.

3. Güvenlik Bariyerlerinin Tanımlanması

02 – Güvenlik Bariyerleri / Olay Dalları bölümünde, başlangıç olayının sonuçlarını önlemek veya etkilerini azaltmak için kullanılan güvenlik tedbirleri tanımlanır.

Formdaki Bariyer Ekle seçeneği kullanılarak yeni güvenlik bariyerleri oluşturulur. Her bariyer için adı, çalışma veya başarı kriteri, başarı olasılığı ve veri kaynağı bilgileri girilir.

Örneğin, yangın olayında otomatik yangın algılama sistemi, acil durdurma sistemi ve otomatik söndürme sistemi ayrı güvenlik bariyerleri olarak değerlendirilebilir.

Bariyerin başarı olasılığı yüzde olarak girilir. Başarı olasılığı %90 olan bir güvenlik bariyerinin başarısızlık olasılığı uygulama tarafından otomatik olarak %10 hesaplanır.

Bariyerlerin olay sonrasında devreye girme sırasına göre düzenlenmesi önemlidir. Uygulama en fazla 6 güvenlik bariyeri tanımlanmasına izin verir. Bu durumda 64 farklı sonuç senaryosu oluşturulabilir.

Girilen başarı oranlarının gerçek sistem performansını temsil etmesi ve teknik verilerle doğrulanması gerekir.

4. Olay Ağacı Diyagramının Oluşturulması

03 – Olay Ağacı Diyagramı bölümünde, tanımlanan güvenlik bariyerlerine bağlı olarak olası sonuç yolları otomatik oluşturulur. Her güvenlik bariyeri iki temel duruma ayrılır: başarılı çalışma ve başarısız çalışma.

Örneğin iki güvenlik bariyeri tanımlandığında dört farklı sonuç yolu oluşur. Üç bariyer tanımlandığında ise sekiz farklı senaryo değerlendirilir.

Diyagram sayesinde başlangıç olayından itibaren hangi güvenlik önlemlerinin çalıştığı, hangilerinin başarısız olduğu ve olayın hangi sonuçlara ilerleyebileceği görsel olarak incelenebilir.

Başarılı ve başarısız dallar farklı renklerle gösterilir. Diyagram, gerektiğinde yatay veya dikey kaydırılarak incelenebilir. Bu bölümde hesaplanan olasılıklar, bariyerlerin başarı veya başarısızlık olasılıklarının ilgili sonuç yolu boyunca çarpılmasıyla elde edilir.


5. Sonuç Senaryolarının Değerlendirilmesi

04 – Sonuç Senaryoları ve Kontrol Aksiyonları bölümünde olay ağacındaki her sonuç yolu ayrı ayrı değerlendirilir.

Uygulama, senaryo kodunu, bariyerlerin başarı ve başarısızlık durumlarını, yol olasılığını ve gerekli veriler girilmişse yıllık sonuç sıklığını otomatik hesaplar.

Kullanıcının her senaryo için Sonuç Sınıfı, Muhtemel Sonuç / Etki, Düzeltici / Önleyici Aksiyon, Sorumlu ve Hedef Tarih alanlarını doldurması gerekir.

Sonuç sınıfları beş seviyede değerlendirilir:

SeviyeSonuç sınıfı
0Etki yok / Güvenli
1Düşük etki
2Orta etki
3Ciddi etki
4Kritik / Felaket

Örneğin, yangın algılama ve söndürme sistemlerinin başarılı olduğu bir senaryo sınırlı hasarla sonuçlanabilirken, her iki sistemin de başarısız olduğu başka bir senaryo ciddi yaralanmalara, tesis hasarına veya üretim kaybına yol açabilir.

Bu nedenle her sonuç yolunun etkisi kendi koşulları içerisinde değerlendirilmelidir. Alınması gereken ek tedbirler açık, uygulanabilir ve takip edilebilir şekilde yazılmalıdır. Aksiyon sorumluları ve hedef tamamlanma tarihleri belirlenmelidir.

6. Değerlendirme, Karar ve Onay

05 – Değerlendirme, Karar ve Onay bölümünde analizden elde edilen bulgular değerlendirilerek genel karar oluşturulur.

Değerlendirme Kararı alanında mevcut önlemlerin kabul edilebilir olması, ek iyileştirme gerekliliği, ilave analiz ihtiyacı veya faaliyetin durdurularak yeniden tasarlanması gibi seçeneklerden uygun olanı seçilir.

Kontrol / Gözden Geçiren ve Onaylayan alanlarına ilgili kişilerin adları ve unvanları yazılır.

Genel Bulgular / Aksiyon Planı / Belirsizlikler alanında ise analiz sonucunda tespit edilen önemli tehlikeler, öncelikli tedbirler, veri eksiklikleri ve izlenecek çalışmalar açıklanır.

Onay işlemi, kurumun yetkilendirme ve doküman kontrol prosedürlerine uygun yürütülmelidir. Formda isim bulunması, tek başına resmî onayın tamamlandığı anlamına gelmez.

7. ETA Hesaplama Yöntemi

06 – ETA Hesaplama Yöntemi ve Kullanım Notları bölümünde uygulamanın kullandığı hesaplama yaklaşımı açıklanır.

Bir sonuç yolunun koşullu olasılığı, o yol üzerindeki başarılı veya başarısız bariyer dallarının olasılıklarının çarpılmasıyla hesaplanır.

Sonuç yolunun yıllık sıklığı = Başlangıç olayının yıllık sıklığı × Sonuç yolunun koşullu olasılığı

Örneğin, başlangıç olayı sıklığı 0,1 olay/yıl, birinci güvenlik bariyerinin başarı olasılığı %90 ve ikinci bariyerin başarı olasılığı %80 olsun.

Her iki bariyerin de başarılı olduğu sonuç yolunun koşullu olasılığı:
0,90 × 0,80 = 0,72 (%72)
Bu yolun yıllık sonuç sıklığı:
0,1 × 0,72 = 0,072 olay/yıl
olarak hesaplanır.

Bu örnek, uygulamanın kullandığı basitleştirilmiş hesaplama yaklaşımını göstermektedir. Bariyerler arasında bağımlılık bulunması veya başarı olasılığının önceki olay dallarına göre değişmesi durumunda daha ayrıntılı koşullu olasılık analizi yapılmalıdır.

8. Excel İçeri ve Dışarı Aktarma

Uygulamanın alt bölümünde üç temel işlem butonu bulunmaktadır.

Excel İçeri Aktar: Daha önce hazırlanmış ve uygulamanın veri yapısıyla uyumlu .xlsx dosyasının yeniden forma yüklenmesini sağlar. Analiz bilgileri, güvenlik bariyerleri ve sonuç senaryoları forma aktarılır.

Excel Dışarı Aktar: Formda oluşturulan analiz verilerini Excel dosyası olarak bilgisayara kaydeder. Dosyada ETA Bariyerleri, ETA Senaryoları ve Rapor Bilgileri olmak üzere üç çalışma sayfası bulunur.

PDF / Yazdır: Tamamlanan analizi A4 yatay sayfa düzeninde yazdırmaya veya PDF dosyası olarak kaydetmeye olanak tanır. Rapor; kurumsal başlık, analiz bilgileri, bariyerler, sonuç senaryoları ve değerlendirme bölümlerini içerir. Çok geniş olay ağaçlarında diyagramın tamamı PDF'ye sığmayabilir; sonuç yolları rapor tablosunda yer alır.

Önemli bir kullanım kuralı olarak, formda yapılan analiz değişiklikleri Excel Dışarı Aktar seçeneğiyle kaydedilmelidir. Excel dosyası, analizlerin arşivlenmesi ve daha sonra tekrar düzenlenebilmesi için kullanılmalıdır.

9. Kurumsal Başlık ve Logo Düzenleme

Uygulamanın üst bölümünde analiz başlığı, açıklama metni, kurum adı ve kurum logosu bulunur. Varsayılan kurum adı OLGUN BAŞKANLIĞI olarak tanımlanmıştır.

Başlık, alt başlık veya kurum adı üzerine art arda beş kez tıklanarak ilgili yazı düzenlenebilir. Logo alanına art arda beş kez tıklandığında bilgisayardan yeni bir logo seçilebilir. Ayrıca HTML dosyasıyla aynı klasörde bulunan logo.jpg dosyası varsayılan logo olarak kullanılabilir. 

10. Form Doldurulurken Dikkat Edilmesi Gerekenler

Analiz çalışmasına başlamadan önce incelenecek başlangıç olayı açıkça belirlenmeli, proses bilgileri ve mevcut güvenlik önlemleri hakkında yeterli veri toplanmalıdır.

Bariyer başarı olasılıkları rastgele belirlenmemeli; bakım kayıtları, test sonuçları, güvenilirlik hesaplamaları, geçmiş olay verileri veya uzman değerlendirmelerine dayandırılmalıdır.

Her sonuç senaryosunun insan sağlığı, çevre, ekipman, üretim sürekliliği ve işletme güvenliği üzerindeki olası etkileri dikkate alınmalıdır.

Özellikle ciddi ve kritik sonuçlara ulaşan yollar için mevcut koruyucu tedbirlerin yeterliliği sorgulanmalı, gerekli ek önlemler belirlenmeli ve aksiyonların tamamlanması takip edilmelidir.

ETA, başlangıç olayının gerçekleşmesinden sonraki olası sonuçları analiz eder. Tek başına bütün tehlikeleri ortaya çıkaran veya tüm riskleri kabul edilebilir düzeye indirdiğini kanıtlayan bir yöntem değildir. Gerektiğinde HAZOP, FTA, LOPA ve diğer mühendislik analizleriyle desteklenmelidir.

11. Sonuç

Risk UI – ETA Olay Ağacı Analizi Masaüstü HTML Uygulaması, endüstriyel tesislerde meydana gelebilecek başlangıç olaylarının farklı güvenlik bariyeri durumlarına göre hangi sonuçlara ulaşabileceğini sistematik olarak değerlendirmek amacıyla hazırlanmış bir analiz ve raporlama aracıdır.

Uygulama; güvenlik bariyerlerinin tanımlanmasını, olay ağacının görselleştirilmesini, senaryo olasılıklarının hesaplanmasını, sonuçların sınıflandırılmasını ve düzeltici/önleyici faaliyetlerin kayıt altına alınmasını sağlar.

Excel veri aktarımı ve PDF raporlama özellikleri sayesinde analizler düzenlenebilir, arşivlenebilir, tekrar incelenebilir ve kurum içi değerlendirme süreçlerinde kullanılabilir.

Temel hedef, tehlikeli bir başlangıç olayının olası sonuçlarını önceden belirlemek, mevcut güvenlik tedbirlerinin etkinliğini değerlendirmek ve daha ağır sonuçları önleyebilecek iyileştirme çalışmalarına teknik bir temel oluşturmaktır.

PDF / Yazdır

HTML Kod:
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="theme-color" content="#eaf7ee">
<title>İSG Risk Analizi – ETA (Olay Ağacı Analizi)</title>
<style>
:root{--bg:#eaf1f6;--frame:#f9fcfe;--surface:#fff;--ink:#183146;--muted:#5d7282;--line:#c9d8e4;--green:#0b72a5;--deep:#075b83;--soft:#e9f5fd;--blue:#0b72a5;--warn:#b6651a;--danger:#b43e4b;--radius:7px}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:var(--bg);color:var(--ink);font:13px/1.5 'Segoe UI',Arial,sans-serif}button,input,select,textarea{font:inherit}button{cursor:pointer}input,select,textarea{width:100%;border:1px solid #bdcfc4;border-radius:5px;background:#fff;color:#1e293b;padding:8px 9px;min-height:36px;outline:none}input:focus,textarea:focus,select:focus{border-color:var(--green);box-shadow:0 0 0 3px #2f855a1c}input[type=number]{font-variant-numeric:tabular-nums}textarea{min-height:70px;resize:vertical}label{display:block;font-weight:650;font-size:11.5px;color:#365449;margin-bottom:5px}.required:after{content:' *';color:var(--danger)}small,.subdued{color:var(--muted)}.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap}.frame{margin:8px;border:2px solid #91bea0;border-radius:8px;background:var(--frame);min-height:calc(100vh - 16px);box-shadow:0 5px 19px #173f2b0e;overflow:hidden}
.header{position:sticky;top:0;z-index:25;background:#fff;border-top:4px solid var(--green);border-bottom:1px solid #b7d0c1}.header-inner{display:flex;align-items:center;gap:12px;padding:10px 17px;min-height:76px}.logo-box{flex:none;width:59px;height:54px;background:#f1faf3;border:1px solid #b4d6c0;border-radius:6px;display:flex;align-items:center;justify-content:center;color:#28744c;font-size:10px;font-weight:800;padding:3px;overflow:hidden}.logo-box img{display:none;width:100%;height:100%;object-fit:contain}.title-group{min-width:0;flex:1 1 auto}.title-group h1{margin:0;color:#075c3a;line-height:1.22;font-size:18px;font-weight:800}.title-group p{margin:3px 0 0;color:#4d6a5b;font-size:11.5px}.org{flex:0 1 auto;max-width:46%;text-align:right;overflow-wrap:anywhere;white-space:normal;color:#1e6440;font-size:15px;font-weight:800;margin-left:auto}.editable[contenteditable=true]{outline:2px dashed var(--green);outline-offset:3px;border-radius:3px}.container{padding:12px 17px;display:grid;gap:11px}.section{border:1px solid var(--line);border-radius:var(--radius);background:white;box-shadow:0 2px 8px #25425b08;min-width:0;overflow:hidden}.section-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:9px 12px;background:var(--soft);border-bottom:1px solid #cbe2d3;border-left:4px solid var(--green)}.section-head h2{display:flex;align-items:center;gap:7px;margin:0;color:#1f5a3d;font-size:14px}.section-no{font-size:10px;color:#1b693f;background:#d9f0e0;border-radius:4px;padding:3px 7px}.section-body{padding:12px 13px}.section-tools{display:flex;align-items:center;gap:7px;flex-wrap:wrap}.grid{display:grid;gap:10px}.grid-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-4{grid-template-columns:repeat(4,minmax(0,1fr))}.span-2{grid-column:span 2}.span-3{grid-column:span 3}.full{grid-column:1/-1}.kpis{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:9px}.kpi{padding:10px 12px;background:#fff;border:1px solid #c8ddd0;border-top:3px solid var(--green);border-radius:6px;min-width:0}.kpi small{display:block;font-weight:700;font-size:10px;letter-spacing:.02em}.kpi strong{font-size:23px;font-weight:800;display:block;color:#175f3b;line-height:1.22;margin-top:3px;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}.kpi strong.warning{color:#b15b25}.kpi strong.danger{color:#ab2e40}.kpi em{font-size:10px;color:#698175;font-style:normal}.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid #c3d6ca;border-radius:5px;min-height:35px;padding:7px 11px;background:#fff;color:#345342;font-weight:700;font-size:11.5px;white-space:nowrap}.btn:hover{background:#f0f8f2}.btn-primary{background:var(--green);border-color:var(--green);color:#fff}.btn-primary:hover{background:#226b47}.btn-blue{color:#08618b;border-color:#a9d5e9;background:#e8f7fe}.btn-danger{border-color:#ebbdc1;color:#b33247}.btn-mini{padding:4px 7px;min-height:28px;font-size:11px}.actions{display:flex;flex-wrap:wrap;gap:7px;align-items:center}.actions .push{flex:1}.note{font-size:11px;color:#5f7568;margin-top:7px}.info{padding:9px 11px;background:#eff8f2;border:1px solid #cce6d5;border-left:3px solid var(--green);border-radius:5px;color:#365c47;font-size:11.5px}.alert{padding:10px 12px;border:1px solid #f0d59b;border-left:4px solid #d39c33;background:#fff9ea;border-radius:5px;color:#775322;font-size:11.5px}.alert-danger{border-color:#ecc2c8;border-left-color:#b43e4b;background:#fff5f5;color:#8b3040}.pill{display:inline-flex;align-items:center;justify-content:center;border-radius:99px;font-size:10.5px;font-weight:800;padding:2px 9px;border:1px solid transparent;white-space:nowrap}.pill-pass{color:#19734a;background:#e4f6ea;border-color:#bce0c8}.pill-fail{color:#a73c48;background:#fff0f0;border-color:#f1c5ca}.pill-muted{background:#f1f5f9;border-color:#d8e0e7;color:#627386}.pill-amber{background:#fff5dc;border-color:#ecd398;color:#99620f}.table-scroll{width:100%;overflow-x:auto}.table{border-collapse:collapse;width:100%;min-width:1000px}.table th{background:#f1f7f3;color:#426354;font-size:11px;text-align:left;font-weight:800;border-bottom:1px solid #d8e9de;padding:9px 8px;white-space:nowrap}.table td{border-bottom:1px solid #e6efe8;padding:8px;vertical-align:top;font-size:11.5px}.table tbody tr:hover{background:#fafffa}.table input,.table textarea,.table select{min-height:33px;font-size:11.5px}.table textarea{min-height:40px}.table .td-actions{white-space:nowrap}.table-barriers{min-width:990px}.table-results{min-width:1670px;table-layout:fixed}.center{text-align:center}.num{font-variant-numeric:tabular-nums;font-weight:750}.empty{padding:25px 12px;text-align:center;font-size:12px;color:#62786b;background:#f9fcfa;border:1px dashed #bed6c7;border-radius:6px}.empty b{display:block;color:#1b693f;font-size:13px;margin-bottom:5px}.outcome-4{color:#b82d3a!important;font-weight:800}.outcome-3{color:#bd6427!important;font-weight:800}.outcome-2{color:#8d731c!important;font-weight:800}.outcome-1{color:#367259!important}.outcome-0{color:#64748b!important}.diagram-wrap{border:1px solid #d1e4d8;border-radius:6px;overflow:auto;background:linear-gradient(0deg,#ffffff,#fbfefd);max-height:740px}.diagram-wrap svg{display:block;max-width:none}.diagram-controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:10px}.legend{display:flex;align-items:center;gap:12px;flex-wrap:wrap;font-size:11px;color:#526b5e}.dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:4px}.dot.ok{background:#2f855a}.dot.bad{background:#d65b61}.dot.unknown{background:#b9c7bd}.math{font-size:12px;background:#f6faf7;border:1px solid #d4e8da;border-radius:6px;padding:11px 12px;display:grid;gap:4px}.math code{font-size:12px;background:#e5f3ea;padding:2px 4px;border-radius:3px;color:#245f41}.footer{border-top:1px solid #c2deca;padding:10px 17px 15px;color:#466957;font-size:11px}.toast{position:fixed;bottom:18px;right:18px;background:#154e32;color:#fff;padding:10px 14px;z-index:100;border-radius:6px;box-shadow:0 7px 25px #123b2c38;opacity:0;transform:translateY(12px);pointer-events:none;transition:.2s;max-width:min(400px,90vw);font-size:12px}.toast.visible{opacity:1;transform:translateY(0)}.fineprint{font-size:10.5px;color:#62786c}.report{display:none}.flexline{display:flex;align-items:center;gap:7px;flex-wrap:wrap}
@media(max-width:1100px){.kpis{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-4{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:720px){.frame{margin:3px;border-width:1px}.header-inner{padding:7px 10px;min-height:63px;gap:8px}.logo-box{width:52px;height:49px}.title-group h1{font-size:15px}.title-group p{font-size:10px}.org{font-size:11.5px;max-width:38%}.container{padding:9px;gap:9px}.section-head{align-items:flex-start;flex-wrap:wrap}.section-body{padding:10px}.grid-4,.grid-3,.grid-2{grid-template-columns:1fr}.span-2,.span-3{grid-column:auto}.kpis{grid-template-columns:repeat(2,minmax(0,1fr))}.kpi{padding:8px}.kpi strong{font-size:20px}.actions .btn{flex:1 1 115px;white-space:normal}.actions .push{display:none}.section-tools .btn{white-space:normal}}
@media(max-width:390px){.kpis{grid-template-columns:1fr 1fr}.org{font-size:10px}}
@page{size:A4 landscape;margin:10mm 9mm 13mm 9mm;@bottom-right{content:'Sayfa ' counter(page) ' / ' counter(pages);font:8pt Arial;color:#46665a}}
@media print{
html,body{margin:0!important;padding:0!important;background:#fff!important;font:9px/1.35 Arial,sans-serif!important;color:#202e37!important;print-color-adjust:exact!important;-webkit-print-color-adjust:exact!important}
.frame,.toast{display:none!important}.report{display:table!important;width:100%;border-collapse:collapse;table-layout:fixed}.report thead{display:table-header-group}.report tbody{display:table-row-group}.report>thead>tr>td{padding:0 0 9px;border:0}.report>tbody>tr>td{padding:0;border:0}
.report-header{display:flex;gap:10px;align-items:center;border:1px solid #7f95a9;border-top:4px solid #0284c7;background:white;padding:7px 10px;min-height:56px}.report-header img{width:45px;height:42px;object-fit:contain}.report-header strong{color:#075985;font-size:16px;display:block}.report-header small{font-size:9px;color:#627386}.report-header .print-org{margin-left:auto;text-align:right;font-size:12px;font-weight:700;max-width:38%;overflow-wrap:anywhere}
.pr-section{margin-bottom:9px;border:1px solid #c1ced8;break-inside:auto}.pr-section h3{margin:0;padding:6px 8px;background:#eaf5fc;border-left:4px solid #0284c7;color:#075985;font-size:11px;break-after:avoid}.pr-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:5px;padding:7px}.pr-field{border:1px solid #dce5ea;padding:5px;overflow-wrap:anywhere;white-space:pre-wrap;min-height:31px}.pr-field b{display:block;color:#657487;font-size:8px;margin-bottom:2px}.pr-table{width:100%;border-collapse:collapse;table-layout:fixed}.pr-table th,.pr-table td{border:1px solid #cdd7db;padding:5px 5px;text-align:left;vertical-align:top;overflow-wrap:anywhere}.pr-table th{background:#ebf5fa;color:#23506c}.pr-table tr{break-inside:avoid}.pr-table thead{display:table-header-group}.pr-summary{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;padding:7px}.pr-summary div{border:1px solid #cbd8e1;padding:6px}.pr-summary b{display:block;font-size:15px;color:#075985}.pr-small{color:#657487;font-size:8.5px;padding:7px}.pr-tree{padding:6px;break-inside:avoid}.pr-tree svg{display:block;width:100%;max-height:155mm;height:auto}.pr-sign{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:15px 0}.pr-sign div{border:1px solid #cad4df;min-height:50px;padding:7px}.pr-sign b{display:block;color:#375575}.report-row{break-inside:avoid}
}

/* Risk UI / HAZOP referansındaki kurumsal mavi görsel sistem */
body{background:#eaf1f6;color:#183146;font:13px/1.43 'Segoe UI',Arial,sans-serif}
input,textarea,select{border-color:#c8d6e1;min-height:34px;padding:7px 8px;color:#1d354a}
input:focus,textarea:focus,select:focus{border-color:#268dc5;box-shadow:0 0 0 2px #268dc522}
label{color:#29465c;font-size:11.5px;font-weight:700;margin-bottom:4px}
.frame{margin:8px;border:2px solid #8ca7bc;background:#f9fcfe;min-height:calc(100vh - 16px);border-radius:7px;box-shadow:0 4px 18px #23425a15}
.header{border-top:4px solid #0579ad;border-bottom:1px solid #bed1df;border-radius:4px 4px 0 0;background:#fff}
.header-inner{min-height:75px;gap:13px;padding:8px 17px}
.logo-box{flex:0 0 61px;width:61px;height:57px;border:1px solid #cbd9e4;background:#f6fbff;border-radius:5px;color:#11658b;font-size:12px;font-weight:800}
.title-group{flex:1;min-width:0}.title-group h1{color:#08658e;font-size:19px;line-height:1.22}.title-group p{margin:3px 0 0;font-size:11px;color:#4d6576}
.org{margin-left:auto;max-width:35%;font-size:15px;font-weight:800;text-align:right;color:#23455e;overflow-wrap:anywhere;min-width:0}
.editable[contenteditable=true]{outline:2px dashed #0284c7;outline-offset:3px}
.container{padding:12px 17px 7px;gap:10px}
.kpis{grid-template-columns:repeat(5,minmax(0,1fr));gap:10px}
.kpi{border:1px solid #c7d8e3;border-top:3px solid #0c83bd;border-radius:6px;background:#fff;padding:9px 12px}
.kpi small{font-size:10px;color:#5b7386;font-weight:750}.kpi strong{color:#164766;font-size:23px;line-height:1.35}
.section{background:#fff;border:1px solid #c9d8e4;border-radius:6px;box-shadow:0 2px 7px #17405a0a}
.section-head{padding:9px 12px;background:#e9f5fd;border-left:4px solid #087dae;border-bottom:1px solid #c2ddea}
.section-head h2{color:#0b587c;font-size:14px}.section-no{background:#d2ecfb;color:#135d88;font-size:10px;padding:3px 6px;border-radius:4px}
.section-body{padding:11px 13px}
.btn{border:1px solid #c5d4df;border-radius:5px;background:#fff;padding:7px 10px;color:#2c4a5c;font-weight:700;min-height:33px;font-size:11.5px}
.btn:hover{background:#eff6fa}.btn-primary{background:#057eb6;border-color:#057eb6;color:#fff}.btn-primary:hover{background:#086993}
.btn-blue{background:#e7f5ff;border-color:#b8dbf4;color:#0b5881}.btn-green{background:#e7f8ee;border-color:#b5e0c6;color:#17633d}
.btn-mini{font-size:10.5px;padding:4px 7px;min-height:27px}
.info{background:#eaf7fd;border:1px solid #bdddeb;border-left:3px solid #087dae;color:#135f88}
.note,.fineprint{color:#61788b}.empty{background:#f5fafc;border-color:#dceaf0;color:#60788a}.empty b{color:#0b587c}
.table th{background:#edf5fa;color:#4e6476;border-bottom:1px solid #dae4ea;font-size:10.5px}
.table td{border-bottom:1px solid #e7eef3}.table tbody tr:hover{background:#f7fbff}
.diagram-wrap{border-color:#b9d2e1;background:#fbfdff}.math{background:#f6f9fb;border-color:#e1eaf1}.math code{background:#e8f5fc;color:#135f88}
.pill-pass{background:#ddf5e3;border-color:#a4dfb5;color:#16603a}.footer{white-space:nowrap;overflow-x:auto;font-size:11px;border-top:1px solid #d7e4ec;margin:0 17px;padding:5px 0 4px;color:#4c6074;line-height:1.35}
.toast{background:#194b68;border-radius:5px}
.bottom-actions{padding:5px 17px 4px;display:flex}.bottom-panel{border:1px solid #bed4e1;background:#fff;border-radius:6px;padding:8px 10px;display:flex;gap:9px;flex-wrap:wrap}
@media(max-width:1120px){.kpis{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:720px){.frame{margin:3px}.header-inner{padding:8px 10px;flex-wrap:wrap}.title-group h1{font-size:15px}.title-group p{font-size:10px}.logo-box{flex-basis:49px;width:49px;height:49px}.org{max-width:100%;width:100%;font-size:11px;text-align:left}.kpis{grid-template-columns:1fr 1fr;gap:5px}.kpi{padding:7px}.kpi strong{font-size:19px}.container{padding:9px;gap:9px}.bottom-actions{padding:5px 9px}.bottom-panel{width:100%;gap:5px}.bottom-panel .btn{flex:1 1 110px;white-space:normal}.footer{font-size:10px;margin:0 9px}}
/* Yatay A4 baskıda referans HAZOP gibi her sayfa başında kurumsal başlık */
#printPageFrame{display:none}
@page{size:A4 landscape;margin:6mm 7mm 7mm 7mm}
@media print{
 html,body{background:#fff!important;margin:0!important;padding:0!important;font-size:8.5px!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
 #printPages{display:table!important;width:100%!important;border:0!important;border-collapse:separate;border-spacing:0;table-layout:fixed}
 #printPages>thead{display:table-header-group!important}#printPages>tbody{display:table-row-group!important}
 #printPages>thead>tr>td{padding:0 0 3px!important}#printPages>tbody>tr>td{padding:0!important}
 #printPageFrame{display:block!important;position:fixed;inset:0;border:1.5px solid #809bb2;pointer-events:none;z-index:15}
 .report-header{min-height:49px!important;padding:3px 8px!important;gap:8px!important;background:#fff!important;border-top:4px solid #0c84b8}
 .report-header img{width:43px!important;height:40px!important}.report-header strong{font-size:14px!important}
 .pr-section{margin-bottom:3px!important;break-inside:auto!important;page-break-inside:auto!important}
 .pr-section h3{break-after:avoid-page!important;page-break-after:avoid!important;padding:3px 7px!important;background:#eaf5fc!important}
 .pr-grid{gap:3px!important;padding:4px!important}.pr-field{padding:2px 3px!important;font-size:8px!important;min-height:0!important}
 .pr-field b{font-size:7px!important;margin-bottom:1px!important}
 .pr-table th,.pr-table td{padding:2px 3px!important;font-size:7.5px!important;line-height:1.27!important}
 .pr-table thead{display:table-header-group!important}.pr-table tr{break-inside:avoid-page!important;page-break-inside:avoid!important}
 .pr-summary{padding:4px!important;gap:3px!important}.pr-summary div{padding:3px!important}.pr-summary b{font-size:12px!important}
 .pr-tree{padding:4px!important;break-inside:avoid-page!important;page-break-inside:avoid!important}.pr-tree svg{max-height:92mm!important}
 .pr-sign{margin:8px 0!important;gap:5px!important}.pr-sign div{min-height:35px!important;padding:5px!important}
 .pr-small{font-size:7px!important;padding:3px 5px!important}
}


/* ETA nihai: Sonuç senaryosu açıklama, aksiyon ve sorumlu alanları
   içerikle birlikte büyür; yatay/dikey metin kırpma veya iç kaydırma olmaz. */
.table-results td{overflow-wrap:anywhere}
.table-results textarea[data-oprop]{
 display:block;width:100%;height:72px;min-height:72px;
 line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere;
 overflow:hidden;resize:vertical;box-sizing:border-box;
 font-size:11.5px;padding:8px 9px;
}
.table-results textarea[data-oprop="owner"]{height:52px;min-height:52px}
.table-results td:has(textarea[data-oprop]){vertical-align:top}
.table-results textarea[data-oprop]:focus{outline:0;border-color:#268dc5;box-shadow:0 0 0 2px #268dc522}
</style>
</head>
<body>
<div class="frame" id="screenApp">
<header class="header"><div class="header-inner">
<button type="button" class="logo-box" id="logoButton" aria-label="Logoyu değiştirmek için 5 kez tıklayın" title="Logo dosyası: logo.jpg · değiştirmek için 5 kez tıklayın"><img id="brandLogo" alt="Kurum logosu"><span id="logoFallback">LOGO</span></button>
<div class="title-group"><h1 id="headerTitle" class="editable" title="Düzenlemek için 5 kez tıklayın">İSG RİSK ANALİZİ – ETA</h1><p class="editable" id="headerSub" title="Düzenlemek için 5 kez tıklayın">Olay Ağacı Analizi · Başlangıç Olayı, Güvenlik Bariyerleri ve Sonuç Senaryoları</p></div>
<div class="org editable" id="headerOrg" title="Düzenlemek için 5 kez tıklayın">OLGUN BAŞKANLIĞI</div>
</div></header>
<input class="sr-only" type="file" id="logoFile" accept="image/png,image/jpeg,image/webp,image/gif,image/svg+xml">
<main class="container">
<section class="kpis metrics" aria-label="Analiz göstergeleri">
<div class="kpi metric"><small>GÜVENLİK BARİYERİ</small><strong id="kpiBarrier">0</strong><em>En fazla 6</em></div>
<div class="kpi metric"><small>OLASI SENARYO</small><strong id="kpiScenario">0</strong><em>2ⁿ sonuç yolu</em></div>
<div class="kpi metric"><small>DEĞERLENDİRİLEN</small><strong id="kpiAssessed">0 / 0</strong><em>Sonuç sınıfı atanmış</em></div>
<div class="kpi metric"><small>CİDDİ / KRİTİK SENARYO</small><strong id="kpiSevere">0</strong><em>Sonuç sınıfı 3–4</em></div>
<div class="kpi metric"><small>CİDDİ / KRİTİK SONUÇ SIKLIĞI</small><strong id="kpiFreq">—</strong><em>Olay / yıl (sınıflanan yollar)</em></div>
</section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">01</span> Analiz ve Başlangıç Olayı Bilgileri</h2><span class="pill pill-muted">ETA / Event Tree Analysis</span></div><div class="section-body card-b">
<div class="grid grid-4">
<div><label for="analysisId" class="required">Analiz / Doküman No</label><input id="analysisId" data-field="analysisId" maxlength="80" placeholder="Örn. ETA-2026-001"></div>
<div><label for="analysisDate">Analiz Tarihi</label><input id="analysisDate" type="date" data-field="analysisDate"></div>
<div><label for="facility">Tesis / Birim</label><input id="facility" data-field="facility" maxlength="140" placeholder="Tesis veya sorumlu birim"></div>
<div><label for="owner">Analizi Hazırlayan</label><input id="owner" data-field="owner" maxlength="120" placeholder="Ad soyad / unvan"></div>
<div><label for="eventType">Olay Türü</label><select id="eventType" data-field="eventType"><option value="">Seçiniz</option><option>Yangın</option><option>Patlama</option><option>Endüstriyel kaza</option><option>Kimyasal sızıntı</option><option>Diğer</option></select></div>
<div><label for="process">Proses / Faaliyet</label><input id="process" data-field="process" maxlength="160" placeholder="İlgili faaliyet / proses"></div>
<div><label for="eventFrequency" class="required">Başlangıç Olayı Sıklığı (olay/yıl)</label><input id="eventFrequency" data-field="eventFrequency" type="number" min="0" step="any" inputmode="decimal" placeholder="Örn. 0,1 yerine 0.1"></div>
<div><label for="revision">Revizyon / Durum</label><input id="revision" data-field="revision" maxlength="80" placeholder="Rev.00 / Taslak"></div>
<div class="span-2"><label for="initEvent" class="required">Başlangıç Olayı (Initiating Event)</label><textarea id="initEvent" data-field="initEvent" maxlength="500" placeholder="Örn. Depolama alanında elektrik kaynaklı yangının başlaması"></textarea></div>
<div class="span-2"><label for="boundaries">Kapsam, Varsayımlar ve Sınırlar</label><textarea id="boundaries" data-field="boundaries" maxlength="1500" placeholder="Bariyerlerin kapsadığı olay sırası, veri kaynağı, bağımlılıklar, müdahale süresi, senaryo sınırları..."></textarea></div>
</div>
<div class="note">Sıklık alanına yıllık beklenen başlangıç olayı sayısını girin. Örneğin <b>0.1 olay/yıl</b>, ortalamada 10 yılda bir olaya karşılık gelen tahmini sıklıktır; gözlem veya tasarım verisine dayanmalıdır.</div>
</div></section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">02</span> Güvenlik Bariyerleri / Olay Dalları</h2><div class="section-tools"><span class="pill pill-muted" id="barrierLimit">0 / 6</span><button class="btn btn-primary btn-mini" type="button" id="addBarrierBtn">+ Bariyer Ekle</button></div></div><div class="section-body card-b">
<div class="info">Bariyerleri olay sonrası gerçekleşme sırasıyla ekleyin. <b>Başarı olasılığı (%)</b> her iki dala ayrılır: Başarılı = p, Başarısız = 1 − p. Aynı değer farklı geçmiş senaryo dallarında da kullanılır; yol bağımlılığı varsa ayrı koşullu veri gerekir.</div>
<div class="table-scroll" style="margin-top:10px"><table class="table table-barriers"><thead><tr><th style="width:55px">Sıra</th><th style="width:220px">Bariyer / Kontrol</th><th style="width:230px">Çalışma / Başarı Kriteri</th><th style="width:120px">Başarı (%)</th><th style="width:110px">Başarısızlık (%)</th><th style="width:220px">Veri Kaynağı / Not</th><th style="width:165px">İşlemler</th></tr></thead><tbody id="barrierRows"></tbody></table></div>
<div class="note">Maksimum 6 bariyer → 64 sonuç senaryosu. Bariyer adını ve başarı olasılığını girmeniz yeterlidir. Bariyer sırası senaryo yollarının adlandırmasını etkiler.</div>
</div></section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">03</span> Olay Ağacı Diyagramı</h2><div class="section-tools"><span id="calcStatus" class="pill pill-amber">Veri bekleniyor</span></div></div><div class="section-body card-b">
<div class="diagram-controls"><div class="legend"><span><i class="dot ok"></i> Başarılı</span><span><i class="dot bad"></i> Başarısız</span><span><i class="dot unknown"></i> Sınıflanmamış sonuç</span></div><span class="subdued">Diyagramı yatay ve dikey kaydırabilirsiniz.</span></div>
<div id="diagram" class="diagram-wrap" aria-label="ETA olay ağacı görseli"></div>
<div class="note" id="probNote">Henüz bariyer eklenmedi.</div>
</div></section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">04</span> Sonuç Senaryoları ve Kontrol Aksiyonları</h2><div class="section-tools"><span class="pill pill-muted" id="scenarioCount">0 sonuç</span></div></div><div class="section-body card-b">
<div class="info" style="margin-bottom:10px">Her yol için <b>sonuç sınıfını</b>, <b>beklenen sonucu</b> ve <b>aksiyonu</b> girin. Yol olasılıkları yalnızca tüm başarı oranları geçerliyse; yıllık sıklıklar ayrıca başlangıç olayı sıklığı girilmişse hesaplanır.</div>
<div class="table-scroll"><table class="table table-results"><thead><tr><th style="width:56px">Kod</th><th style="width:235px">Bariyer Durumları</th><th style="width:90px">Yol Olasılığı</th><th style="width:112px">Sonuç Sıklığı<br>(olay/yıl)</th><th style="width:170px">Sonuç Sınıfı</th><th style="width:330px">Muhtemel Sonuç / Etki</th><th style="width:330px">Düzeltici / Önleyici Aksiyon</th><th style="width:185px">Sorumlu</th><th style="width:130px">Hedef Tarih</th></tr></thead><tbody id="resultRows"></tbody></table></div>
<div class="note">Olasılık hesapları başlangıç olayı <i>meydana gelmiş olması koşuluyla</i> yapılır. Yıllık sonuç sıklıkları başlangıç sıklığıyla çarpılır. Birden çok sonuç yolu aynı ciddiyetteyse sıklıkları toplanabilir.</div>
</div></section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">05</span> Değerlendirme, Karar ve Onay</h2></div><div class="section-body card-b">
<div class="grid grid-3">
<div><label for="decision">Değerlendirme Kararı</label><select id="decision" data-field="decision"><option value="">Karar verilmedi</option><option>Mevcut önlemlerle kabul</option><option>Ek önlem ve iyileştirme gerekli</option><option>İlave veri / analiz gerekli</option><option>Faaliyet durdurulmalı / yeniden tasarlanmalı</option></select></div>
<div><label for="reviewer">Kontrol / Gözden Geçiren</label><input id="reviewer" data-field="reviewer" maxlength="120" placeholder="Ad soyad / unvan"></div>
<div><label for="approver">Onaylayan</label><input id="approver" data-field="approver" maxlength="120" placeholder="Ad soyad / unvan"></div>
<div class="full"><label for="generalNotes">Genel Bulgular / Aksiyon Planı / Belirsizlikler</label><textarea id="generalNotes" data-field="generalNotes" maxlength="3000" placeholder="Öncelikli iyileştirmeler, veri kısıtları, kontrol tarihi, sorumluluklar..."></textarea></div>
</div>
<div id="qualityWarning" class="alert" style="margin-top:11px">Hesaplama için başlangıç sıklığını ve bariyer bilgilerini girin.</div>
</div></section>
<section class="section card"><div class="section-head card-h"><h2><span class="section-no sect">06</span> ETA Hesaplama Yöntemi ve Kullanım Notları</h2></div><div class="section-body card-b"><div class="math">
<div><b>Bir sonuç yolunun koşullu olasılığı:</b> <code>P(yol | başlangıç) = ∏ her bariyer dalı olasılığı</code></div>
<div><b>Bir sonuç yolunun yıllık sıklığı:</b> <code>F(yol) = F(başlangıç) × P(yol | başlangıç)</code></div>
<div><b>Tüm sonuç yolları:</b> <code>Σ P(yol | başlangıç) = 1</code> (eksiksiz ikili dallar ve geçerli olasılıklar için)</div>
</div><div class="note"><b>Önemli:</b> Bu araç her bariyerde iki olasılığı (başarılı / başarısız) kullanır. Bir bariyerin başarı şansı önceki bariyer sonuçlarına göre değişiyorsa, bağımsızlık varsayımına dayanmadan dal bazlı koşullu olasılıklar ve uzman doğrulaması gerekir. Bu araç bir ön analiz ve dokümantasyon yardımcısıdır; HAZOP, FTA, LOPA, QRA, mevzuat değerlendirmesi veya mühendislik onayının yerine geçmez.</div></div></section>
</main>
<div class="bottom-actions"><div class="bottom-panel">
<button type="button" class="btn btn-blue" id="importExcelBtn">⬆ Excel İçeri Aktar</button>
<button type="button" class="btn btn-green" id="exportExcelBtn">⬇ Excel Dışarı Aktar</button>
<button type="button" class="btn" id="printBtn">▣ PDF / Yazdır</button>
<input type="file" id="excelFile" class="sr-only" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
</div></div>
<footer class="footer"><b>Risk UI · ETA / Olay Ağacı Analizi</b> &nbsp;|&nbsp; Sayfa yenilendiğinde analiz temizlenir. Kalıcı saklamak için Excel Dışarı Aktar kullanın; bilgiler sunucuya gönderilmez. &nbsp;|&nbsp; Kurum adı ve başlıklar 5 ardışık tıklamayla düzenlenebilir.</footer>
</div>
<table class="report" id="printPages" role="presentation"><thead><tr><td id="reportHeader"></td></tr></thead><tbody><tr><td id="reportBody"></td></tr></tbody></table><div id="printPageFrame"></div>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script>
(function(){
'use strict';
const BRAND_KEY='risk-ui-eta-brand-v2';
const $=id=>document.getElementById(id);
const nowDate=()=>{const d=new Date();return [d.getFullYear(),String(d.getMonth()+1).padStart(2,'0'),String(d.getDate()).padStart(2,'0')].join('-')};
const defaults=()=>({analysisId:'',analysisDate:'',facility:'',owner:'',eventType:'',process:'',eventFrequency:'',revision:'',initEvent:'',boundaries:'',decision:'',reviewer:'',approver:'',generalNotes:'',barriers:[],outcomes:{},brand:{title:'İSG RİSK ANALİZİ – ETA',sub:'Olay Ağacı Analizi · Başlangıç Olayı, Güvenlik Bariyerleri ve Sonuç Senaryoları',org:'OLGUN BAŞKANLIĞI',logo:''}});
let model=defaults();let toastTimeout=0;let currentScenarios=[];let diagramSVG='';
const scalarFields=['analysisId','analysisDate','facility','owner','eventType','process','eventFrequency','revision','initEvent','boundaries','decision','reviewer','approver','generalNotes'];
function esc(v){return String(v==null?'':v).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));}
function fmt(v,d=4){if(v===null || !Number.isFinite(v))return '—';return new Intl.NumberFormat('tr-TR',{maximumFractionDigits:d}).format(v);}
function pct(v){return v===null?'—':fmt(v*100,5)+' %'}
function setNotice(msg){const el=$('toast');el.textContent=msg;el.classList.add('visible');clearTimeout(toastTimeout);toastTimeout=setTimeout(()=>el.classList.remove('visible'),3000)}
function scheduleSave(){/* Analiz verileri yalnızca Excel üzerinden kalıcılaştırılır. */}
function hydrate(x){const o=defaults();if(!x || typeof x!=='object'||Array.isArray(x))return o;
for(const k of scalarFields){if(k==='eventFrequency'){o[k]=x[k]==null?'':String(x[k]).slice(0,32)}else if(typeof x[k]==='string')o[k]=x[k].slice(0,k==='generalNotes'?3000:1600);}
if(Array.isArray(x.barriers)){o.barriers=x.barriers.slice(0,6).map((b,i)=>({id:String(b.id||('b'+i)).slice(0,35),name:String(b.name||'').slice(0,120),criterion:String(b.criterion||'').slice(0,250),success:b.success==null?'':String(b.success).slice(0,16),note:String(b.note||'').slice(0,250)}));}
if(x.outcomes && typeof x.outcomes==='object'&&!Array.isArray(x.outcomes)){for(const [k,v] of Object.entries(x.outcomes).slice(0,128)){if(!v||typeof v!=='object')continue;o.outcomes[k.slice(0,280)]={severity:['','0','1','2','3','4'].includes(String(v.severity))?String(v.severity):'',description:String(v.description||'').slice(0,400),action:String(v.action||'').slice(0,400),owner:String(v.owner||'').slice(0,150),due:String(v.due||'').slice(0,30)}}}
if(x.brand&&typeof x.brand==='object'){for(const k of ['title','sub','org'])if(typeof x.brand[k]==='string')o.brand[k]=x.brand[k].slice(0,180);if(typeof x.brand.logo==='string'&&x.brand.logo.startsWith('data:image/')&&x.brand.logo.length<750000)o.brand.logo=x.brand.logo;}
return o;}
function renderFields(){scalarFields.forEach(k=>{if($(k))$(k).value=model[k]});['Title','Sub','Org'].forEach((part)=>{$('header'+part).textContent=model.brand[part.toLowerCase()]||'';});renderLogo()}
function renderLogo(){let img=$('brandLogo');let fallback=$('logoFallback');let source=model.brand.logo||'logo.jpg';img.onload=()=>{img.style.display='block';fallback.style.display='none'};img.onerror=()=>{if(!model.brand.logo){img.style.display='none';fallback.style.display='block'}else{img.style.display='none';fallback.style.display='block'}};img.src=source}
function loadBrand(){try{const b=JSON.parse(localStorage.getItem(BRAND_KEY)||'null');if(b&&typeof b==='object'){for(const k of ['title','sub','org','logo']){if(typeof b[k]==='string'&&(k!=='logo'||b[k].startsWith('data:image/')))model.brand[k]=(k==='org' && b[k]==='KURUM / İŞLETME')?'OLGUN BAŞKANLIĞI':b[k]}}}catch(e){}}
function saveBrand(){try{localStorage.setItem(BRAND_KEY,JSON.stringify(model.brand))}catch(e){setNotice('Başlık ve logo tarayıcıya kaydedilemedi.')}}
function makeId(){return 'b'+Math.random().toString(36).slice(2,10)}
function pSuccess(b){if(b.success===''||b.success===null||b.success===undefined)return null;const p=Number(b.success);return Number.isFinite(p)&&p>=0&&p<=100?p/100:null}
function getFreq(){if(model.eventFrequency===''||model.eventFrequency===null)return null;const f=Number(model.eventFrequency);return Number.isFinite(f)&&f>=0?f:null}
function validBars(){return model.barriers.length>0&&model.barriers.every(b=>b.name.trim()&&pSuccess(b)!==null)}
function scenarioCode(index){return 'S'+String(index).padStart(2,'0')}
function scenarioKey(bits){return model.barriers.map((b,i)=>b.id+':'+bits[i]).sort().join('|')}
function getScenarios(){const n=model.barriers.length;if(!n)return [];const count=1<<n;const allValid=model.barriers.every(b=>pSuccess(b)!==null);const f=getFreq();let paths=[];
for(let i=0;i<count;i++){let bits=[];let probability=allValid?1:null;for(let j=0;j<n;j++){const bit=(i>>(n-j-1))&1;const success=!bit;bits.push(success?'S':'F');if(allValid){const p=pSuccess(model.barriers[j]);probability*=success?p:1-p;}}
const key=scenarioKey(bits);const outcome=model.outcomes[key]||{severity:'',description:'',action:'',owner:'',due:''};paths.push({id:scenarioCode(i+1),key,bits,probability,frequency:f===null||probability===null?null:f*probability,outcome});}
return paths;}
function barrierRows(){const root=$('barrierRows');$('barrierLimit').textContent=model.barriers.length+' / 6';$('addBarrierBtn').disabled=model.barriers.length>=6;
if(!model.barriers.length){root.innerHTML='<tr><td colspan="7"><div class="empty"><b>Henüz bariyer eklenmedi.</b>"+ Bariyer Ekle" ile ilk güvenlik bariyerini tanımlayın.</div></td></tr>';return}
root.innerHTML=model.barriers.map((b,i)=>`<tr data-id="${esc(b.id)}"><td class="num">${i+1}</td><td><input aria-label="${i+1}. bariyer adı" data-bprop="name" maxlength="120" placeholder="Örn. Yangın algılama" value="${esc(b.name)}"></td><td><input aria-label="Başarı kriteri" data-bprop="criterion" maxlength="250" placeholder="Örn. Alarmın zamanında çalışması" value="${esc(b.criterion)}"></td><td><input aria-label="Başarı olasılığı yüzde" data-bprop="success" type="number" min="0" max="100" step="any" placeholder="0–100" value="${esc(b.success)}"></td><td class="num" data-failure-for="${esc(b.id)}">${pSuccess(b)===null?'—':fmt((1-pSuccess(b))*100,4)+' %'}</td><td><input aria-label="Veri kaynağı" data-bprop="note" maxlength="250" placeholder="Test / bakım kaydı / uzman tahmini" value="${esc(b.note)}"></td><td class="td-actions"><button type="button" class="btn btn-mini" data-action="up" title="Yukarı taşı" ${i===0?'disabled':''}>↑</button> <button type="button" class="btn btn-mini" data-action="down" title="Aşağı taşı" ${i===model.barriers.length-1?'disabled':''}>↓</button> <button type="button" class="btn btn-mini btn-danger" data-action="remove" title="Bariyeri sil">✕</button></td></tr>`).join('')}
const options='<option value="">Değerlendirilmedi</option><option value="0">0 · Etki yok / güvenli</option><option value="1">1 · Düşük etki</option><option value="2">2 · Orta etki</option><option value="3">3 · Ciddi etki</option><option value="4">4 · Kritik / felaket</option>';
function resizeScenarioTextarea(el){
 if(!el || el.tagName!=='TEXTAREA' || !el.matches('[data-oprop]'))return;
 const minHeight=el.dataset.oprop==='owner'?52:72;
 // Reset first: deleting text also shrinks the field to its content.
 el.style.height='auto';
 el.style.height=Math.max(minHeight,Math.ceil(el.scrollHeight)+2)+'px';
}
function resizeAllScenarioTextareas(){
 $('resultRows').querySelectorAll('textarea[data-oprop]').forEach(resizeScenarioTextarea);
}
function resultRows(){const root=$('resultRows');currentScenarios=getScenarios();$('scenarioCount').textContent=currentScenarios.length+' sonuç';
if(!currentScenarios.length){root.innerHTML='<tr><td colspan="9"><div class="empty">İlk bariyer eklendiğinde sonuç senaryoları burada oluşur.</div></td></tr>';return}
root.innerHTML=currentScenarios.map(s=>{const o=s.outcome;const statuses=s.bits.map((v,i)=>`<span class="pill ${v==='S'?'pill-pass':'pill-fail'}" title="${esc(model.barriers[i].name)}">${i+1}. ${v==='S'?'Başarı':'Başarısız'}</span>`).join(' ');return `<tr data-key="${esc(s.key)}"><td class="num">${s.id}</td><td><div class="flexline">${statuses}</div></td><td class="num">${pct(s.probability)}</td><td class="num">${fmt(s.frequency,7)}</td><td><select data-oprop="severity" aria-label="${s.id} sonuç sınıfı" class="outcome-${esc(o.severity)}">${options.replace('value="'+esc(o.severity)+'"','value="'+esc(o.severity)+'" selected')}</select></td><td><textarea data-oprop="description" rows="3" maxlength="400" aria-label="${s.id} sonucu" placeholder="Olası sonuç / etkiler">${esc(o.description)}</textarea></td><td><textarea data-oprop="action" rows="3" maxlength="400" aria-label="${s.id} önlem" placeholder="Önerilen aksiyon">${esc(o.action)}</textarea></td><td><textarea data-oprop="owner" rows="2" maxlength="150" aria-label="${s.id} sorumlu" placeholder="Sorumlu">${esc(o.owner)}</textarea></td><td><input data-oprop="due" type="date" aria-label="${s.id} hedef tarih" value="${esc(o.due)}"></td></tr>`}).join('');
 // Auto-expand populated fields after rendering (including imported Excel).
 resizeAllScenarioTextareas();
 requestAnimationFrame(resizeAllScenarioTextareas);
}
function textSvg(s){return esc(s).replace(/\n/g,' ')}
function svgText(x,y,t,style=''){return `<text x="${x}" y="${y}" ${style}>${textSvg(t)}</text>`}
function svgDiagram(){const n=model.barriers.length;if(!n)return '';const paths=currentScenarios;const count=paths.length;const rowH=38;const top=72;const width=250+n*190+270;const height=Math.max(260,top+count*rowH+40);const rootX=145;const yAt=i=>top+i*rowH+11;const pos=(start,length)=> (yAt(start)+yAt(start+length-1))/2;const f=getFreq();const allValid=model.barriers.every(b=>pSuccess(b)!==null);
let parts=[`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}" width="${width}" height="${height}" role="img" aria-label="Başlangıç olayından sonuç yollarına uzanan ETA diyagramı"><rect width="${width}" height="${height}" fill="#fcfffd"/>`];
parts.push(`<rect x="14" y="16" rx="5" width="115" height="38" fill="#e8f4ec" stroke="#9ecbb1"/>${svgText(23,32,'BAŞLANGIÇ OLAYI','font-size="10" font-weight="800" fill="#266344"')}${svgText(23,45,'(olay/yıl)','font-size="9" fill="#5b7b66"')}`);
for(let j=0;j<n;j++){const x=rootX+(j+1)*190;parts.push(`<rect x="${x-70}" y="14" width="148" height="42" rx="6" fill="#e8f4ed" stroke="#b8d9c6"/>${svgText(x-61,30,`${j+1}. ${model.barriers[j].name.slice(0,22)||'Bariyer'}`,'font-size="10" font-weight="700" fill="#205f3e"')}${svgText(x-61,46,'Başarı: '+(pSuccess(model.barriers[j])===null?'?':fmt(pSuccess(model.barriers[j])*100,3)+' %'),'font-size="10" fill="#537662"')}`)}
const lx=rootX+(n+1)*190;parts.push(svgText(lx-55,33,'SONUÇ YOLLARI','font-size="11" font-weight="800" fill="#245a3f"'));
const rootY=pos(0,count);parts.push(`<rect x="10" y="${rootY-18}" width="126" height="36" rx="6" fill="#e0f3e6" stroke="#2f855a"/>${svgText(19,rootY-2,'BAŞLANGIÇ','font-size="10" font-weight="800" fill="#205e3e"')}${svgText(19,rootY+12,f===null?'Sıklık: —':fmt(f,5)+'/yıl','font-size="10" fill="#3a6550"')}`);
function drawLevel(depth,start,length,oldX,oldY){if(depth===n){const index=start,s=paths[index],y=yAt(index);const color=s.outcome.severity==='4'?'#b82d3a':s.outcome.severity==='3'?'#c27b2c':s.outcome.severity===''?'#9cafaa':'#2f855a';
parts.push(`<line x1="${oldX+6}" y1="${oldY}" x2="${lx-10}" y2="${y}" stroke="#9abca7" stroke-width="1.3"/>`);
parts.push(`<rect x="${lx}" y="${y-11}" rx="4" width="205" height="23" fill="#fff" stroke="${color}"/><rect x="${lx}" y="${y-11}" width="4" height="23" rx="2" fill="${color}"/>${svgText(lx+10,y+4,s.id+'  '+(s.probability===null?'—':pct(s.probability)),'font-size="10.2" font-weight="700" fill="#2b4a3b"')}${svgText(lx+124,y+4,s.outcome.severity===''?'Sınıfsız':'Etki: '+s.outcome.severity,'font-size="10" fill="'+color+'"')}`);return;}
const x=rootX+(depth+1)*190;const half=length/2;
for(let branch=0;branch<2;branch++){const childStart=start+branch*half;const y=pos(childStart,half);const successful=branch===0;const color=successful?'#2f855a':'#d25a62';const p=pSuccess(model.barriers[depth]);const bp=p===null?null:successful?p:1-p;const elbow=(oldX+x)/2;
parts.push(`<path d="M${oldX+7},${oldY} L${elbow},${oldY} L${elbow},${y} L${x-9},${y}" fill="none" stroke="${color}" stroke-width="1.55"/>`);
parts.push(`<circle cx="${x}" cy="${y}" r="5" fill="${color}" stroke="#fff" stroke-width="1"/>`);
if(half>=2 || n<=3)parts.push(svgText(x+9,y-7,(successful?'B':'H')+' '+(bp===null?'?':fmt(bp*100,2)+' %'),`font-size="9" fill="${color}" font-weight="700"`));
drawLevel(depth+1,childStart,half,x,y);}
}
drawLevel(0,0,count,rootX,rootY);
parts.push('</svg>');return parts.join('')}
function renderDiagram(){const d=$('diagram');if(!model.barriers.length){diagramSVG='';d.innerHTML='<div class="empty"><b>Olay ağacı hazır değil.</b>Görsel olay ağacı için en az 1 bariyer ekleyin.</div>';return;}diagramSVG=svgDiagram();d.innerHTML=diagramSVG;}
function getAnalysis(){const n=model.barriers.length;const scenarios=currentScenarios;const counted=scenarios.filter(s=>s.outcome.severity!=='').length;const severe=scenarios.filter(s=>Number(s.outcome.severity)>=3 && s.outcome.severity!=='');const f=getFreq();const ready=validBars();const seriousFrequency=(f!==null&&ready)?severe.reduce((a,s)=>a+s.frequency,0):null;return {n,count:scenarios.length,counted,severe:severe.length,seriousFrequency,ready,hasFreq:f!==null,sumP:ready?scenarios.reduce((a,s)=>a+s.probability,0):null}}
function renderSummary(){const a=getAnalysis();$('kpiBarrier').textContent=a.n;$('kpiScenario').textContent=a.count;$('kpiAssessed').textContent=a.counted+' / '+a.count;$('kpiSevere').textContent=a.severe;$('kpiSevere').className=a.severe?'danger':'';$('kpiFreq').textContent=fmt(a.seriousFrequency,7);$('kpiFreq').className=a.severe?'danger':'';
$('calcStatus').textContent=a.ready?(a.hasFreq?'Hesaplandı':'Yol olasılıkları hesaplandı'):'Veri bekleniyor';$('calcStatus').className='pill '+(a.ready?'pill-pass':'pill-amber');
$('probNote').textContent=!a.n?'Henüz bariyer eklenmedi.':!a.ready?'Bariyerlerin adını ve 0–100 aralığında başarı oranlarını doldurun; eksik oranlarda yol olasılıkları hesaplanmaz.':`Olasılık kontrolü: sonuç yolları toplamı ${fmt(a.sumP*100,6)} % · ${a.hasFreq?'Başlangıç sıklığı ile yıllık sonuç sıklıkları hesaplandı.':'Yıllık sıklık için başlangıç olayı sıklığını girin.'}`;
let warnings=[];if(!model.analysisId.trim())warnings.push('Doküman numarası boş.');if(!model.initEvent.trim())warnings.push('Başlangıç olayı tanımlanmadı.');if(!a.n)warnings.push('En az bir güvenlik bariyeri ekleyin.');else if(!a.ready)warnings.push('Bariyer adı veya başarı olasılığı eksik / geçersiz.');if(!a.hasFreq)warnings.push('Başlangıç olayının yıllık sıklığı girilmedi / geçersiz.');if(a.counted<a.count)warnings.push(`${a.count-a.counted} sonuç yolunun etki sınıfı henüz belirlenmedi.`);
const q=$('qualityWarning');if(warnings.length){q.className='alert';q.innerHTML='<b>Analiz kontrolü:</b> '+esc(warnings.join(' '))}else{q.className='info';q.innerHTML='<b>Tamlık kontrolü başarılı:</b> Temel bilgiler, bariyer oranları ve tüm sonuç sınıfları girildi. Uzman doğrulaması ve kurumsal onay ayrıca gereklidir.';}}
function renderCalculated(){currentScenarios=getScenarios();resultRows();renderDiagram();renderSummary()}
function rebuild(){barrierRows();renderCalculated();scheduleSave()}
function getOutcome(sKey){if(!model.outcomes[sKey])model.outcomes[sKey]={severity:'',description:'',action:'',owner:'',due:''};return model.outcomes[sKey]}
function makeDownload(filename,content,mime){const b=new Blob([content],{type:mime});const url=URL.createObjectURL(b);const a=document.createElement('a');a.href=url;a.download=filename;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),3000)}
function safeFilename(v){return String(v||'ETA_Analizi').replace(/[^\w-]/g,'_').slice(0,70)}
function csvCell(v){let t=String(v??'');if(/^[\s]*[=+\-@\t\r]/.test(t))t="'"+t;return '"'+t.replace(/"/g,'""')+'"'}
function exportCSV(){if(!currentScenarios.length){setNotice('Önce bariyer ekleyin.');return}const headers=['Senaryo','Dallar','Yol Olasılığı (%)','Yıllık Sıklık','Sonuç Sınıfı','Olası Sonuç','Önerilen Aksiyon','Sorumlu','Hedef Tarih'];const lines=[headers,...currentScenarios.map(s=>[s.id,s.bits.map((v,i)=>`${model.barriers[i].name}: ${v==='S'?'Başarılı':'Başarısız'}`).join(' | '),s.probability===null?'':(s.probability*100).toPrecision(12),s.frequency===null?'':s.frequency.toPrecision(12),s.outcome.severity,s.outcome.description,s.outcome.action,s.outcome.owner,s.outcome.due])];makeDownload(safeFilename(model.analysisId)+'_ETA_Senaryolar.csv','\ufeff'+lines.map(row=>row.map(csvCell).join(';')).join('\r\n'),'text/csv;charset=utf-8');setNotice('Senaryo CSV dosyası indirildi.')}
function svgPrintClone(){if(currentScenarios.length>16||!diagramSVG)return '<div class="pr-small">Geniş olay ağacı şeması yazdırma düzenine alınmadı. Tam olay ağacı HTML görünümünde bulunur; tüm yollar sonuç tablosunda listelenmiştir.</div>';return `<div class="pr-tree">${diagramSVG.replace(/width="\d+" height="\d+" role="img"/,'width="100%" height="auto" role="img"')}</div>`;}
function printReport(){renderCalculated();const h=model.brand;const logo=h.logo||'logo.jpg';const img=$('brandLogo');const displayLogo=img&&img.complete&&img.naturalWidth; $('reportHeader').innerHTML=`<div class="report-header">${displayLogo?`<img src="${esc(img.dataset.printData||logo)}" alt="Logo">`:'<span style="font-weight:800;color:#70879c">LOGO</span>'}<div><strong>${esc(h.title)}</strong><small>${esc(h.sub)}</small></div><span class="print-org">${esc(h.org)}</span></div>`;
const cell=(label,v)=>`<div class="pr-field"><b>${esc(label)}</b>${esc(v===null||v===undefined||v===''?'—':v)}</div>`;const section=(heading,body)=>`<section class="pr-section"><h3>${esc(heading)}</h3>${body}</section>`;const a=getAnalysis();let html='';
html+=section('01 · Analiz ve Başlangıç Olayı',`<div class="pr-grid">${cell('Doküman No',model.analysisId)}${cell('Tarih',model.analysisDate)}${cell('Tesis / Birim',model.facility)}${cell('Hazırlayan',model.owner)}${cell('Olay Türü',model.eventType)}${cell('Proses',model.process)}${cell('Başlangıç Sıklığı (olay/yıl)',model.eventFrequency)}${cell('Revizyon',model.revision)}${cell('Başlangıç Olayı',model.initEvent)}${cell('Kapsam ve Varsayımlar',model.boundaries)}</div>`);
html+=section('02 · Analiz Özeti',`<div class="pr-summary"><div><small>Bariyer Sayısı</small><b>${a.n}</b></div><div><small>Olası Senaryo</small><b>${a.count}</b></div><div><small>Değerlendirilen</small><b>${a.counted} / ${a.count}</b></div><div><small>Ciddi / Kritik</small><b>${a.severe}</b></div><div><small>Ciddi / Kritik Sıklığı (olay/yıl)</small><b>${fmt(a.seriousFrequency,6)}</b></div></div>`);
html+=section('03 · Güvenlik Bariyerleri',`<table class="pr-table"><thead><tr><th style="width:5%">No</th><th style="width:25%">Bariyer</th><th style="width:31%">Başarı Kriteri</th><th style="width:11%">Başarı</th><th style="width:12%">Başarısızlık</th><th>Veri Kaynağı</th></tr></thead><tbody>${model.barriers.length?model.barriers.map((b,i)=>`<tr><td>${i+1}</td><td>${esc(b.name)}</td><td>${esc(b.criterion)}</td><td>${pSuccess(b)===null?'—':pct(pSuccess(b))}</td><td>${pSuccess(b)===null?'—':pct(1-pSuccess(b))}</td><td>${esc(b.note)}</td></tr>`).join(''):'<tr><td colspan="6">Bariyer kaydı bulunmuyor.</td></tr>'}</tbody></table>`);
html+=section('04 · Olay Ağacı Diyagramı',svgPrintClone());
html+=section('05 · Sonuç Senaryoları ve Kontrol Aksiyonları',`<table class="pr-table"><thead><tr><th style="width:5%">Kod</th><th style="width:17%">Dallar (B/H)</th><th style="width:9%">Olasılık</th><th style="width:10%">Sıklık/yıl</th><th style="width:7%">Etki</th><th style="width:19%">Olası Sonuç</th><th style="width:19%">Aksiyon</th><th style="width:8%">Sorumlu</th><th style="width:7%">Tarih</th></tr></thead><tbody>${currentScenarios.map(s=>`<tr><td>${s.id}</td><td>${s.bits.map((v,i)=>(i+1)+(v==='S'?'B':'H')).join(' · ')}</td><td>${pct(s.probability)}</td><td>${fmt(s.frequency,7)}</td><td>${esc(s.outcome.severity||'—')}</td><td>${esc(s.outcome.description)}</td><td>${esc(s.outcome.action)}</td><td>${esc(s.outcome.owner)}</td><td>${esc(s.outcome.due)}</td></tr>`).join('')}</tbody></table>`);
html+=section('06 · Değerlendirme ve Karar',`<div class="pr-grid">${cell('Karar',model.decision)}${cell('Kontrol Eden',model.reviewer)}${cell('Onaylayan',model.approver)}${cell('Genel Bulgular / Aksiyon Planı',model.generalNotes)}</div>`);
html+=`<div class="pr-sign"><div><b>Hazırlayan / İmza</b></div><div><b>Kontrol Eden / İmza</b></div><div><b>Onaylayan / İmza</b></div></div><div class="pr-small">Yöntem: P(yol|başlangıç)=dal olasılıkları çarpımı; yıllık sıklık=başlangıç sıklığı × yol olasılığı. Bariyer bağımlılıkları ve belirsizlikler uzman tarafından ayrıca doğrulanmalıdır. · Risk UI / ETA</div>`;
$('reportBody').innerHTML=html;}
// Main data fields. Recalculate frequency-dependent outputs without recreating the field being edited.
for(const field of scalarFields){$(field).addEventListener('input',e=>{model[field]=e.target.value;if(field==='eventFrequency')renderCalculated();else if(field==='initEvent'||field==='analysisId')renderSummary();scheduleSave()})}
$('barrierRows').addEventListener('input',e=>{const key=e.target.dataset.bprop;if(!key)return;const row=e.target.closest('tr[data-id]');if(!row)return;const b=model.barriers.find(z=>z.id===row.dataset.id);if(!b)return;b[key]=e.target.value;if(key==='success')row.querySelector('[data-failure-for]').textContent=pSuccess(b)===null?'—':fmt((1-pSuccess(b))*100,4)+' %';if(key==='name'||key==='success')renderCalculated();scheduleSave()});
$('barrierRows').addEventListener('click',e=>{const btn=e.target.closest('[data-action]');if(!btn)return;const row=btn.closest('tr[data-id]');const index=model.barriers.findIndex(b=>b.id===row.dataset.id);if(index<0)return;let action=btn.dataset.action;if(action==='remove'){if(!confirm('Bu bariyer silinsin mi? İlgili sonuç senaryolarının dalları yeniden oluşturulur.'))return;model.barriers.splice(index,1)}if(action==='up'&&index>0){[model.barriers[index-1],model.barriers[index]]=[model.barriers[index],model.barriers[index-1]]}if(action==='down'&&index<model.barriers.length-1){[model.barriers[index+1],model.barriers[index]]=[model.barriers[index],model.barriers[index+1]]}rebuild()});
$('resultRows').addEventListener('input',e=>{const key=e.target.dataset.oprop;if(!key)return;const row=e.target.closest('tr[data-key]');if(!row)return;const o=getOutcome(row.dataset.key);o[key]=e.target.value;if(e.target.tagName==='TEXTAREA')resizeScenarioTextarea(e.target);if(key==='severity'){e.target.className='outcome-'+e.target.value;const current=currentScenarios.find(s=>s.key===row.dataset.key);if(current)current.outcome=o;renderSummary();renderDiagram()}scheduleSave()});
// Width changes may reflow long paragraphs into new lines.
let scenarioResizePending=false;
window.addEventListener('resize',()=>{
 if(scenarioResizePending)return;
 scenarioResizePending=true;
 requestAnimationFrame(()=>{scenarioResizePending=false;resizeAllScenarioTextareas()});
});
$('addBarrierBtn').addEventListener('click',()=>{if(model.barriers.length>=6)return setNotice('En fazla 6 bariyer eklenebilir.');model.barriers.push({id:makeId(),name:'',criterion:'',success:'',note:''});rebuild();let arr=$('barrierRows').querySelectorAll('tr[data-id]');arr[arr.length-1]?.querySelector('[data-bprop=name]')?.focus()});
$('printBtn').addEventListener('click',printNow);window.addEventListener('beforeprint',printReport);
function clickToEdit(el,prop){let count=0,last=0;el.addEventListener('click',()=>{if(el.isContentEditable)return;const t=Date.now();count=(t-last<=1100)?count+1:1;last=t;if(count>=5){count=0;el.contentEditable='true';el.focus();const range=document.createRange();range.selectNodeContents(el);const sel=window.getSelection();sel.removeAllRanges();sel.addRange(range);setNotice('Başlık düzenleme açıldı. Çıkmak için dışarı tıklayın.')}});el.addEventListener('blur',()=>{if(el.contentEditable==='true'){el.contentEditable='false';el.textContent=el.textContent.trim().slice(0,180);model.brand[prop]=el.textContent;saveBrand()}});el.addEventListener('keydown',e=>{if(e.key==='Enter'){e.preventDefault();el.blur();}if(e.key==='Escape'){el.textContent=model.brand[prop];el.blur()}})}
clickToEdit($('headerTitle'),'title');clickToEdit($('headerSub'),'sub');clickToEdit($('headerOrg'),'org');
let logoClicks=0,logoLast=0;$('logoButton').addEventListener('click',()=>{const t=Date.now();logoClicks=t-logoLast<=1100?logoClicks+1:1;logoLast=t;if(logoClicks>=5){logoClicks=0;$('logoFile').click();}});$('logoFile').addEventListener('change',e=>{const file=e.target.files?.[0];e.target.value='';if(!file)return;if(!/^image\//.test(file.type)||file.size>1500000){setNotice('En fazla 1,5 MB boyutunda PNG / JPEG / WebP / GIF / SVG görsel seçin.');return}const r=new FileReader();r.onload=()=>{model.brand.logo=String(r.result);renderLogo();saveBrand();setNotice('Logo güncellendi.')};r.readAsDataURL(file)});

/* ETA / Risk UI: çevrimdışı, gerçek .xlsx giriş / çıkış altyapısı */
const asText=v=>v==null?'':String(v);
function xmlEsc(v){return asText(v).replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&apos;'}[c])).replace(/[\x00-\x08\x0b\x0c\x0e-\x1f]/g,'')}
function colLetter(num){let res='';for(let n=num;n>0;n=Math.floor((n-1)/26))res=String.fromCharCode(65+(n-1)%26)+res;return res}
function sheetXml(rows,{width=18,autoFilter=true}={}){
 const maxCols=Math.max(1,...rows.map(r=>r.length));const cols=Array.from({length:maxCols},(_,i)=>{let w=width;if(i===0)w=17;if(i===5||i===6||i===8||i===9||i===26)w=42;if(i===3||i===4||i===10)w=24;return `<col min="${i+1}" max="${i+1}" width="${w}" customWidth="1"/>`}).join('');
 const sheetRows=rows.map((row,i)=>`<row r="${i+1}">${row.map((value,j)=>{const c=colLetter(j+1)+(i+1),st=i===0?' s="1"':'';if(typeof value==='number'&&Number.isFinite(value))return `<c r="${c}"${st}><v>${value}</v></c>`;return `<c r="${c}" t="inlineStr"${st}><is><t xml:space="preserve">${xmlEsc(value)}</t></is></c>`}).join('')}</row>`).join('');
 return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetViews><sheetView workbookViewId="0"><pane ySplit="1" topLeftCell="A2" activePane="bottomLeft" state="frozen"/></sheetView></sheetViews><sheetFormatPr defaultRowHeight="16"/><cols>${cols}</cols><sheetData>${sheetRows}</sheetData>${autoFilter?`<autoFilter ref="A1:${colLetter(maxCols)}${Math.max(1,rows.length)}"/>`:''}</worksheet>`
}
const CRC_TABLE=(()=>{const result=[];for(let i=0;i<256;i++){let x=i;for(let j=0;j<8;j++)x=(x&1)?(0xedb88320^(x>>>1)):(x>>>1);result[i]=x>>>0}return result})();
function crc32(data){let crc=0xffffffff;for(const byte of data)crc=CRC_TABLE[(crc^byte)&255]^(crc>>>8);return (crc^0xffffffff)>>>0}
function zipCreate(entries){
 const enc=new TextEncoder(),pieces=[],centers=[];let offset=0;
 const u16=(view,pos,val)=>view.setUint16(pos,val,true),u32=(view,pos,val)=>view.setUint32(pos,val>>>0,true);
 function append(piece){pieces.push(piece);offset+=piece.length}
 for(const [filename,text] of entries){const name=enc.encode(filename),data=enc.encode(text),crc=crc32(data),local=new Uint8Array(30+name.length),dv=new DataView(local.buffer),begin=offset;
  u32(dv,0,0x04034b50);u16(dv,4,20);u16(dv,6,0x0800);u16(dv,8,0);u16(dv,10,0);u16(dv,12,0);u32(dv,14,crc);u32(dv,18,data.length);u32(dv,22,data.length);u16(dv,26,name.length);u16(dv,28,0);local.set(name,30);append(local);append(data);
  const cent=new Uint8Array(46+name.length),cv=new DataView(cent.buffer);u32(cv,0,0x02014b50);u16(cv,4,20);u16(cv,6,20);u16(cv,8,0x0800);u16(cv,10,0);u16(cv,12,0);u16(cv,14,0);u32(cv,16,crc);u32(cv,20,data.length);u32(cv,24,data.length);u16(cv,28,name.length);u16(cv,30,0);u16(cv,32,0);u16(cv,34,0);u16(cv,36,0);u32(cv,38,0);u32(cv,42,begin);cent.set(name,46);centers.push(cent)
 }
 const start=offset;for(const c of centers)append(c);const end=new Uint8Array(22),e=new DataView(end.buffer);u32(e,0,0x06054b50);u16(e,4,0);u16(e,6,0);u16(e,8,centers.length);u16(e,10,centers.length);u32(e,12,offset-start);u32(e,16,start);u16(e,20,0);append(end);return new Blob(pieces,{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
}

async function unzipEntries(arrayBuffer){const bytes=new Uint8Array(arrayBuffer),view=new DataView(arrayBuffer);let end=-1;for(let i=bytes.length-22;i>=Math.max(0,bytes.length-65557);i--)if(view.getUint32(i,true)===0x06054b50){end=i;break}if(end<0)throw new Error('Geçerli Excel ZIP yapısı bulunamadı.');const count=view.getUint16(end+10,true),base=view.getUint32(end+16,true),decoder=new TextDecoder(),entries={};let cursor=base;
 for(let i=0;i<count;i++){if(view.getUint32(cursor,true)!==0x02014b50)throw new Error('Excel dosyası merkezi dizini okunamadı.');const method=view.getUint16(cursor+10,true),compressed=view.getUint32(cursor+20,true),nameLength=view.getUint16(cursor+28,true),extra=view.getUint16(cursor+30,true),comment=view.getUint16(cursor+32,true),localOffset=view.getUint32(cursor+42,true),name=decoder.decode(bytes.subarray(cursor+46,cursor+46+nameLength));if(view.getUint32(localOffset,true)!==0x04034b50)throw new Error('Excel dosyası veri bölümü bozuk.');const start=localOffset+30+view.getUint16(localOffset+26,true)+view.getUint16(localOffset+28,true);const content=bytes.slice(start,start+compressed);if(method===0)entries[name]=decoder.decode(content);else if(method===8){if(typeof DecompressionStream!=='function')throw new Error('Bu tarayıcı sıkıştırılmış Excel içeri aktarmayı desteklemiyor. Güncel bir Chrome veya Edge tarayıcısı deneyin.');try{const stream=new Blob([content]).stream().pipeThrough(new DecompressionStream('deflate-raw'));entries[name]=decoder.decode(await new Response(stream).arrayBuffer())}catch(e){throw new Error('Excel sıkıştırması açılamadı: '+e.message)}}else throw new Error('Excel dosyasında desteklenmeyen sıkıştırma türü.');cursor+=46+nameLength+extra+comment;
 }return entries}
function parseXml(source){const doc=new DOMParser().parseFromString(source,'application/xml');if(doc.querySelector('parsererror'))throw new Error('Excel XML içeriği okunamadı.');return doc}
function parseXlsxSheet(source,shared=[]){if(!source)return [];const doc=parseXml(source),rows=[];for(const row of doc.getElementsByTagNameNS('*','row')){const cells=[];for(const c of row.getElementsByTagNameNS('*','c')){const ref=c.getAttribute('r')||'';let index=0;for(const letter of (ref.match(/^[A-Z]+/)||[''])[0])index=index*26+letter.charCodeAt(0)-64;index=Math.max(0,index-1);const type=c.getAttribute('t');let value='';if(type==='inlineStr')value=Array.from(c.getElementsByTagNameNS('*','t')).map(n=>n.textContent).join('');else{value=c.getElementsByTagNameNS('*','v')[0]?.textContent||'';if(type==='s')value=shared[Number(value)]||''}cells[index]=value}rows.push(cells)}return rows}

function normalizeDate(value){const str=asText(value);if(/^\d{4}-\d{2}-\d{2}$/.test(str))return str;if(/^\d{2}\.\d{2}\.\d{4}$/.test(str)){const a=str.split('.');return a[2]+'-'+a[1]+'-'+a[0]}const n=Number(value);if(Number.isFinite(n)&&n>=1&&n<100000)return new Date(Date.UTC(1899,11,30)+Math.floor(n)*86400000).toISOString().slice(0,10);return ''}


const excelMetaLabels={analysisId:'Analiz / Doküman No',analysisDate:'Analiz Tarihi',facility:'Tesis / Birim',owner:'Analizi Hazırlayan',eventType:'Olay Türü',process:'Proses / Faaliyet',eventFrequency:'Başlangıç Olayı Sıklığı (olay/yıl)',revision:'Revizyon / Durum',initEvent:'Başlangıç Olayı',boundaries:'Kapsam ve Varsayımlar',decision:'Değerlendirme Kararı',reviewer:'Kontrol / Gözden Geçiren',approver:'Onaylayan',generalNotes:'Genel Bulgular / Aksiyon Planı'};
const BARRIER_COLUMNS=['Bariyer ID','Sıra','Bariyer / Kontrol','Başarı Kriteri','Başarı Olasılığı (%)','Başarısızlık Olasılığı (%)','Veri Kaynağı / Not'];
const OUTCOME_COLUMNS=['Senaryo Kodu','Bariyer Dalları','Yol Olasılığı (%)','Sonuç Sıklığı (olay/yıl)','Sonuç Sınıfı (0-4)','Muhtemel Sonuç / Etki','Düzeltici / Önleyici Aksiyon','Sorumlu','Hedef Tarih','Senaryo Anahtarı'];
function etaWorkbookFiles(sheets){const types=`<?xml version="1.0" encoding="UTF-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>${sheets.map((s,i)=>`<Override PartName="/xl/worksheets/sheet${i+1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`).join('')}<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>`;
 const rels=`<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`;
 const workbook=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets>${sheets.map((s,i)=>`<sheet name="${xmlEsc(s.name)}" sheetId="${i+1}" r:id="rId${i+1}"/>`).join('')}</sheets></workbook>`;
 const wbRels=`<?xml version="1.0" encoding="UTF-8"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${sheets.map((s,i)=>`<Relationship Id="rId${i+1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet${i+1}.xml"/>`).join('')}<Relationship Id="rId${sheets.length+1}" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>`;
 const styles=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="2"><font><sz val="10"/><name val="Calibri"/></font><font><b/><sz val="10"/><color rgb="FFFFFFFF"/><name val="Calibri"/></font></fonts><fills count="3"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FF0369A1"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="2"><xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0"/><xf numFmtId="0" fontId="1" fillId="2" borderId="0" xfId="0" applyFont="1" applyFill="1"/></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
 return [['[Content_Types].xml',types],['_rels/.rels',rels],['xl/workbook.xml',workbook],['xl/_rels/workbook.xml.rels',wbRels],['xl/styles.xml',styles],...sheets.map((s,i)=>[`xl/worksheets/sheet${i+1}.xml`,sheetXml(s.rows,{autoFilter:i!==2,width:i===2?36:18})])];
}
function excelDownload(blob,name){const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=name;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),5000)}
function exportExcel(){try{renderCalculated();const barrierRowsData=[BARRIER_COLUMNS,...model.barriers.map((b,i)=>[b.id,i+1,b.name,b.criterion,pSuccess(b)===null?'':Number(b.success),pSuccess(b)===null?'':100-Number(b.success),b.note])];
 const outcomeRows=[OUTCOME_COLUMNS,...currentScenarios.map(s=>[s.id,s.bits.map((v,i)=>`${model.barriers[i].name}: ${v==='S'?'Başarı':'Başarısız'}`).join(' | '),s.probability===null?'':s.probability*100,s.frequency===null?'':s.frequency,s.outcome.severity,s.outcome.description,s.outcome.action,s.outcome.owner,s.outcome.due,s.key])];
 const metaRows=[['Alan','Değer'],['Yöntem','ETA - Olay Ağacı Analizi'],...scalarFields.map(k=>[excelMetaLabels[k],model[k]]),['Bariyer Sayısı',model.barriers.length],['Senaryo Sayısı',currentScenarios.length],['Koşullu Olasılık Notu','Bariyer dalı olasılıkları yol boyunca çarpılır; bağımlılıklar ayrıca değerlendirilmelidir.']];
 excelDownload(zipCreate(etaWorkbookFiles([{name:'ETA Bariyerleri',rows:barrierRowsData},{name:'ETA Senaryoları',rows:outcomeRows},{name:'Rapor Bilgileri',rows:metaRows}])),safeFilename(model.analysisId)+'_ETA_Risk_UI.xlsx');setNotice('ETA verileri 3 sayfalı Excel dosyasına aktarıldı.');}catch(err){console.error(err);alert('Excel dışarı aktarımı başarısız: '+err.message)}}
function columnsFor(row,expected){let pos=new Map(row.map((c,i)=>[asText(c).trim(),i]));for(const h of expected)if(!pos.has(h))throw new Error('Excel sayfasında eksik sütun: '+h);return pos}
function excelValue(row,idx,key){return asText(row[idx.get(key)]).trim()}
function dateFromExcel(v){const s=asText(v).trim();if(/^\d{4}-\d{2}-\d{2}$/.test(s))return s;if(/^\d{2}\.\d{2}\.\d{4}$/.test(s)){const a=s.split('.');return a[2]+'-'+a[1]+'-'+a[0]}const n=Number(s);if(s&&Number.isFinite(n)&&n>0&&n<100000)return new Date(Date.UTC(1899,11,30)+Math.floor(n)*86400000).toISOString().slice(0,10);return ''}
async function parseEtaExcel(file){if(!/\.xlsx$/i.test(file.name))throw Error('Yalnızca .xlsx biçimindeki Excel dosyaları içeri aktarılabilir.');if(file.size>15*1024*1024)throw Error('Excel dosyası 15 MB sınırını aşıyor.');const entries=await unzipEntries(await file.arrayBuffer());const shared=[];if(entries['xl/sharedStrings.xml']){let d=parseXml(entries['xl/sharedStrings.xml']);for(const item of d.getElementsByTagNameNS('*','si'))shared.push(Array.from(item.getElementsByTagNameNS('*','t')).map(x=>x.textContent).join(''))}
 const barriers=parseXlsxSheet(entries['xl/worksheets/sheet1.xml'],shared),outcomes=parseXlsxSheet(entries['xl/worksheets/sheet2.xml'],shared),info=parseXlsxSheet(entries['xl/worksheets/sheet3.xml'],shared);
 if(!barriers.length||!outcomes.length||!info.length)throw Error('Excel dosyası ETA şablonuna uygun üç sayfa içermiyor.');
 const bi=columnsFor(barriers[0],['Bariyer ID','Sıra','Bariyer / Kontrol','Başarı Olasılığı (%)']);const oi=columnsFor(outcomes[0],['Senaryo Kodu','Sonuç Sınıfı (0-4)','Senaryo Anahtarı','Muhtemel Sonuç / Etki','Düzeltici / Önleyici Aksiyon','Sorumlu','Hedef Tarih']);
 const modelNext=defaults(),seen=new Set(),barrierData=barriers.slice(1).filter(r=>r.some(v=>asText(v).trim()));if(barrierData.length>6)throw Error('ETA en fazla 6 güvenlik bariyerini destekliyor.');
 // Tekrarlanan, boş ya da atlayan Excel Sıra alanları güvenli biçimde yeniden sıralanır.
 // Eşit sıra numaralarında dosyadaki özgün satır dizilimi korunur.
 const ordered=barrierData.map((row,originalIndex)=>{
  const raw=excelValue(row,bi,'Sıra');const parsed=Number(raw);
  const order=raw!==''&&Number.isInteger(parsed)&&parsed>0?parsed:null;
  return {row,originalIndex,order};
 }).sort((a,b)=>(a.order??Number.MAX_SAFE_INTEGER)-(b.order??Number.MAX_SAFE_INTEGER)||a.originalIndex-b.originalIndex);
 modelNext._fixedBarrierOrder=ordered.some((x,i)=>x.order!==i+1);
 modelNext.barriers=ordered.map(({row:r},i)=>{const raw=excelValue(r,bi,'Başarı Olasılığı (%)').replace(',','.');if(raw&&!/^\d+(?:\.\d+)?$/.test(raw))throw Error((i+1)+'. bariyerin başarı yüzdesi hatalı.');const val=raw===''?'':Number(raw);if(val!==''&&(val<0||val>100))throw Error((i+1)+'. bariyerin başarı yüzdesi 0–100 dışında.');const id=excelValue(r,bi,'Bariyer ID')||makeId();if(seen.has(id))throw Error('Excel dosyasında yinelenen bariyer ID: '+id);seen.add(id);return {id:id.slice(0,35),name:excelValue(r,bi,'Bariyer / Kontrol').slice(0,120),criterion:excelValue(r,bi,'Başarı Kriteri').slice(0,250),success:String(val),note:excelValue(r,bi,'Veri Kaynağı / Not').slice(0,250)}});
 const canonicalPaths=getPathKeys(modelNext.barriers);
 const possibleKeys=new Set(canonicalPaths),canonicalCodes=new Map(canonicalPaths.map((key,i)=>[key,scenarioCode(i+1)]));
 const outcomeData=outcomes.slice(1).filter(r=>r.some(v=>asText(v).trim()));if(outcomeData.length>64)throw Error('ETA senaryo sayısı 64 sınırını aşıyor.');
 modelNext._fixedScenarioCodes=false;
 for(const r of outcomeData){const key=excelValue(r,oi,'Senaryo Anahtarı');if(!possibleKeys.has(key))throw Error('Senaryo anahtarı bariyer yapısına uymuyor.');if(modelNext.outcomes[key])throw Error('Yinelenen senaryo anahtarı mevcut.');if(excelValue(r,oi,'Senaryo Kodu')!==canonicalCodes.get(key))modelNext._fixedScenarioCodes=true;const severity=excelValue(r,oi,'Sonuç Sınıfı (0-4)');if(!['','0','1','2','3','4'].includes(severity))throw Error('Sonuç sınıfı 0–4 aralığında olmalıdır.');modelNext.outcomes[key]={severity,description:excelValue(r,oi,'Muhtemel Sonuç / Etki').slice(0,400),action:excelValue(r,oi,'Düzeltici / Önleyici Aksiyon').slice(0,400),owner:excelValue(r,oi,'Sorumlu').slice(0,150),due:dateFromExcel(excelValue(r,oi,'Hedef Tarih'))};}
 const map=new Map(info.slice(1).map(r=>[asText(r[0]).trim(),asText(r[1])]));for(const k of scalarFields)if(map.has(excelMetaLabels[k]))modelNext[k]=k==='analysisDate'?dateFromExcel(map.get(excelMetaLabels[k])):asText(map.get(excelMetaLabels[k])).slice(0,k==='generalNotes'?3000:1600);
 if(modelNext.eventFrequency&&!/^\d+(?:[\.,]\d+)?(?:e[+-]?\d+)?$/i.test(modelNext.eventFrequency))throw Error('Başlangıç olayı sıklığı geçersiz.');modelNext.eventFrequency=modelNext.eventFrequency.replace(',','.');return modelNext;
}
function getPathKeys(barriers){if(!barriers.length)return [];const count=1<<barriers.length;return Array.from({length:count},(_,i)=>barriers.map((b,j)=>b.id+':'+(((i>>(barriers.length-j-1))&1)===0?'S':'F')).sort().join('|'))}
async function importExcel(file){if(!file)return;try{const imported=await parseEtaExcel(file);if((model.barriers.length||model.initEvent||model.analysisId)&&!confirm('Excel dosyası mevcut ETA analizinin yerini alacak. Devam edilsin mi?'))return;const currentBrand=model.brand,corrected=imported._fixedBarrierOrder||imported._fixedScenarioCodes;
 model=imported;model.brand=currentBrand;delete model._fixedBarrierOrder;delete model._fixedScenarioCodes;
 renderFields();rebuild();setNotice('Excel: '+model.barriers.length+' bariyer ve '+currentScenarios.length+' senaryo yüklendi. '+(corrected?'Tekrarlanan / hatalı sıra kodları benzersiz ve artan olarak düzeltildi.':'Sıra numaraları benzersiz ve artan.'));}catch(e){console.error(e);alert('Excel içeri aktarımı başarısız: '+e.message)}finally{$('excelFile').value=''}}
async function readyPrintLogo(){const img=$('brandLogo');if(!img||!img.complete||!img.naturalWidth)return;try{const canvas=document.createElement('canvas'),ratio=Math.min(1,512/Math.max(img.naturalWidth,img.naturalHeight));canvas.width=Math.max(1,Math.round(img.naturalWidth*ratio));canvas.height=Math.max(1,Math.round(img.naturalHeight*ratio));canvas.getContext('2d').drawImage(img,0,0,canvas.width,canvas.height);img.dataset.printData=canvas.toDataURL('image/png')}catch(e){img.dataset.printData=''}}
async function printNow(){await readyPrintLogo();printReport();try{await document.fonts.ready}catch(e){}await new Promise(r=>requestAnimationFrame(()=>requestAnimationFrame(r)));window.print()}
$('importExcelBtn').addEventListener('click',()=>$('excelFile').click());
$('exportExcelBtn').addEventListener('click',exportExcel);
$('excelFile').addEventListener('change',e=>importExcel(e.target.files?.[0]));

// Yeni sayfa açılışı, F5/Ctrl+R ve geri-ileri önbelleği aynı boş analiz görünümüyle başlar.
 // Kayıtlar yerel depolamaya yazılmaz; sadece kurumsal başlık/logo tercihi korunur.
 function resetOnOpen(){
  const keepBrand={...model.brand};
  model=defaults();model.brand=keepBrand;currentScenarios=[];diagramSVG='';
  document.querySelectorAll('#uiShell input,#uiShell textarea,#uiShell select').forEach(el=>{
   el.setAttribute('autocomplete','off');
   if(el.type==='file'){el.value='';return}
   if(el.type==='checkbox'||el.type==='radio')el.checked=false;
   else if(el.tagName==='SELECT')el.selectedIndex=0;
   else el.value='';
  });
  $('reportHeader').replaceChildren();$('reportBody').replaceChildren();
  renderFields();barrierRows();renderCalculated();
 }
 loadBrand();resetOnOpen();
 // Bazı tarayıcılar form değerlerini JS başlangıcından sonra geri yükler.
 // pageshow sonrasında bir kez daha senkronize etmek bu davranışı da önler.
 window.addEventListener('pageshow',()=>{
  requestAnimationFrame(()=>{resetOnOpen();window.scrollTo(0,0)});
 });
})();
</script>
</body>
</html>