<!doctype html>
<html lang="tr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light">
<title>İSG Ramak Kala Bildirim Formu</title>
<style>
:root{--blue:#0284c7;--blue-dark:#075985;--ink:#15283a;--muted:#65788a;--line:#cbd5df;--bg:#e2eaf1;--panel:#fff;--soft:#f8fafc;--red:#b91c1c;--amber:#92400e;--green:#166534}
*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;background:#dbe5ee;font:13px/1.43 "Segoe UI",Arial,sans-serif;color:var(--ink)}button,input,select,textarea{font:inherit}button{cursor:pointer}
.app{width:100%;min-height:100vh;padding:9px;background:var(--bg);border:3px solid #8498aa;border-top:6px solid var(--blue)}
.shell{width:100%;min-height:calc(100vh - 27px);border:1px solid #c6d1dc;background:var(--soft);padding:11px;box-shadow:0 2px 12px #1736530b}
.header{display:flex;align-items:center;gap:15px;background:#fff;border:1px solid var(--line);border-left:4px solid var(--blue);padding:10px 13px;min-width:0;border-radius:5px}
.logo-box{flex:none;width:76px;height:69px;border:1px solid #c7d5e0;border-radius:5px;background:#fff;display:flex;align-items:center;justify-content:center;overflow:hidden;user-select:none;cursor:pointer}
.logo-box img{display:block;width:100%;height:100%;object-fit:contain}
.logo-fallback{font-size:11px;letter-spacing:1.1px;text-align:center;font-weight:800;color:var(--blue-dark)}
.header-titles{min-width:0;flex:1}.main-title{font-size:20px;line-height:1.22;color:#093c62;font-weight:800;overflow-wrap:anywhere}.sub-title{margin-top:4px;font-size:12px;color:#526c82;overflow-wrap:anywhere}
.brand{flex:0 1 35%;max-width:430px;min-width:175px;align-self:stretch;display:flex;align-items:center;justify-content:flex-end;text-align:right;font-size:15px;line-height:1.25;letter-spacing:.3px;font-weight:800;color:#26475f;overflow-wrap:anywhere;cursor:pointer;user-select:none}
.editable{cursor:pointer}.edit-hint{display:none}
.toolbar{margin:8px 0 11px;display:flex;justify-content:flex-start;align-items:center;gap:10px;flex-wrap:wrap}
.toolbar-frame{background:#fff;border:1px solid var(--line);padding:7px;display:flex;gap:7px;flex-wrap:wrap;border-radius:5px}
.btn{border:1px solid #b8c9d8;border-radius:5px;padding:9px 13px;color:#17415b;font-weight:700;white-space:nowrap;box-shadow:0 1px 1px #2342a10b}
.btn:focus-visible,.logo-box:focus-visible,.editable:focus-visible{outline:2px solid var(--blue);outline-offset:2px}.btn:hover{filter:brightness(.97)}
.btn-import{background:#dff1ff;border-color:#8bcff5}.btn-export{background:#dff7e5;border-color:#9cd7ac;color:#17623a}.btn-print{background:#eaedf1;border-color:#c3ccd5;color:#344559}
.toolbar-message{font-size:12px;color:var(--muted);min-width:0}.toolbar-message.good{color:var(--green)}.toolbar-message.error{color:var(--red)}
.record-picker{background:#fff;border:1px solid var(--line);padding:7px 9px;border-radius:5px;display:none;align-items:center;gap:8px}.record-picker select{max-width:250px}
.workspace{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px;align-items:stretch;min-height:calc(100vh - 263px)}
.stack{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px;min-width:0;grid-column:1/-1;align-items:stretch}.panel{height:100%;display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:5px;box-shadow:0 1px 3px #19375308;overflow:hidden;break-inside:avoid-page;page-break-inside:avoid}
.panel-head{display:flex;align-items:center;gap:9px;padding:9px 12px;background:#edf5fb;border-bottom:1px solid #d5e2ec;min-height:39px}
.step{width:21px;height:21px;flex:none;border-radius:4px;background:#deedf8;border:1px solid #a1cadf;color:#0a5989;display:grid;place-items:center;font-size:11px;font-weight:800}
.panel-head h2{font-size:13px;margin:0;color:#154866;line-height:1.24}.panel-head small{color:#7a8c9b;margin-left:auto;font-size:10px}
.panel-body{padding:11px 12px;flex:1;display:flex;flex-direction:column}.fields{flex:1;align-content:space-around;display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:9px 11px}.field{display:flex;flex-direction:column;min-width:0;gap:4px;grid-column:span 6}
.field.full{grid-column:span 12}.field.third{grid-column:span 4}.field.quarter{grid-column:span 3}.field.two-third{grid-column:span 8}
.field label{font-weight:650;font-size:11.5px;color:#405669;line-height:1.2}.required::after{content:" *";color:#ba2b34;font-weight:bold}
.field :is(input,select,textarea){width:100%;min-width:0;border:1px solid #c5d1db;border-radius:4px;background:#fff;color:#152a3b;padding:7px 8px;height:35px;outline-offset:1px}
.field textarea{height:68px;min-height:60px;line-height:1.35;resize:vertical;padding-top:7px}
.field :is(input,select,textarea):focus{border-color:#0284c7;outline:2px solid #e1f2fd}.field input[readonly]{background:#eef4f8;color:#143e58;font-weight:750}
[hidden]{display:none!important}
.field .invalid{border-color:#c23a42 !important;background:#fff8f8 !important}.note{color:#748799;font-size:11px}.section-note{font-size:11px;color:#587080;margin:-2px 0 9px}
.warn{background:#fff7e6;border:1px solid #f4d49f;border-radius:5px;padding:8px 10px;font-size:11.5px;color:#7b4d11;margin-bottom:10px;display:none}
.bottom{margin-top:11px;border:1px solid #cad7e2;border-radius:5px;background:white;padding:9px 12px;display:flex;gap:12px;align-items:center;justify-content:space-between;color:#627b8e;font-size:10.5px;flex-wrap:wrap}
.bottom a{color:#0c6699;text-decoration:none}.legal{text-align:right}.print-only{display:none}
@media(max-width:1100px){.field.third{grid-column:span 6}.field.quarter{grid-column:span 6}}
@media(max-width:850px){.workspace{min-height:0}.stack{grid-template-columns:1fr}.panel{display:block}.panel-body{display:block}.fields{align-content:start}.app{padding:4px}.shell{padding:6px}.header{gap:9px;padding:8px}.logo-box{width:58px;height:57px}.main-title{font-size:16px}.sub-title{font-size:11px}.brand{min-width:0;flex:0 1 37%;font-size:11.5px}.workspace{grid-template-columns:1fr}.field.third,.field.quarter{grid-column:span 6}.toolbar-message{flex-basis:100%}.btn{padding:8px 10px;font-size:11px}}
@media(max-width:425px){.header{flex-wrap:wrap}.brand{flex-basis:100%;max-width:none;align-self:auto;justify-content:flex-start;text-align:left;border-top:1px solid #e2e9ef;padding-top:6px}.field{grid-column:span 12}.field.third,.field.quarter,.field.two-third{grid-column:span 12}.toolbar-frame{width:100%}.btn{flex:1}.panel-body{padding:10px}}
/* OLGUN UI2 bildirim formu: yatay iki panelli sayfa ve kategori yönetimi */
.workspace{min-height:calc(100vh - 220px)}.stack{align-items:stretch}.panel-body{padding:11px 13px}.fields{align-content:start;gap:10px 11px}.field{gap:5px}.field textarea{height:79px;min-height:65px}.field input,.field select{height:36px}
/* Print-only mirrors are populated from the input fields by JavaScript. */
.print-value{display:none}
/* OLGUN UI2 - clean A4 portrait print: natural card heights, generous page whitespace */
@page{size:A4 portrait;margin:13mm 12mm 15mm}
@media print{
html,body{margin:0!important;padding:0!important;width:auto!important;height:auto!important;overflow:visible!important;background:white!important;-webkit-print-color-adjust:exact!important;print-color-adjust:exact!important}
.app,.shell{min-height:0!important;height:auto!important;width:100%!important;margin:0!important;padding:0!important;border:0!important;box-shadow:none!important;background:#fff!important}
.shell{max-width:184mm!important;margin:0 auto!important;display:block!important}
.header{display:flex!important;align-items:center!important;min-height:19mm!important;height:auto!important;gap:3mm!important;margin:0 0 6mm!important;padding:2.5mm 3mm!important;border:1px solid #d0dce5!important;border-left:3px solid #0284c7!important;border-radius:2mm!important;background:#fff!important;overflow:visible!important}
.logo-box{height:14.5mm!important;width:16mm!important;flex:0 0 16mm!important;border-radius:1.5mm!important}
.header-titles{min-width:0!important;flex:1 1 auto!important}.main-title{font-size:16.2px!important;line-height:1.2!important;color:#103e60!important}.sub-title{font-size:10px!important;line-height:1.25!important;margin-top:1.5mm!important}
.brand{min-width:0!important;max-width:36%!important;flex:0 1 36%!important;font-size:10.5px!important;line-height:1.23!important;align-self:center!important}
.toolbar,.bottom,.print-ending,.no-print{display:none!important}
.workspace{display:block!important;min-height:0!important;height:auto!important;width:100%!important;margin:0!important;padding:0!important}
.stack{display:flex!important;flex-direction:column!important;gap:5mm!important;min-height:0!important;height:auto!important;width:100%!important;align-items:stretch!important}
.panel{display:block!important;height:auto!important;min-height:0!important;min-width:0!important;margin:0!important;border:1px solid #c7d5df!important;border-radius:1.8mm!important;box-shadow:none!important;overflow:visible!important;break-inside:avoid-page!important;page-break-inside:avoid-page!important;background:#fff!important}
.panel-head{display:flex!important;align-items:center!important;min-height:8.5mm!important;height:auto!important;padding:1.6mm 3mm!important;background:#edf5fb!important;border-bottom:1px solid #d8e4ed!important}
.step{width:5.1mm!important;height:5.1mm!important;flex:0 0 5.1mm!important;font-size:10px!important;border-radius:1mm!important}
.panel-head h2{font-size:12.1px!important;line-height:1.2!important}.panel-head small{display:none!important}
.panel-body{display:block!important;min-height:0!important;flex:none!important;padding:3.6mm!important}
.fields{display:grid!important;grid-template-columns:repeat(12,minmax(0,1fr))!important;align-content:start!important;grid-auto-rows:auto!important;row-gap:2.9mm!important;column-gap:3.2mm!important;min-height:0!important;flex:none!important}
.field{display:flex!important;flex-direction:column!important;gap:1.2mm!important;min-width:0!important}
.field.third{grid-column:span 4!important}.field.quarter{grid-column:span 3!important}.field.two-third{grid-column:span 8!important}.field.full{grid-column:span 12!important}
.field label{font-size:10.4px!important;line-height:1.22!important;color:#40586b!important;font-weight:650!important}
.field :is(input,select,textarea){display:none!important}
.print-value{display:block!important;min-height:8.2mm!important;height:auto!important;padding:1.65mm 2mm!important;border:1px solid #d2dce5!important;border-radius:1mm!important;background:#fff!important;color:#203646!important;font-size:10.7px!important;line-height:1.33!important;white-space:pre-wrap!important;overflow-wrap:anywhere!important;word-break:break-word!important;max-height:none!important}
.field:has(textarea) .print-value{min-height:17mm!important}
#otherHazardWrap[hidden]{display:none!important}
}
</style>
</head>
<body>
<div class="app"><div class="shell">
<header class="header">
<div id="logoBox" class="logo-box" title="Logoyu değiştirmek için 5 kez tıklayın" role="button" tabindex="0" aria-label="Beş kez tıklayarak logo seçin">
<img id="companyLogo" src="logo.jpg" alt="Kurum logosu" onerror="this.hidden=true;document.getElementById('logoFallback').hidden=false">
<div class="logo-fallback" id="logoFallback" hidden>LOGO<br>İSG</div>
</div>
<div class="header-titles"><div class="main-title editable" id="mainTitle" tabindex="0" title="Beş kez tıklayarak düzenleyin">İSG Ramak Kala Bildirim Formu</div><div class="sub-title editable" id="subTitle" tabindex="0" title="Beş kez tıklayarak düzenleyin">(Ramak Kala ve Tehlikeli Durum Bildirimi)</div></div>
<div class="brand editable" id="institution" tabindex="0" title="Beş kez tıklayarak düzenleyin">OLGUN BAŞKANLIĞI</div>
</header>
<nav class="toolbar no-print" aria-label="Form işlemleri">
<div class="toolbar-frame">
<button id="importBtn" class="btn btn-import" type="button">Excel İçeri Aktar</button>
<button id="exportBtn" class="btn btn-export" type="button">Excel Dışarı Aktar</button>
<button id="printBtn" class="btn btn-print" type="button">PDF / Yazdır</button>
</div>
<div class="record-picker" id="recordPicker"><label for="recordSelect"><strong>İçe alınan kayıt:</strong></label><select id="recordSelect"></select></div>
<div class="toolbar-message" id="message" role="status" aria-live="polite">Kayıt bilgileri yalnızca bu tarayıcıda işlenir; otomatik olarak gönderilmez.</div>
<input type="file" id="excelFile" accept=".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" hidden>
<input type="file" id="logoFile" accept="image/*" hidden>
</nav>
<main class="workspace" id="formWorkspace">
<div class="stack">
<section class="panel"><div class="panel-head"><span class="step">01</span><h2>Bildiren Kişi ve Ramak Kala Bilgileri</h2><small>* Önemli alan</small></div><div class="panel-body">
<div class="fields">
<div class="field third"><label class="required" for="reportDate">Bildirim Tarihi</label><input type="date" id="reportDate"></div>
<div class="field third"><label for="department">Birim / Bölüm</label><input id="department" placeholder="Örn. Bakım, depo"></div>
<div class="field third"><label for="reporter">Bildiren Kişi</label><input id="reporter" placeholder="Ad soyad / anonim"></div>
<div class="field third"><label for="involved">Olayı Yaşayan Kişi</label><input id="involved" placeholder="Ad soyad (varsa)"></div>
<div class="field third"><label for="role">Görevi</label><input id="role" placeholder="Görev / ünvan"></div>
<div class="field third"><label class="required" for="eventDate">Olay Tarihi</label><input id="eventDate" type="date"></div>
<div class="field third"><label for="eventTime">Olay Saati</label><input id="eventTime" type="time"></div>
<div class="field third"><label for="shift">Vardiya</label><select id="shift"><option value="">Seçiniz</option><option>Gündüz</option><option>Gece</option><option>1. Vardiya</option><option>2. Vardiya</option><option>3. Vardiya</option><option>Diğer</option></select></div>
<div class="field two-third"><label class="required" for="place">Olay Yeri / Konum</label><input id="place" placeholder="Bina, kat, hat, oda / saha"></div>
<div class="field third"><label for="affected">Etkilenebilecek Kişi Sayısı</label><input id="affected" type="number" min="0" max="99999" placeholder="0"></div>
<div class="field full"><label for="witnesses">Tanıklar / İlgili Ekipman</label><input id="witnesses" placeholder="Tanık bilgisi, makine veya ekipman adı (varsa)"></div>
</div>
</div></section>
<section class="panel"><div class="panel-head"><span class="step">02</span><h2>Tehlikenin Tanımı ve Önleme Önerisi</h2></div><div class="panel-body">
<div class="fields">
<div class="field full"><label class="required" for="hazard">Tehlike / Olay Kategorisi</label><select id="hazard"><option value="">Tehlike kategorisi seçiniz</option>
<optgroup label="Çalışma Ortamı"><option>Islak/Kaygan Zemin</option><option>Dökülme/Saçılma</option><option>Kapatılmamış Boşluk/Aralıklar</option><option>Düzensiz Ortam/Dağınıklık</option><option>Yetersiz Aydınlatma</option><option>Yüksek Ses/Gürültü</option><option>Tozlu Ortam</option><option>Kötü Koku</option><option>İklimlendirme - Isıtma/Soğutma</option><option>Ergonomik Uygunsuzluk</option><option>Kötü Çalışma Ortamı</option></optgroup>
<optgroup label="Teknik / Ekipman"><option>Elektrik Sisteminde Tehlikeli Açıklık</option><option>Elektrik Sisteminde Arıza</option><option>Bozuk El Aleti</option><option>Periyodik Bakım Eksikliği</option><option>Emniyetsiz İstifleme / Devrilme</option><option>Emniyetsiz Kaldırma</option><option>Hatalı veya Arızalı Ekipman</option><option>Arızalı Ekipman Kullanımı</option><option>Ekipman Kullanım Hatası</option></optgroup>
<optgroup label="Acil Durum ve Koruma"><option>Yangın Tehlikesi</option><option>Problemli Söndürme Cihazı</option><option>Yetersiz İkaz/Uyarı Levhası</option><option>Yetersiz Alarm Sistemi</option><option>Patlama Tehlikesi</option><option>KKD Kullanılmaması</option><option>KKD Eksikliği/Uygunsuzluğu</option></optgroup>
<optgroup label="Çalışma Yöntemi / İnsan Faktörleri"><option>Kurallara Uyulmaması</option><option>Dalgınlık</option><option>Yorgunluk</option><option>Stres</option><option>Heyecan/Öfke</option><option>Güvensizlik</option><option>Aşırı Yük Kaldırmak</option><option>İşbirliği Noksanlığı</option><option>Uygun Olmayan Hız</option><option>Yetkisiz Çalışma</option><option>Talimatlara Uymamak</option><option>Disiplinsiz/Ciddiyetsiz Çalışma</option></optgroup>
<option>Diğer</option></select></div>
<div class="field full" id="otherHazardWrap" hidden><label class="required" for="otherHazard">Diğer Tehlike Açıklaması</label><input id="otherHazard" placeholder="Yalnız bu bildirime özgü tehlikeyi yazın"></div>
<div class="field full"><label class="required" for="description">Olayı Kısaca Açıklayınız (Ne oldu, nasıl gerçekleşti?)</label><textarea id="description" placeholder="Gözlenen olayı nesnel biçimde anlatınız. Suçlayıcı ifade yerine olayın koşullarını yazınız."></textarea></div>
<div class="field full"><label for="suggestion">İyileştirme Öneriniz</label><textarea id="suggestion" placeholder="Olayın tekrarını önlemek için hangi düzenleme yapılabilir?"></textarea></div>
<div class="field full"><label for="potentialOutcome">Olası En Kötü Sonuç</label><input id="potentialOutcome" placeholder="Örn. ciddi yaralanma, düşme, yangın, üretim kesintisi"></div>
<div class="field full"><label for="preventedBy">Zararı Engelleyen Unsur / Koşul</label><input id="preventedBy" placeholder="Örn. bariyer, uyarı, zamanında müdahale, tesadüf"></div>
</div>
</div></section>
</div>
</main>
<div class="bottom no-print"><div>Tek bildirim · Çevrimdışı kullanım · Dikey .xlsx · Hazır tehlike listesi</div><div class="legal">Bu form yalnızca bildirim içindir; İSG incelemesi ve faaliyet yönetimi ilgili birim tarafından ayrıca yürütülür.</div></div>
<div class="print-only print-ending">Ramak kala bildirim kaydı · İlgili birime iletilmek üzere</div>
</div></div>
<input type="hidden" id="hazardGroup" value="">
<script>
'use strict';
(() => {
const $ = id => document.getElementById(id);
const specs = [
['reportDate','Bildirim Tarihi'],['department','Birim / Bölüm'],['reporter','Bildiren Kişi'],['involved','Olayı Yaşayan Kişi'],['role','Olayı Yaşayanın Görevi'],
['eventDate','Olay Tarihi'],['eventTime','Olay Saati'],['shift','Vardiya'],['place','Olay Yeri / Konum'],['affected','Etkilenebilecek Kişi Sayısı'],['witnesses','Tanıklar / İlgili Ekipman'],
['hazardGroup','Tehlike Kategori Başlığı'],['hazard','Tehlike / Olay Kategorisi'],['otherHazard','Diğer Tehlike Açıklaması'],['description','Olay Açıklaması'],['suggestion','İyileştirme Önerisi'],['potentialOutcome','Olası En Kötü Sonuç'],['preventedBy','Zararı Engelleyen Unsur']
];
const norm = s => String(s??'').trim().toLocaleLowerCase('tr-TR').replace(/[\u00a0\s]+/g,' ').replace(/[^a-z0-9ğüşıöç\/\- ]/gi,'');
const fieldMap = new Map(specs.map(([id,label]) => [norm(label),id]));
const encode = s => String(s??'').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
let allRecords=[]; let selectedLogoUrl=null;
function msg(s,level=''){ $('message').textContent=s; $('message').className='toolbar-message '+level; }
// Hazır tehlike kategorileri sabittir; liste düzenleme/ekleme/silme işlemi bulunmaz.
const categories=[...$('hazard').querySelectorAll('optgroup')].map(g=>({name:g.label,items:[...g.querySelectorAll('option')].map(o=>o.textContent.trim())}));
function findGroup(value){const group=categories.find(g=>g.items.includes(value));return group?group.name:'';}
function renderHazards(selected=''){
const sel=$('hazard');sel.replaceChildren();
const placeholder=document.createElement('option');placeholder.value='';placeholder.textContent='Tehlike seçiniz';sel.appendChild(placeholder);
for(const cat of categories){const group=document.createElement('optgroup');group.label=cat.name;
for(const item of cat.items){const option=document.createElement('option');option.value=item;option.textContent=item;group.appendChild(option);}sel.appendChild(group);}
const other=document.createElement('option');other.value='Diğer';other.textContent='Diğer';sel.appendChild(other);
sel.value=[...sel.options].some(o=>o.value===selected)?selected:'';
update();
}
function values(){return Object.fromEntries(specs.map(([id])=>[id,$(id).value.trim()]));}
function update(){
const value=$('hazard').value;
$('hazardGroup').value=value==='Diğer'?'Diğer':findGroup(value);
$('otherHazardWrap').hidden=value!=='Diğer';
updatePrintValues();
}
// Eski dosyalarda listede artık bulunmayan bir tehlike varsa veri kaybetmeden "Diğer" olarak aç.
function assign(row){
const rec={...row};const hazard=String(rec.hazard||'').trim();
if(hazard&&hazard!=='Diğer'&&!findGroup(hazard)){
rec.hazard='Diğer';
rec.otherHazard=rec.otherHazard||hazard;
}
renderHazards(rec.hazard||'');
for(const [id] of specs){if(id==='hazardGroup')continue;$(id).value=rec[id]??'';}
update();
}
for(const [id] of specs){let el=$(id);if(el.type==='hidden')continue;el.addEventListener('input',update);el.addEventListener('change',update);}
// Yazdırmada hiçbir bilginin giriş alanı sınırlarında kesilmemesi için metin eşleri kullanılır.
for(const f of document.querySelectorAll('main .field')){const el=f.querySelector('input,select,textarea');if(!el)continue;const view=document.createElement('div');view.className='print-value';view.setAttribute('aria-hidden','true');f.appendChild(view);}
function updatePrintValues(){for(const f of document.querySelectorAll('main .field')){const el=f.querySelector('input,select,textarea'),v=f.querySelector('.print-value');if(!el||!v)continue;let value=el.value||'';if(el.id==='hazard'&&value==='Diğer')value='Diğer';if(el.type==='date'&&/^\d{4}-\d{2}-\d{2}$/.test(value)){const [y,m,d]=value.split('-');value=`${d}.${m}.${y}`;}v.textContent=value||'—';}}
renderHazards('');
// Yazdırırken uzun açıklamaları kesmeden göstermek için metin alanlarının yüksekliğini geçici büyüt.
window.addEventListener('beforeprint',()=>{updatePrintValues();});
$('printBtn').onclick=()=>{update();window.print()};
// XLSX oluşturma: üçüncü taraf kütüphane veya ağ bağlantısı olmadan ZIP (STORE) + OOXML.
const enc=new TextEncoder(),dec=new TextDecoder();
function crc32(data){let c=0xffffffff;for(const b of data){c^=b;for(let j=0;j<8;j++) c=(c>>>1)^((c&1)?0xedb88320:0);}return (c^0xffffffff)>>>0;}
function u16(v){return [v&255,v>>>8&255];}function u32(v){return [v&255,(v>>>8)&255,(v>>>16)&255,(v>>>24)&255];}
function zipStored(entries){const parts=[],cent=[];let offset=0;for(const [name,raw] of entries){const n=enc.encode(name),data=enc.encode(raw),crc=crc32(data);
const local=new Uint8Array([...u32(0x04034b50),...u16(20),...u16(0x0800),...u16(0),...u16(0),...u16(0),...u32(crc),...u32(data.length),...u32(data.length),...u16(n.length),...u16(0),...n]);parts.push(local,data);
const central=new Uint8Array([...u32(0x02014b50),...u16(20),...u16(20),...u16(0x0800),...u16(0),...u16(0),...u16(0),...u32(crc),...u32(data.length),...u32(data.length),...u16(n.length),...u16(0),...u16(0),...u16(0),...u16(0),...u32(0),...u32(offset),...n]);cent.push(central);offset+=local.length+data.length;
} const cenSize=cent.reduce((n,a)=>n+a.length,0);const end=new Uint8Array([...u32(0x06054b50),...u16(0),...u16(0),...u16(cent.length),...u16(cent.length),...u32(cenSize),...u32(offset),...u16(0)]);return new Blob([...parts,...cent,end],{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});}
function xmlCell(ref,v,style){const str=String(v??'');return `<c r="${ref}" s="${style}" t="inlineStr"><is><t xml:space="preserve">${encode(str)}</t></is></c>`;}
function xlsxExport(){
update();const data=values(); const rows=[['Alan','Değer'],...specs.map(([id,label])=>[label,data[id]])];
const sheetRows=rows.map((r,i)=>`<row r="${i+1}" ht="${i===0?29:23}" customHeight="1">${r.map((v,j)=>xmlCell((j?'B':'A')+(i+1),v,i===0?1:j===0?2:(i%2?0:3))).join('')}</row>`).join('');
const sheet=`<?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><cols><col min="1" max="1" width="44" customWidth="1"/><col min="2" max="2" width="82" customWidth="1"/></cols><sheetData>${sheetRows}</sheetData><autoFilter ref="A1:B${rows.length}"/><pageMargins left="0.4" right="0.4" top="0.5" bottom="0.5" header="0.2" footer="0.2"/></worksheet>`;
const styles=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><fonts count="3"><font><sz val="11"/><name val="Calibri"/></font><font><b/><color rgb="FFFFFFFF"/><sz val="12"/><name val="Calibri"/></font><font><b/><color rgb="FF154866"/><sz val="11"/><name val="Calibri"/></font></fonts><fills count="4"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill><fill><patternFill patternType="solid"><fgColor rgb="FF0284C7"/><bgColor indexed="64"/></patternFill></fill><fill><patternFill patternType="solid"><fgColor rgb="FFF1F6FA"/><bgColor indexed="64"/></patternFill></fill></fills><borders count="2"><border><left/><right/><top/><bottom/><diagonal/></border><border><left style="thin"><color rgb="FFD1DEE9"/></left><right style="thin"><color rgb="FFD1DEE9"/></right><top style="thin"><color rgb="FFD1DEE9"/></top><bottom style="thin"><color rgb="FFD1DEE9"/></bottom><diagonal/></border></borders><cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs><cellXfs count="4"><xf numFmtId="0" fontId="0" fillId="0" borderId="1" xfId="0"><alignment vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="1" fillId="2" borderId="1" xfId="0"><alignment vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="2" fillId="3" borderId="1" xfId="0"><alignment vertical="center" wrapText="1"/></xf><xf numFmtId="0" fontId="0" fillId="3" borderId="1" xfId="0"><alignment vertical="center" wrapText="1"/></xf></cellXfs><cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles></styleSheet>`;
const entries=[
['[Content_Types].xml',`<?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"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/></Types>`],
['_rels/.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>`],
['xl/workbook.xml',`<?xml version="1.0" encoding="UTF-8"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets><sheet name="Ramak Kala Formu" sheetId="1" r:id="rId1"/></sheets></workbook>`],
['xl/_rels/workbook.xml.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/worksheet" Target="worksheets/sheet1.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/></Relationships>`],
['xl/styles.xml',styles],['xl/worksheets/sheet1.xml',sheet]
];return zipStored(entries);
}
function download(blob,filename){const url=URL.createObjectURL(blob),a=document.createElement('a');a.href=url;a.download=filename;document.body.appendChild(a);a.click();a.remove();setTimeout(()=>URL.revokeObjectURL(url),2500);}
$('exportBtn').onclick=()=>{try{const name=($('eventDate').value||'Bildirim').replace(/[^a-zA-Z0-9_-]/g,'_');download(xlsxExport(),`ISG_Ramak_Kala_${name}.xlsx`);msg('Dikey Excel (.xlsx) dosyası oluşturuldu.','good');}catch(e){msg('Excel oluşturulamadı: '+e.message,'error');}};
function r16(d,n){return d[n]|(d[n+1]<<8);}function r32(d,n){return (d[n]|(d[n+1]<<8)|(d[n+2]<<16)|(d[n+3]<<24))>>>0;}
async function readZip(buffer){const d=new Uint8Array(buffer),map=new Map();let end=-1;for(let p=d.length-22;p>=Math.max(0,d.length-65557);p--)if(r32(d,p)===0x06054b50){end=p;break;}if(end<0)throw Error('Geçerli XLSX (ZIP) yapısı bulunamadı.');let pos=r32(d,end+16),count=r16(d,end+10);if(count>10000)throw Error('Dosya çok fazla içerik içeriyor.');for(let k=0;k<count;k++){
if(r32(d,pos)!==0x02014b50)throw Error('ZIP dizini hatalı');const method=r16(d,pos+10),size=r32(d,pos+20),fn=r16(d,pos+28),extra=r16(d,pos+30),comment=r16(d,pos+32),loc=r32(d,pos+42),path=dec.decode(d.subarray(pos+46,pos+46+fn));pos+=46+fn+extra+comment;
if(!path.startsWith('xl/')&&!path.startsWith('_rels/'))continue;
if(r32(d,loc)!==0x04034b50)throw Error('ZIP içeriği hatalı');let dataPos=loc+30+r16(d,loc+26)+r16(d,loc+28);if(size>20_000_000)throw Error('Dosya parçası çok büyük');const buf=d.subarray(dataPos,dataPos+size);
let data;if(method===0)data=buf;else if(method===8){if(!('DecompressionStream' in window))throw Error('Bu tarayıcı sıkıştırılmış Excel dosyalarını açmayı desteklemiyor. Güncel Chrome/Edge kullanın.');const stream=new Blob([buf]).stream().pipeThrough(new DecompressionStream('deflate-raw'));data=new Uint8Array(await new Response(stream).arrayBuffer());}else throw Error('Excel dosyası desteklenmeyen ZIP sıkıştırması kullanıyor.');map.set(path,dec.decode(data));
}return map;}
function parseXML(data){const xml=new DOMParser().parseFromString(data,'application/xml');if(xml.querySelector('parsererror'))throw Error('Excel XML içeriği bozuk');return xml;}
function tagElements(parent,name){return [...parent.getElementsByTagNameNS('*',name)];}
function readRows(xml,shared){let rows=[];for(const row of tagElements(xml,'row')){let cells=[];for(const c of tagElements(row,'c')){
const ref=c.getAttribute('r')||'A1',m=/^([A-Z]+)/i.exec(ref);if(!m)continue;let col=0;for(const ch of m[1].toUpperCase())col=col*26+ch.charCodeAt(0)-64;col--;
if(col>300)continue;let type=c.getAttribute('t'),value='';if(type==='inlineStr'){value=tagElements(c,'t').map(x=>x.textContent).join('');}else{value=tagElements(c,'v')[0]?.textContent??'';if(type==='s')value=shared[Number(value)]??'';if(type==='b')value=value==='1'?'Evet':'Hayır';}
cells[col]=value;
}rows.push(cells);if(rows.length>3000)throw Error('Çok fazla satır var (en çok 3000).');}return rows;}
function parseSheetRecords(rows){
let records=[];
const header=rows.findIndex(row=>norm(row[0])==='alan'&&norm(row[1])==='değer');
const labelHits=rows.filter(row=>fieldMap.has(norm(row[0]))).length;
if(header>=0||labelHits>=4){const rec={};for(const row of rows.slice(header>=0?header+1:0)){const id=fieldMap.get(norm(row[0]));if(id)rec[id]=String(row[1]??'');}return [rec];}
// Yatay şablon: ilk satırda alan adları / ID'ler, sonraki satırlarda kayıtlar.
let best={i:-1,n:0};for(let i=0;i<Math.min(10,rows.length);i++){let n=rows[i].filter(cell=>fieldMap.has(norm(cell))||specs.some(([id])=>id===cell)).length;if(n>best.n)best={i,n};}
if(best.n>=4){const hdr=rows[best.i];for(const row of rows.slice(best.i+1)){
const rec={};hdr.forEach((h,i)=>{let id=fieldMap.get(norm(h))||specs.find(([id])=>id===h)?.[0];if(id)rec[id]=String(row[i]??'');});
if(Object.values(rec).some(v=>String(v).trim()))records.push(rec);
}return records;}
throw Error('Alan/Değer başlıklı dikey şablon veya alan başlıklı yatay tablo bulunamadı.');
}
function serialToDate(x){let n=Number(x);if(!Number.isFinite(n)||n<1||n>200000)return x;const t=Math.round((n-25569)*86400000);return new Date(t).toISOString().slice(0,10);}
function normalizeRecord(rec){for(const key of ['reportDate','eventDate']){let v=rec[key]||'';if(/^\d{4,6}(\.\d+)?$/.test(v))v=serialToDate(v);if(/^\d{2}\.\d{2}\.\d{4}$/.test(v)){let [d,m,y]=v.split('.');v=`${y}-${m}-${d}`;}rec[key]=v;}return rec;}
async function xlsxImport(file){if(!/\.xlsx$/i.test(file.name))throw Error('Yalnızca .xlsx desteklenir.');if(file.size>8_000_000)throw Error('Dosya boyutu 8 MB sınırını aşıyor.');let map=await readZip(await file.arrayBuffer());let path='xl/worksheets/sheet1.xml';const wb=map.get('xl/workbook.xml'),rel=map.get('xl/_rels/workbook.xml.rels');
if(wb&&rel){const x=parseXML(wb),rx=parseXML(rel),sheet=tagElements(x,'sheet')[0],rid=sheet?.getAttribute('r:id')||sheet?.getAttributeNS('http://schemas.openxmlformats.org/officeDocument/2006/relationships','id');const relTag=tagElements(rx,'Relationship').find(e=>e.getAttribute('Id')===rid);if(relTag){const target=relTag.getAttribute('Target')||'';path=target.startsWith('/')?target.slice(1):'xl/'+target.replace(/^\.\//,'');}}
let txt=map.get(path)||map.get('xl/worksheets/sheet1.xml');if(!txt)throw Error('Excel çalışma sayfası okunamadı.');let shared=[];if(map.get('xl/sharedStrings.xml')){let sx=parseXML(map.get('xl/sharedStrings.xml'));shared=tagElements(sx,'si').map(si=>tagElements(si,'t').map(t=>t.textContent).join(''));}
const records=parseSheetRecords(readRows(parseXML(txt),shared)).map(normalizeRecord);if(!records.length)throw Error('Excel dosyasında okunabilir kayıt bulunamadı.');return records;
}
$('importBtn').onclick=()=>$('excelFile').click();
$('excelFile').addEventListener('change',async e=>{const file=e.target.files?.[0];if(!file)return;try{
const records=await xlsxImport(file);allRecords=records;const box=$('recordPicker'),select=$('recordSelect');select.replaceChildren();
records.forEach((r,i)=>{const option=document.createElement('option');option.value=String(i);option.textContent=`Bildirim ${i+1}${r.eventDate?' · '+r.eventDate:''}${r.place?' · '+r.place:''}`;select.appendChild(option);});
box.style.display=records.length>1?'flex':'none';assign(records[0]);msg(`${records.length} kayıt içeri alındı. ${records.length>1?'Kayıt listesinden görüntülenecek kaydı seçin.':''}`,'good');
}catch(err){msg('Excel alınamadı: '+err.message,'error');}finally{e.target.value='';}});
$('recordSelect').onchange=e=>{assign(allRecords[Number(e.target.value)]||{});msg('Seçilen kayıt görüntüleniyor.','good');};
// Beş hızlı tıklama ile yalnızca kurum şablonu başlığı değişir; olay bilgileri depolanmaz.
function fiveClicks(id,fn){let counter=0,last=0;const el=$(id);const handler=()=>{const now=Date.now();counter=(now-last<1050)?counter+1:1;last=now;if(counter>=5){counter=0;fn();}};el.addEventListener('click',handler);el.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();handler();}});}
for(const [id,key] of [['mainTitle','title'],['subTitle','subtitle'],['institution','organization']]){
try{const stored=localStorage.getItem('OLGUN_UI2_ISG_'+key);if(stored&&stored.length<=140)$(id).textContent=stored;}catch(_){/* LocalStorage kapalı olabilir. */}
fiveClicks(id,()=>{const v=prompt('Yeni başlık / kurum bilgisini girin:',$(id).textContent);if(v&&v.trim()&&v.trim().length<=140){$(id).textContent=v.trim();try{localStorage.setItem('OLGUN_UI2_ISG_'+key,v.trim());}catch(_){}}});
}
fiveClicks('logoBox',()=>$('logoFile').click());$('logoFile').onchange=e=>{const file=e.target.files?.[0];if(!file)return;if(!file.type.startsWith('image/')||file.size>5_000_000){msg('En fazla 5 MB görsel dosyası seçin.','error');return;}if(selectedLogoUrl)URL.revokeObjectURL(selectedLogoUrl);selectedLogoUrl=URL.createObjectURL(file);$('companyLogo').hidden=false;$('companyLogo').src=selectedLogoUrl;$('logoFallback').hidden=true;msg('Logo bu oturum için değiştirildi. Kalıcı kullanım için logo.jpg dosyasını HTML ile aynı klasöre koyun.','good');};
// Açılışta tüm bildirim alanları boştur; hazır kategori listesi değiştirilmez.
update();
})();
</script>
</body>
</html>