<!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> | Sayfa yenilendiğinde analiz temizlenir. Kalıcı saklamak için Excel Dışarı Aktar kullanın; bilgiler sunucuya gönderilmez. | 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=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[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>