{"id":360,"date":"2026-06-21T17:00:14","date_gmt":"2026-06-21T17:00:14","guid":{"rendered":"http:\/\/janrauwerdink-fotografie.de\/?page_id=360"},"modified":"2026-07-20T08:05:18","modified_gmt":"2026-07-20T08:05:18","slug":"roll-tracker","status":"publish","type":"page","link":"https:\/\/janrauwerdink-fotografie.de\/en\/roll-tracker\/","title":{"rendered":"Roll Tracker"},"content":{"rendered":"\n<!--\n  Roll Tracker\n  \u00a9 2026 Jan Rauwerdink (janrauwerdink-fotografie.de). Alle Rechte vorbehalten.\n  Weiterverwendung, Vervielf\u00e4ltigung oder Weiterverbreitung dieses Codes,\n  ganz oder in Teilen, nur mit ausdr\u00fccklicher schriftlicher Genehmigung.\n-->\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Roll Tracker<\/title>\n<style>*,::after,::before{box-sizing:border-box;margin:0;padding:0}:root{--bg:#ffffff;--bg2:#f5f4f1;--bg3:#eeedea;--text:#1a1a18;--text2:#5f5e5a;--text3:#888780;--border:rgba(0,0,0,0.12);--border2:rgba(0,0,0,0.22);--success-bg:#eaf3de;--success-text:#3b6d11;--warning-bg:#faeeda;--warning-text:#854f0b;--danger-bg:#fcebeb;--danger-text:#a32d2d;--info-bg:#e6f1fb;--info-text:#185fa5;--accent:#185fa5;--radius:10px;--radius-sm:6px}@media (prefers-color-scheme:dark){:root{--bg:#1e1e1c;--bg2:#2a2a28;--bg3:#333330;--text:#f0ede8;--text2:#b4b2a9;--text3:#888780;--border:rgba(255,255,255,0.12);--border2:rgba(255,255,255,0.22);--success-bg:#173404;--success-text:#c0dd97;--warning-bg:#412402;--warning-text:#fac775;--danger-bg:#501313;--danger-text:#f09595;--info-bg:#042c53;--info-text:#b5d4f4;--accent:#85b7eb}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;background:var(--bg);color:var(--text);font-size:15px;line-height:1.6}.pc-wrap{max-width:760px;margin:0 auto;padding:2rem 1.25rem 3rem}.pc-header{margin-bottom:2rem;position:relative}.pc-info-btn{position:absolute;top:0;right:0;width:22px;height:22px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;background:var(--bg2);border:.5px solid var(--border2);color:var(--text2);font-size:12px;font-weight:700;font-style:italic;font-family:Georgia,'Times New Roman',serif;text-decoration:none;cursor:pointer;flex-shrink:0;transition:background .12s,color .12s}.pc-info-btn:hover{background:var(--bg3);color:var(--text)}.pc-header h1{font-size:22px;font-weight:600;color:var(--text);margin-bottom:4px;display:flex;align-items:center;gap:10px}.pc-header p{font-size:14px;color:var(--text2)}.pc-icon{width:36px;height:36px;background:var(--info-bg);border-radius:var(--radius-sm);display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}.pc-icon svg{width:20px;height:20px;stroke:var(--accent);fill:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}.pc-section-label{font-size:12px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.06em;margin-bottom:.75rem}.pc-divider{border:none;border-top:.5px solid var(--border);margin:1.25rem 0}input[type=number],input[type=text],select,textarea{width:100%;font-size:14px;color:var(--text);background:var(--bg2);border:.5px solid var(--border2);border-radius:var(--radius-sm);padding:.45rem .65rem;outline:0;appearance:none;-webkit-appearance:none;font-family:inherit;margin-bottom:5px}select{cursor:pointer}input:focus,select:focus,textarea:focus{border-color:var(--accent);box-shadow:0 0 0 2px rgba(24,95,165,.15)}textarea{resize:vertical;min-height:60px;line-height:1.5}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none}input[type=number]{-moz-appearance:textfield}.btn{display:inline-flex;align-items:center;gap:6px;padding:.45rem 1rem;border-radius:var(--radius-sm);border:.5px solid var(--border2);background:var(--bg);color:var(--text);font-size:13px;font-weight:500;font-family:inherit;cursor:pointer;transition:background .12s}.btn:hover{background:var(--bg2)}.btn:active{transform:scale(.98)}.btn.primary{background:var(--accent);color:#fff;border-color:transparent}.btn.primary:hover{opacity:.9}.btn.danger-btn{color:var(--danger-text);border-color:var(--danger-text);background:var(--danger-bg)}.btn svg{width:15px;height:15px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;flex-shrink:0}.unit-toggle{display:inline-flex;background:var(--bg2);border:.5px solid var(--border2);border-radius:99px;padding:3px;gap:2px;margin-bottom:1rem;flex-wrap:wrap}.unit-btn{padding:.3rem .85rem;border-radius:99px;border:none;background:0 0;font-size:13px;font-weight:500;color:var(--text2);cursor:pointer;transition:all .15s;font-family:inherit;white-space:nowrap}.unit-btn.active{background:var(--bg);color:var(--text);box-shadow:0 1px 3px rgba(0,0,0,.12)}.pc-result-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:8px;margin-bottom:1.25rem}.pc-metric{background:var(--bg2);border-radius:var(--radius-sm);padding:.8rem 1rem}.pc-metric-label{font-size:11px;color:var(--text2);margin-bottom:3px}.pc-metric-val{font-size:20px;font-weight:600;color:var(--text)}.roll-list{display:flex;flex-direction:column;gap:8px}.roll-item{background:var(--bg);border:.5px solid var(--border);border-radius:var(--radius);overflow:hidden}.roll-item-header{display:flex;align-items:center;gap:12px;padding:.75rem 1rem;cursor:pointer;user-select:none}.roll-item-header:hover{background:var(--bg2)}.roll-film-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.roll-name{font-size:14px;font-weight:500;color:var(--text);flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.roll-meta{font-size:12px;color:var(--text3);white-space:nowrap}.roll-status-badge{display:inline-flex;align-items:center;padding:2px 9px;border-radius:99px;font-size:11px;font-weight:600;white-space:nowrap;flex-shrink:0}.roll-progress-wrap{padding:0 1rem .55rem;display:flex;align-items:center;gap:8px}.roll-progress-bar{flex:1;height:4px;background:var(--bg3);border-radius:99px;overflow:hidden}.roll-progress-fill{height:100%;border-radius:99px;transition:width .3s}.roll-progress-label{font-size:11px;color:var(--text3);white-space:nowrap}.roll-detail{display:none;border-top:.5px solid var(--border);background:var(--bg2)}.roll-detail.open{display:block}.roll-detail-inner{padding:.75rem 1rem 1rem}.roll-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:8px;margin-bottom:.85rem}.roll-detail-field label{display:block;font-size:11px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.05em;margin-bottom:3px}.roll-detail-field .field-val{font-size:13px;color:var(--text2)}.roll-notes-block{font-size:13px;color:var(--text2);background:var(--bg);border:.5px solid var(--border);border-radius:var(--radius-sm);padding:.55rem .75rem;margin-bottom:.75rem;white-space:pre-wrap;min-height:36px}.roll-actions{display:flex;gap:6px;flex-wrap:wrap}.film-details-section{border-top:.5px solid var(--border)}.film-details-header{display:flex;align-items:center;justify-content:space-between;padding:.6rem 1rem;cursor:pointer}.film-details-header:hover{background:var(--bg3)}.film-details-title{font-size:12px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.06em;display:flex;align-items:center;gap:8px}.film-details-body{display:none;padding:0 1rem 1rem}.film-details-body.open{display:block}.frame-log-section{border-top:.5px solid var(--border)}.frame-log-header{display:flex;align-items:center;justify-content:space-between;padding:.6rem 1rem;cursor:pointer}.frame-log-header:hover{background:var(--bg3)}.frame-log-title{font-size:12px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.06em;display:flex;align-items:center;gap:8px}.frame-log-body{display:none;padding:0 1rem 1rem}.frame-log-body.open{display:block}.frame-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(52px,1fr));gap:5px;margin-bottom:.75rem}.frame-chip{background:var(--bg3);border:.5px solid var(--border);border-radius:var(--radius-sm);padding:5px 4px 4px;text-align:center;cursor:pointer;transition:border-color .1s;position:relative}.frame-chip:hover{border-color:var(--accent)}.frame-chip.has-data{background:var(--bg);border-color:var(--border2)}.frame-chip.active-frame{border:1.5px solid var(--accent);background:var(--info-bg)}.frame-chip-num{font-size:10px;font-weight:700;color:var(--text3);line-height:1;margin-bottom:3px}.frame-chip.has-data .frame-chip-num{color:var(--text2)}.frame-chip.active-frame .frame-chip-num{color:var(--info-text)}.frame-chip-vals{font-size:9px;color:var(--text3);line-height:1.35}.frame-chip.has-data .frame-chip-vals{color:var(--text2)}.quick-entry{background:var(--bg);border:.5px solid var(--border2);border-radius:var(--radius);padding:.85rem 1rem;margin-bottom:.75rem}.quick-entry-title{font-size:11px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.06em;margin-bottom:.65rem;display:flex;align-items:center;justify-content:space-between}.quick-row{margin-bottom:.6rem}.quick-row-label{font-size:11px;color:var(--text3);margin-bottom:4px;font-weight:500}.chip-row{display:flex;flex-wrap:wrap;gap:5px}.qchip{padding:5px 10px;border-radius:99px;font-size:12px;font-weight:500;border:.5px solid var(--border2);background:var(--bg2);color:var(--text2);cursor:pointer;transition:all .1s;white-space:nowrap;font-family:inherit;line-height:1}.qchip:hover{background:var(--bg3);color:var(--text)}.qchip.selected{background:var(--accent);color:#fff;border-color:transparent}.qchip:active{transform:scale(.95)}.quick-entry-summary{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:.65rem;padding-top:.65rem;border-top:.5px solid var(--border)}.summary-pill{font-size:12px;font-weight:600;padding:3px 10px;border-radius:99px;background:var(--bg2);color:var(--text);border:.5px solid var(--border2)}.summary-empty{font-size:12px;color:var(--text3);font-style:italic}.qnotes-row{margin-top:.5rem}.qnotes-row input{font-size:12px;padding:.35rem .6rem;margin-bottom:0}.frame-detail-bar{background:var(--bg2);border:.5px solid var(--border);border-radius:var(--radius-sm);padding:.5rem .75rem;font-size:12px;color:var(--text2);display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:.6rem}.frame-detail-bar strong{color:var(--text)}.modal-bg{display:none;position:fixed;inset:0;background:rgba(0,0,0,.45);z-index:999999;align-items:center;justify-content:center;padding:1rem}.modal-bg.open{display:flex}.modal{background:var(--bg);border-radius:var(--radius);border:.5px solid var(--border2);padding:1.5rem;width:100%;max-width:480px;max-height:90vh;overflow-y:auto}.modal h2{font-size:17px;font-weight:600;margin-bottom:1.25rem}.modal-field{margin-bottom:.85rem}.modal-field label{display:block;font-size:11px;font-weight:600;color:var(--text3);text-transform:uppercase;letter-spacing:.05em;margin-bottom:5px}.modal-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:1.25rem;flex-wrap:wrap}.stepper{display:flex;align-items:center;border:.5px solid var(--border2);border-radius:var(--radius-sm);overflow:hidden;background:var(--bg2)}.stepper-btn{width:36px;height:36px;display:flex;align-items:center;justify-content:center;border:none;background:0 0;cursor:pointer;font-size:18px;color:var(--text2);font-family:inherit;flex-shrink:0;transition:background .1s}.stepper-btn:hover{background:var(--bg3)}.stepper-val{flex:1;text-align:center;font-size:15px;font-weight:600;color:var(--text);padding:0 4px}.color-row{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:5px}.color-swatch{width:24px;height:24px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:border-color .1s;flex-shrink:0}.color-swatch.selected{border-color:var(--accent);box-shadow:0 0 0 1px var(--bg),0 0 0 3px var(--accent)}.empty-state{text-align:center;padding:3rem 1rem;color:var(--text3);font-size:14px}.empty-state svg{width:40px;height:40px;stroke:var(--text3);fill:none;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;margin:0 auto 1rem;display:block;opacity:.5}.pc-footer{margin-top:2.5rem;padding-top:1rem;border-top:.5px solid var(--border);font-size:12px;color:var(--text3);text-align:center}@media (max-width:520px){.pc-wrap{padding:1rem .85rem 2rem}.pc-header h1{font-size:18px}.roll-meta{display:none}.frame-grid{grid-template-columns:repeat(auto-fill,minmax(44px,1fr))}}<\/style>\n\n\n<div class=\"pc-wrap\">\n\n  <div class=\"pc-header\">\n    <a class=\"pc-info-btn\" id=\"manual-link\" href=\"#\" target=\"_blank\" rel=\"noopener\" title=\"Bedienungsanleitung \u00f6ffnen\">i<\/a>\n    <h1>\n      <span class=\"pc-icon\">\n        <svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"9\"><\/circle><circle cx=\"12\" cy=\"12\" r=\"3\"><\/circle><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"6\"><\/line><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"21\"><\/line><line x1=\"3\" y1=\"12\" x2=\"6\" y2=\"12\"><\/line><line x1=\"18\" y1=\"12\" x2=\"21\" y2=\"12\"><\/line><\/svg>\n      <\/span>\n      Roll Tracker\n    <\/h1>\n    <p>Behalte den \u00dcberblick \u00fcber alle Rollen \u2013 Film, Kamera, Belichtungsdaten pro Bild.<\/p>\n  <\/div>\n\n  <div class=\"pc-result-grid\">\n    <div class=\"pc-metric\"><p class=\"pc-metric-label\">Rollen gesamt<\/p><p class=\"pc-metric-val\" id=\"stat-total\">0<\/p><\/div>\n    <div class=\"pc-metric\"><p class=\"pc-metric-label\">Eingelegt<\/p><p class=\"pc-metric-val\" id=\"stat-loaded\">0<\/p><\/div>\n    <div class=\"pc-metric\"><p class=\"pc-metric-label\">Belichtet<\/p><p class=\"pc-metric-val\" id=\"stat-shot\">0<\/p><\/div>\n    <div class=\"pc-metric\"><p class=\"pc-metric-label\">Entwickelt<\/p><p class=\"pc-metric-val\" id=\"stat-dev\">0<\/p><\/div>\n  <\/div>\n\n  <div style=\"display:flex;align-items:center;gap:10px;margin-bottom:1rem;flex-wrap:wrap;\">\n    <span style=\"font-size:13px;color:var(--text2);\">Ansicht:<\/span>\n    <div class=\"unit-toggle\" id=\"filter-toggle\">\n      <button class=\"unit-btn active\" onclick=\"setFilter('all',this)\">Alle<\/button>\n      <button class=\"unit-btn\" onclick=\"setFilter('loaded',this)\">Eingelegt<\/button>\n      <button class=\"unit-btn\" onclick=\"setFilter('shot',this)\">Belichtet<\/button>\n      <button class=\"unit-btn\" onclick=\"setFilter('developed',this)\">Entwickelt<\/button>\n      <button class=\"unit-btn\" onclick=\"setFilter('archived',this)\">Archiv<\/button>\n    <\/div>\n    <button class=\"btn primary\" onclick=\"openAddModal()\" style=\"margin-left:auto;\">\n      <svg viewBox=\"0 0 24 24\"><line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"><\/line><line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"><\/line><\/svg>\n      Rolle hinzuf\u00fcgen\n    <\/button>\n  <\/div>\n\n  <hr class=\"pc-divider\">\n  <div id=\"roll-list-wrap\"><\/div>\n\n  <div class=\"pc-footer\">\n    <div style=\"display:flex;align-items:center;justify-content:center;gap:8px;flex-wrap:wrap;margin-bottom:.75rem;\">\n      <button class=\"btn\" onclick=\"exportJSON()\">\n        <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"><\/path><polyline points=\"7 10 12 15 17 10\"><\/polyline><line x1=\"12\" y1=\"15\" x2=\"12\" y2=\"3\"><\/line><\/svg>\n        Daten sichern (.json)\n      <\/button>\n      <button class=\"btn\" onclick=\"exportExcel()\">\n        <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"><\/rect><line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\"><\/line><line x1=\"9\" y1=\"9\" x2=\"9\" y2=\"21\"><\/line><\/svg>\n        Als Excel exportieren (.xlsx)\n      <\/button>\n      <button class=\"btn\" onclick=\"document.getElementById('import-input').click()\">\n        <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4\"><\/path><polyline points=\"17 8 12 3 7 8\"><\/polyline><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"15\"><\/line><\/svg>\n        Daten wiederherstellen\n      <\/button>\n      <input type=\"file\" id=\"import-input\" accept=\".json\" style=\"display:none\" onchange=\"importJSON(event)\">\n    <\/div>\n    Roll Tracker \u2014 Daten lokal im Browser \u00b7 Kein Account erforderlich<br>\u00a9 2026 Jan Rauwerdink \u00b7 Alle Rechte vorbehalten\n  <\/div>\n<\/div>\n\n<!-- ROLL MODAL -->\n<div class=\"modal-bg\" id=\"modal-bg\" onclick=\"closeModalOnBg(event)\">\n  <div class=\"modal\">\n    <h2 id=\"modal-title\">Neue Rolle<\/h2>\n    <div class=\"modal-field\"><label>Filmname \/ Bezeichnung<\/label><input type=\"text\" id=\"m-name\" placeholder=\"z.B. Kodak Tri-X 400 #12\"><\/div>\n    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:10px;\">\n      <div class=\"modal-field\"><label>Filmtyp<\/label>\n        <select id=\"m-type\"><option>SW-Negativ<\/option><option>Farb-Negativ<\/option><option>Farb-Dia (E6)<\/option><option>SW-Dia<\/option><option>Polaroid \/ Instax<\/option><option>Sonstiges<\/option><\/select>\n      <\/div>\n      <div class=\"modal-field\"><label>Format<\/label>\n        <select id=\"m-format\"><option>35mm<\/option><option>120 (6\u00d76)<\/option><option>120 (6\u00d77)<\/option><option>120 (6\u00d74.5)<\/option><option>120 (6\u00d79)<\/option><option>4\u00d75&#8243;<\/option><option>8\u00d710&#8243;<\/option><option>APS<\/option><option>110<\/option><option>Sonstiges<\/option><\/select>\n      <\/div>\n    <\/div>\n    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:10px;\">\n      <div class=\"modal-field\"><label>ISO \/ ASA<\/label>\n        <select id=\"m-iso\"><option>25<\/option><option>50<\/option><option>64<\/option><option>100<\/option><option>125<\/option><option>160<\/option><option>200<\/option><option value=\"400\" selected=\"\">400<\/option><option>800<\/option><option>1600<\/option><option>3200<\/option><\/select>\n      <\/div>\n      <div class=\"modal-field\"><label>Bilder gesamt<\/label>\n        <select id=\"m-frames\"><option>8<\/option><option>10<\/option><option>12<\/option><option>15<\/option><option>16<\/option><option>20<\/option><option>24<\/option><option value=\"36\" selected=\"\">36<\/option><option>72<\/option><option>Unbegrenzt<\/option><\/select>\n      <\/div>\n    <\/div>\n    <div class=\"modal-field\"><label>Kamera<\/label><input type=\"text\" id=\"m-camera\" placeholder=\"z.B. Leica M6, Hasselblad 500C \u2026\"><\/div>\n    <div style=\"display:grid;grid-template-columns:1fr 1fr;gap:10px;\">\n      <div class=\"modal-field\"><label>Status<\/label>\n        <select id=\"m-status\"><option value=\"loaded\">Eingelegt<\/option><option value=\"shot\">Belichtet<\/option><option value=\"developed\">Entwickelt<\/option><option value=\"archived\">Archiviert<\/option><\/select>\n      <\/div>\n      <div class=\"modal-field\"><label>Push \/ Pull<\/label>\n        <select id=\"m-push\"><option value=\"-2\">Pull \u22122<\/option><option value=\"-1\">Pull \u22121<\/option><option value=\"0\" selected=\"\">Normal<\/option><option value=\"1\">Push +1<\/option><option value=\"2\">Push +2<\/option><option value=\"3\">Push +3<\/option><\/select>\n      <\/div>\n    <\/div>\n\n    <div class=\"modal-field\"><label>Farbe<\/label><div class=\"color-row\" id=\"color-row\"><\/div><\/div>\n    <div class=\"modal-field\"><label>Notizen<\/label><textarea id=\"m-notes\" placeholder=\"Motivtyp, Lichtsituation \u2026\"><\/textarea><\/div>\n    <div class=\"modal-field\"><label>Eingelegt am<\/label><input type=\"text\" id=\"m-date\" placeholder=\"21.06.2026\"><\/div>\n    <div class=\"modal-actions\">\n      <button class=\"btn\" onclick=\"closeModal()\">Abbrechen<\/button>\n      <button class=\"btn primary\" onclick=\"saveRoll()\">Speichern<\/button>\n    <\/div>\n  <\/div>\n<\/div>\n\n<!-- FRAME MODAL -->\n<div class=\"modal-bg\" id=\"frame-modal-bg\" onclick=\"closeFrameModalOnBg(event)\">\n  <div class=\"modal\" style=\"max-width:420px;\">\n    <h2 id=\"fm-title\">Bild 1<\/h2>\n\n    <!-- Brennweite -->\n    <div class=\"quick-row\">\n      <div class=\"quick-row-label\">Brennweite (mm)<\/div>\n      <div class=\"chip-row\" id=\"fm-fl-chips\"><\/div>\n    <\/div>\n\n    <hr class=\"pc-divider\" style=\"margin:.75rem 0;\">\n\n    <!-- Blende -->\n    <div class=\"quick-row\">\n      <div class=\"quick-row-label\">Blende<\/div>\n      <div class=\"chip-row\" id=\"fm-ap-chips\"><\/div>\n    <\/div>\n\n    <hr class=\"pc-divider\" style=\"margin:.75rem 0;\">\n\n    <!-- Verschlusszeit -->\n    <div class=\"quick-row\">\n      <div class=\"quick-row-label\">Verschlusszeit<\/div>\n      <div class=\"chip-row\" id=\"fm-sh-chips\"><\/div>\n    <\/div>\n\n    <hr class=\"pc-divider\" style=\"margin:.75rem 0;\">\n\n    <!-- Notiz -->\n    <div class=\"quick-row\">\n      <div class=\"quick-row-label\">Notiz (optional)<\/div>\n      <input type=\"text\" id=\"fm-note\" placeholder=\"Motiv, Ort, Besonderheit \u2026\" style=\"font-size:13px;margin-bottom:0;\">\n    <\/div>\n\n    <!-- Summary -->\n    <div class=\"quick-entry-summary\" id=\"fm-summary\" style=\"margin-top:.75rem;padding-top:.75rem;border-top:0.5px solid var(--border);\">\n      <span class=\"summary-empty\">Noch keine Auswahl<\/span>\n    <\/div>\n\n    <div class=\"modal-actions\">\n      <button class=\"btn\" onclick=\"closeFrameModal()\">Abbrechen<\/button>\n      <button class=\"btn danger-btn\" id=\"fm-clear-btn\" onclick=\"clearFrameData()\" style=\"display:none;\">L\u00f6schen<\/button>\n      <button class=\"btn primary\" onclick=\"saveFrameData()\">Speichern<\/button>\n    <\/div>\n  <\/div>\n<\/div>\n\n<!-- SheetJS: ben\u00f6tigt f\u00fcr den Excel-Export (window.XLSX) -->\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\n\n<script>const MANUAL_URLS={de:\"https:\/\/janrauwerdink-fotografie.de\/bedienungsanleitung-roll-tracker\",en:\"https:\/\/janrauwerdink-fotografie.de\/en\/bedienungsanleitung-roll-tracker\"},currentLang=(document.documentElement.getAttribute(\"lang\")||\"de\").toLowerCase().substring(0,2),MANUAL_URL=MANUAL_URLS[currentLang]||MANUAL_URLS.de;document.getElementById(\"manual-link\").href=MANUAL_URL;const STRINGS={de:{emptyAllTitle:\"Noch keine Rollen erfasst.\",emptyAllHint:\"Klick auf <strong>Rolle hinzuf\u00fcgen<\/strong>, um zu starten.\",emptyFilteredTitle:\"Keine Rollen in dieser Kategorie.\",unnamedRoll:\"Unbenannte Rolle\",pushSuffix:e=>e>0?` \u00b7 Push +${e}`:` \u00b7 Pull ${e}`,progressLabel:(e,t,l)=>`${e}\/${t} \u00b7 ${l} frei`,noNotes:\"Keine Notizen.\",filmDetailsTitle:\"Filmdetails & Notizen\",fieldFilmType:\"Filmtyp\",fieldFormat:\"Format\",fieldIso:\"ISO \/ ASA\",fieldCamera:\"Kamera\",fieldPushPull:\"Push \/ Pull\",fieldLoadedOn:\"Eingelegt\",pushValue:e=>0===e?\"Normal\":e>0?\"+\"+e+\" Bl.\":e+\" Bl.\",btnAdvanceShot:\"Als belichtet markieren\",btnAdvanceDev:\"Als entwickelt markieren\",btnAdvanceArchive:\"Archivieren\",btnAdvanceReactivate:\"Reaktivieren\",btnEdit:\"Bearbeiten\",btnDelete:\"L\u00f6schen\",frameLogTitle:\"Bildprotokoll\",frameLogCount:(e,t)=>`${e} von ${t} erfasst`,frameLogHint:\"Auf ein Bild tippen zum Erfassen oder Bearbeiten.\",frameLabel:e=>`Bild ${e}`,modalTitleNew:\"Neue Rolle\",modalTitleEdit:\"Rolle bearbeiten\",fmNoSelection:\"Noch keine Auswahl\",manualLinkTitle:\"Bedienungsanleitung \u00f6ffnen\",confirmDeleteRoll:\"Rolle wirklich l\u00f6schen?\",alertNoRollsInFile:\"Keine Rollen in der Datei gefunden.\",confirmMergeImport:e=>`${e} Rollen gefunden.\\n\\nZusammenf\u00fchren mit vorhandenen Daten?\\n(Abbrechen = vorhandene Daten ersetzen)`,alertImportFailed:\"Datei konnte nicht gelesen werden. Bitte eine g\u00fcltige Roll-Tracker-JSON-Datei w\u00e4hlen.\",alertExcelLibMissing:\"Die Excel-Export-Bibliothek konnte nicht geladen werden. Bitte Internetverbindung pr\u00fcfen und die Seite neu laden.\",alertNoRollsYet:\"Es sind noch keine Rollen erfasst.\",xlsSheetRolls:\"Rollen\",xlsSheetFrames:\"Bildprotokoll\",xlsColName:\"Name\",xlsColFilmType:\"Filmtyp\",xlsColFormat:\"Format\",xlsColIso:\"ISO\/ASA\",xlsColTotalFrames:\"Bilder gesamt\",xlsColFramesShot:\"Belichtete Bilder\",xlsColFramesLeft:\"Frei\",xlsColCamera:\"Kamera\",xlsColStatus:\"Status\",xlsColPushPull:\"Push\/Pull\",xlsColLoadedOn:\"Eingelegt am\",xlsColNotes:\"Notizen\",xlsColRoll:\"Rolle\",xlsColFrameNo:\"Bild-Nr\",xlsColFocalLength:\"Brennweite (mm)\",xlsColAperture:\"Blende\",xlsColShutterSpeed:\"Verschlusszeit\",xlsColNote:\"Notiz\",statusLoaded:\"Eingelegt\",statusShot:\"Belichtet\",statusDeveloped:\"Entwickelt\",statusArchived:\"Archiv\"},en:{emptyAllTitle:\"No rolls recorded yet.\",emptyAllHint:\"Tap <strong>Add roll<\/strong> to get started.\",emptyFilteredTitle:\"No rolls in this category.\",unnamedRoll:\"Untitled roll\",pushSuffix:e=>e>0?` \u00b7 Push +${e}`:` \u00b7 Pull ${e}`,progressLabel:(e,t,l)=>`${e}\/${t} \u00b7 ${l} left`,noNotes:\"No notes.\",filmDetailsTitle:\"Film Details & Notes\",fieldFilmType:\"Film type\",fieldFormat:\"Format\",fieldIso:\"ISO \/ ASA\",fieldCamera:\"Camera\",fieldPushPull:\"Push \/ Pull\",fieldLoadedOn:\"Loaded\",pushValue:e=>0===e?\"Normal\":e>0?\"+\"+e+\" stop(s)\":e+\" stop(s)\",btnAdvanceShot:\"Mark as shot\",btnAdvanceDev:\"Mark as developed\",btnAdvanceArchive:\"Archive\",btnAdvanceReactivate:\"Reactivate\",btnEdit:\"Edit\",btnDelete:\"Delete\",frameLogTitle:\"Frame log\",frameLogCount:(e,t)=>`${e} of ${t} recorded`,frameLogHint:\"Tap a frame to record or edit it.\",frameLabel:e=>`Frame ${e}`,modalTitleNew:\"New roll\",modalTitleEdit:\"Edit roll\",fmNoSelection:\"No selection yet\",manualLinkTitle:\"Open user guide\",confirmDeleteRoll:\"Really delete this roll?\",alertNoRollsInFile:\"No rolls found in the file.\",confirmMergeImport:e=>`${e} rolls found.\\n\\nMerge with existing data?\\n(Cancel = replace existing data)`,alertImportFailed:\"The file could not be read. Please choose a valid Roll Tracker JSON file.\",alertExcelLibMissing:\"The Excel export library could not be loaded. Please check your internet connection and reload the page.\",alertNoRollsYet:\"No rolls have been recorded yet.\",xlsSheetRolls:\"Rolls\",xlsSheetFrames:\"Frame log\",xlsColName:\"Name\",xlsColFilmType:\"Film type\",xlsColFormat:\"Format\",xlsColIso:\"ISO\/ASA\",xlsColTotalFrames:\"Total frames\",xlsColFramesShot:\"Frames shot\",xlsColFramesLeft:\"Left\",xlsColCamera:\"Camera\",xlsColStatus:\"Status\",xlsColPushPull:\"Push\/Pull\",xlsColLoadedOn:\"Loaded on\",xlsColNotes:\"Notes\",xlsColRoll:\"Roll\",xlsColFrameNo:\"Frame no.\",xlsColFocalLength:\"Focal length (mm)\",xlsColAperture:\"Aperture\",xlsColShutterSpeed:\"Shutter speed\",xlsColNote:\"Note\",statusLoaded:\"Loaded\",statusShot:\"Shot\",statusDeveloped:\"Developed\",statusArchived:\"Archive\"}};function t(e,...t){const l=STRINGS[currentLang]||STRINGS.de,o=e in l?l[e]:STRINGS.de[e];return\"function\"==typeof o?o(...t):o}document.getElementById(\"manual-link\").title=t(\"manualLinkTitle\");const STORAGE_KEY=\"rolltracker_v2\",COLORS=[\"#185fa5\",\"#1d9e75\",\"#d85a30\",\"#d4537e\",\"#ba7517\",\"#534ab7\",\"#639922\",\"#5f5e5a\"],FL_VALUES=[\"21\",\"24\",\"28\",\"35\",\"40\",\"50\",\"55\",\"85\",\"90\",\"100\",\"105\",\"135\",\"180\",\"200\",\"300\",\"400\",\"500\"],AP_VALUES=[\"1.0\",\"1.2\",\"1.4\",\"1.8\",\"2.0\",\"2.5\",\"2.8\",\"3.5\",\"4\",\"5.6\",\"8\",\"11\",\"16\",\"22\",\"32\"],SH_VALUES=[\"B\",\"30s\",\"15s\",\"8s\",\"4s\",\"2s\",\"1s\",\"1\/2\",\"1\/4\",\"1\/8\",\"1\/15\",\"1\/30\",\"1\/60\",\"1\/125\",\"1\/250\",\"1\/500\",\"1\/1000\",\"1\/2000\",\"1\/4000\"];function buildStatusMeta(){return{loaded:{label:t(\"statusLoaded\"),bg:\"var(--info-bg)\",color:\"var(--info-text)\",dot:\"#185fa5\"},shot:{label:t(\"statusShot\"),bg:\"var(--warning-bg)\",color:\"var(--warning-text)\",dot:\"#ba7517\"},developed:{label:t(\"statusDeveloped\"),bg:\"var(--success-bg)\",color:\"var(--success-text)\",dot:\"#1d9e75\"},archived:{label:t(\"statusArchived\"),bg:\"var(--bg3)\",color:\"var(--text3)\",dot:\"#888780\"}}}const STATUS_META=buildStatusMeta(),TRP_SELECTORS=[\"#trp-floating-language-switcher-with-ARIA\",\".trp-floating-language-switcher\",\".trp-language-switcher-container\",\".trp-ls-shortcode-container\",\"[data-no-translation] .trp-language-switcher\"];let trpHiddenEls=[];function hideTRPSwitcher(){trpHiddenEls=[],TRP_SELECTORS.forEach(e=>{document.querySelectorAll(e).forEach(e=>{void 0===e.dataset.trpPrevDisplay&&(e.dataset.trpPrevDisplay=e.style.display||\"\"),e.style.display=\"none\",trpHiddenEls.push(e)})})}function showTRPSwitcher(){trpHiddenEls.forEach(e=>{e.style.display=e.dataset.trpPrevDisplay||\"\",delete e.dataset.trpPrevDisplay}),trpHiddenEls=[]}let rolls=[],editId=null,currentFilter=\"all\",selectedColor=COLORS[0],fmRollId=null,fmFrameIdx=null,fmFL=null,fmAP=null,fmSH=null;function load(){try{rolls=JSON.parse(localStorage.getItem(STORAGE_KEY))||[]}catch(e){rolls=[]}}function save(){localStorage.setItem(STORAGE_KEY,JSON.stringify(rolls))}function uid(){return Date.now().toString(36)+Math.random().toString(36).slice(2)}function render(){updateStats(),renderList()}function updateStats(){document.getElementById(\"stat-total\").textContent=rolls.length,document.getElementById(\"stat-loaded\").textContent=rolls.filter(e=>\"loaded\"===e.status).length,document.getElementById(\"stat-shot\").textContent=rolls.filter(e=>\"shot\"===e.status).length,document.getElementById(\"stat-dev\").textContent=rolls.filter(e=>\"developed\"===e.status).length}function setFilter(e,t){currentFilter=e,document.querySelectorAll(\"#filter-toggle .unit-btn\").forEach(e=>e.classList.remove(\"active\")),t.classList.add(\"active\"),renderList()}function renderList(){const e=document.getElementById(\"roll-list-wrap\");let l=\"all\"===currentFilter?rolls:rolls.filter(e=>e.status===currentFilter);if(!l.length){const l=\"all\"===currentFilter?`${t(\"emptyAllTitle\")}<br>${t(\"emptyAllHint\")}`:t(\"emptyFilteredTitle\");return void(e.innerHTML=`<div class=\"empty-state\"><svg viewBox=\"0 0 24 24\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><circle cx=\"12\" cy=\"12\" r=\"3\"\/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"6\"\/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"21\"\/><line x1=\"3\" y1=\"12\" x2=\"6\" y2=\"12\"\/><line x1=\"18\" y1=\"12\" x2=\"21\" y2=\"12\"\/><\/svg>${l}<\/div>`)}const o={loaded:0,shot:1,developed:2,archived:3};l=[...l].sort((e,t)=>o[e.status]-o[t.status]||(t.id>e.id?1:-1)),e.innerHTML='<div class=\"roll-list\">'+l.map(rollHTML).join(\"\")+\"<\/div>\"}function rollHTML(e){const l=STATUS_META[e.status]||STATUS_META.archived,o=\"Unbegrenzt\"===e.frames?null:parseInt(e.frames),n=(e.frameLog||[]).filter(e=>e&&(e.fl||e.ap||e.sh||e.note)).length,a=o?Math.min(100,Math.round(n\/o*100)):null,s=o?Math.max(0,o-n):\"\u221e\",r=0==e.push?\"\":t(\"pushSuffix\",e.push),i=[e.format,`ISO ${e.iso}`,e.camera].filter(Boolean).join(\" \u00b7 \")+r,d=((e.frameLog||[]).filter(e=>e&&(e.fl||e.ap||e.sh)).length,o?`<div class=\"roll-progress-wrap\"><div class=\"roll-progress-bar\"><div class=\"roll-progress-fill\" style=\"width:${a}%;background:${e.color||l.dot}\"><\/div><\/div><span class=\"roll-progress-label\">${t(\"progressLabel\",n,o,s)}<\/span><\/div>`:\"\"),m=e.notes?`<div class=\"roll-notes-block\">${escHtml(e.notes)}<\/div>`:`<div class=\"roll-notes-block\" style=\"color:var(--text3);font-style:italic\">${t(\"noNotes\")}<\/div>`,c=buildFrameLogHTML(e),u=`<div class=\"film-details-section\">\\n    <div class=\"film-details-header\" onclick=\"toggleFilmDetails('${e.id}')\">\\n      <span class=\"film-details-title\">\\n        <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" fill=\"none\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"\/><line x1=\"12\" y1=\"8\" x2=\"12\" y2=\"12\"\/><line x1=\"12\" y1=\"16\" x2=\"12.01\" y2=\"16\"\/><\/svg>\\n        ${t(\"filmDetailsTitle\")}\\n      <\/span>\\n      <span id=\"fd-arrow-${e.id}\" style=\"font-size:11px;color:var(--text3);\">\u25b8<\/span>\\n    <\/div>\\n    <div class=\"film-details-body\" id=\"film-details-${e.id}\">\\n      <div class=\"roll-detail-grid\">\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldFilmType\")}<\/label><span class=\"field-val\">${escHtml(e.type||\"\u2014\")}<\/span><\/div>\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldFormat\")}<\/label><span class=\"field-val\">${escHtml(e.format||\"\u2014\")}<\/span><\/div>\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldIso\")}<\/label><span class=\"field-val\">${escHtml(e.iso||\"\u2014\")}<\/span><\/div>\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldCamera\")}<\/label><span class=\"field-val\">${escHtml(e.camera||\"\u2014\")}<\/span><\/div>\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldPushPull\")}<\/label><span class=\"field-val\">${t(\"pushValue\",e.push)}<\/span><\/div>\\n        <div class=\"roll-detail-field\"><label>${t(\"fieldLoadedOn\")}<\/label><span class=\"field-val\">${escHtml(e.date||\"\u2014\")}<\/span><\/div>\\n      <\/div>\\n      ${m}\\n      <div class=\"roll-actions\">\\n        <button class=\"btn\" onclick=\"advanceStatus('${e.id}')\"><svg viewBox=\"0 0 24 24\"><polyline points=\"9 18 15 12 9 6\"\/><\/svg>${nextStatusLabel(e.status)}<\/button>\\n        <button class=\"btn\" onclick=\"openEditModal('${e.id}')\"><svg viewBox=\"0 0 24 24\"><path d=\"M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7\"\/><path d=\"M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z\"\/><\/svg>${t(\"btnEdit\")}<\/button>\\n        <button class=\"btn danger-btn\" onclick=\"deleteRoll('${e.id}')\"><svg viewBox=\"0 0 24 24\"><polyline points=\"3 6 5 6 21 6\"\/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"\/><path d=\"M10 11v6\"\/><path d=\"M14 11v6\"\/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"\/><\/svg>${t(\"btnDelete\")}<\/button>\\n      <\/div>\\n    <\/div>\\n  <\/div>`;return`<div class=\"roll-item\" id=\"roll-${e.id}\">\\n    <div class=\"roll-item-header\" onclick=\"toggleDetail('${e.id}')\">\\n      <span class=\"roll-film-dot\" style=\"background:${e.color||l.dot}\"><\/span>\\n      <span class=\"roll-name\">${escHtml(e.name||t(\"unnamedRoll\"))}<\/span>\\n      <span class=\"roll-meta\">${escHtml(i)}<\/span>\\n      <span class=\"roll-status-badge\" style=\"background:${l.bg};color:${l.color}\">${l.label}<\/span>\\n    <\/div>\\n    ${d}\\n    <div class=\"roll-detail\" id=\"detail-${e.id}\">\\n      ${c}\\n      ${u}\\n    <\/div>\\n  <\/div>`}function buildFrameLogHTML(e){const l=\"Unbegrenzt\"===e.frames?36:parseInt(e.frames)||36,o=e.frameLog||[],n=o.filter(e=>e&&(e.fl||e.ap||e.sh)).length;let a=\"\";for(let n=0;n<l;n++){const l=o[n]||{},s=l.fl||l.ap||l.sh,r=l.fl?l.fl+\"mm\":\"\",i=l.ap?\"f\/\"+l.ap:\"\",d=l.sh||\"\",m=s?`${t(\"frameLabel\",n+1)}: `+[r,i,d].filter(Boolean).join(\" \u00b7 \"):t(\"frameLabel\",n+1);a+=`<div class=\"frame-chip${s?\" has-data\":\"\"}\" onclick=\"openFrameModal('${e.id}',${n})\" title=\"${escHtml(m)}\">\\n      <div class=\"frame-chip-num\">${n+1}<\/div>\\n      <div class=\"frame-chip-vals\">${s?[r,i,d].filter(Boolean).join(\"<br>\"):\"\u00b7\"}<\/div>\\n    <\/div>`}return`<div class=\"frame-log-section\">\\n    <div class=\"frame-log-header\" onclick=\"toggleFrameLog('${e.id}')\">\\n      <span class=\"frame-log-title\">\\n        <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" fill=\"none\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"\/><line x1=\"9\" y1=\"3\" x2=\"9\" y2=\"21\"\/><line x1=\"15\" y1=\"3\" x2=\"15\" y2=\"21\"\/><\/svg>\\n        ${t(\"frameLogTitle\")}\\n        <span style=\"font-weight:400;text-transform:none;letter-spacing:0;font-size:11px;\">${t(\"frameLogCount\",n,l)}<\/span>\\n      <\/span>\\n      <span id=\"fl-arrow-${e.id}\" style=\"font-size:11px;color:var(--text3);\">\u25be<\/span>\\n    <\/div>\\n    <div class=\"frame-log-body open\" id=\"frame-log-${e.id}\">\\n      <div class=\"frame-grid\">${a}<\/div>\\n      <p style=\"font-size:11px;color:var(--text3);\">${t(\"frameLogHint\")}<\/p>\\n    <\/div>\\n  <\/div>`}function toggleFrameLog(e){const t=document.getElementById(\"frame-log-\"+e),l=document.getElementById(\"fl-arrow-\"+e),o=t.classList.toggle(\"open\");l&&(l.textContent=o?\"\u25be\":\"\u25b8\")}function toggleFilmDetails(e){const t=document.getElementById(\"film-details-\"+e),l=document.getElementById(\"fd-arrow-\"+e),o=t.classList.toggle(\"open\");l&&(l.textContent=o?\"\u25be\":\"\u25b8\")}function openFrameModal(e,l){fmRollId=e,fmFrameIdx=l;const o=rolls.find(t=>t.id===e);if(!o)return;const n=o.frameLog&&o.frameLog[l]||{};fmFL=n.fl||null,fmAP=n.ap||null,fmSH=n.sh||null,document.getElementById(\"fm-title\").textContent=t(\"frameLabel\",l+1),document.getElementById(\"fm-note\").value=n.note||\"\",buildChipRow(\"fm-fl-chips\",FL_VALUES,fmFL,e=>{fmFL=e,updateFmSummary()}),buildChipRow(\"fm-ap-chips\",AP_VALUES,fmAP,e=>{fmAP=e,updateFmSummary()}),buildChipRow(\"fm-sh-chips\",SH_VALUES,fmSH,e=>{fmSH=e,updateFmSummary()}),updateFmSummary();const a=n.fl||n.ap||n.sh;document.getElementById(\"fm-clear-btn\").style.display=a?\"\":\"none\",hideTRPSwitcher(),document.getElementById(\"frame-modal-bg\").classList.add(\"open\")}function buildChipRow(e,t,l,o){const n=document.getElementById(e);n.innerHTML=t.map(e=>`<button class=\"qchip${e===l?\" selected\":\"\"}\" data-val=\"${escHtml(e)}\">${escHtml(e)}<\/button>`).join(\"\"),n._onSelect=o,n.addEventListener(\"click\",function(e){const t=e.target.closest(\".qchip\");t&&(n.querySelectorAll(\".qchip\").forEach(e=>e.classList.remove(\"selected\")),t.classList.add(\"selected\"),n._onSelect&&n._onSelect(t.dataset.val))})}function updateFmSummary(){const e=document.getElementById(\"fm-summary\"),l=[];fmFL&&l.push(`<span class=\"summary-pill\">${fmFL} mm<\/span>`),fmAP&&l.push(`<span class=\"summary-pill\">f\/${fmAP}<\/span>`),fmSH&&l.push(`<span class=\"summary-pill\">${fmSH}<\/span>`),e.innerHTML=l.length?l.join(\"\"):`<span class=\"summary-empty\">${t(\"fmNoSelection\")}<\/span>`}function saveFrameData(){const e=rolls.find(e=>e.id===fmRollId);if(e){for(e.frameLog||(e.frameLog=[]);e.frameLog.length<=fmFrameIdx;)e.frameLog.push(null);e.frameLog[fmFrameIdx]={fl:fmFL,ap:fmAP,sh:fmSH,note:document.getElementById(\"fm-note\").value.trim()||null},save(),render(),setTimeout(()=>{const e=document.getElementById(\"detail-\"+fmRollId);e&&e.classList.add(\"open\");const t=document.getElementById(\"frame-log-\"+fmRollId),l=document.getElementById(\"fl-arrow-\"+fmRollId);t&&(t.classList.add(\"open\"),l&&(l.textContent=\"\u25be\"))},10),closeFrameModal()}}function clearFrameData(){const e=rolls.find(e=>e.id===fmRollId);e&&e.frameLog&&(e.frameLog[fmFrameIdx]=null,save(),render(),setTimeout(()=>{const e=document.getElementById(\"detail-\"+fmRollId);e&&e.classList.add(\"open\");const t=document.getElementById(\"frame-log-\"+fmRollId),l=document.getElementById(\"fl-arrow-\"+fmRollId);t&&(t.classList.add(\"open\"),l&&(l.textContent=\"\u25be\"))},10),closeFrameModal())}function closeFrameModal(){document.getElementById(\"frame-modal-bg\").classList.remove(\"open\"),showTRPSwitcher()}function closeFrameModalOnBg(e){e.target===document.getElementById(\"frame-modal-bg\")&&closeFrameModal()}function toggleDetail(e){const t=document.getElementById(\"detail-\"+e);t&&t.classList.toggle(\"open\")}function advanceStatus(e){const t=rolls.find(t=>t.id===e);if(!t)return;const l=[\"loaded\",\"shot\",\"developed\",\"archived\"];t.status=l[(l.indexOf(t.status)+1)%l.length],save(),render()}function deleteRoll(e){confirm(t(\"confirmDeleteRoll\"))&&(rolls=rolls.filter(t=>t.id!==e),save(),render())}function nextStatusLabel(e){return t(\"loaded\"===e?\"btnAdvanceShot\":\"shot\"===e?\"btnAdvanceDev\":\"developed\"===e?\"btnAdvanceArchive\":\"btnAdvanceReactivate\")}function buildColorRow(e){selectedColor=e||COLORS[0],document.getElementById(\"color-row\").innerHTML=COLORS.map(e=>`<span class=\"color-swatch${e===selectedColor?\" selected\":\"\"}\" style=\"background:${e}\" onclick=\"pickColor('${e}',this)\"><\/span>`).join(\"\")}function pickColor(e,t){selectedColor=e,document.querySelectorAll(\".color-swatch\").forEach(e=>e.classList.remove(\"selected\")),t.classList.add(\"selected\")}function openAddModal(){editId=null,document.getElementById(\"modal-title\").textContent=t(\"modalTitleNew\"),document.getElementById(\"m-name\").value=\"\",document.getElementById(\"m-type\").value=\"SW-Negativ\",document.getElementById(\"m-format\").value=\"35mm\",document.getElementById(\"m-iso\").value=\"400\",document.getElementById(\"m-frames\").value=\"36\",document.getElementById(\"m-camera\").value=\"\",document.getElementById(\"m-status\").value=\"loaded\",document.getElementById(\"m-push\").value=\"0\",document.getElementById(\"m-notes\").value=\"\",document.getElementById(\"m-date\").value=todayDE(),buildColorRow(null),hideTRPSwitcher(),document.getElementById(\"modal-bg\").classList.add(\"open\"),document.getElementById(\"m-name\").focus()}function openEditModal(e){const l=rolls.find(t=>t.id===e);l&&(editId=e,document.getElementById(\"modal-title\").textContent=t(\"modalTitleEdit\"),document.getElementById(\"m-name\").value=l.name||\"\",document.getElementById(\"m-type\").value=l.type||\"SW-Negativ\",document.getElementById(\"m-format\").value=l.format||\"35mm\",document.getElementById(\"m-iso\").value=l.iso||\"400\",document.getElementById(\"m-frames\").value=l.frames||\"36\",document.getElementById(\"m-camera\").value=l.camera||\"\",document.getElementById(\"m-status\").value=l.status||\"loaded\",document.getElementById(\"m-push\").value=l.push??0,document.getElementById(\"m-notes\").value=l.notes||\"\",document.getElementById(\"m-date\").value=l.date||\"\",buildColorRow(l.color),hideTRPSwitcher(),document.getElementById(\"modal-bg\").classList.add(\"open\"))}function closeModal(){document.getElementById(\"modal-bg\").classList.remove(\"open\"),showTRPSwitcher()}function closeModalOnBg(e){e.target===document.getElementById(\"modal-bg\")&&closeModal()}function saveRoll(){const e=document.getElementById(\"m-name\").value.trim();if(!e)return void document.getElementById(\"m-name\").focus();const t={name:e,type:document.getElementById(\"m-type\").value,format:document.getElementById(\"m-format\").value,iso:document.getElementById(\"m-iso\").value,frames:document.getElementById(\"m-frames\").value,camera:document.getElementById(\"m-camera\").value.trim(),status:document.getElementById(\"m-status\").value,push:parseInt(document.getElementById(\"m-push\").value)||0,notes:document.getElementById(\"m-notes\").value.trim(),date:document.getElementById(\"m-date\").value.trim(),color:selectedColor};if(editId){const e=rolls.findIndex(e=>e.id===editId);-1!==e&&(rolls[e]={...rolls[e],...t})}else rolls.unshift({id:uid(),...t});save(),render(),closeModal()}async function shareOrDownloadFile(e,t,l){try{const o=new File([e],t,{type:l});if(navigator.canShare&&navigator.canShare({files:[o]}))return void await navigator.share({files:[o],title:t})}catch(e){if(e&&\"AbortError\"===e.name)return}const o=URL.createObjectURL(e),n=document.createElement(\"a\");n.href=o,n.download=t,document.body.appendChild(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(o),1e3)}function exportJSON(){const e={version:2,exported:(new Date).toISOString(),rolls:rolls},t=new Blob([JSON.stringify(e,null,2)],{type:\"application\/json\"}),l=new Date;shareOrDownloadFile(t,\"roll-tracker-\"+[String(l.getDate()).padStart(2,\"0\"),String(l.getMonth()+1).padStart(2,\"0\"),l.getFullYear()].join(\"-\")+\".json\",\"application\/json\")}function exportExcel(){if(\"undefined\"==typeof XLSX)return void alert(t(\"alertExcelLibMissing\"));if(!rolls.length)return void alert(t(\"alertNoRollsYet\"));const e=rolls.map(e=>{const l=\"Unbegrenzt\"===e.frames?null:parseInt(e.frames),o=(e.frameLog||[]).filter(e=>e&&(e.fl||e.ap||e.sh||e.note)).length,n=(STATUS_META[e.status]||{}).label||e.status||\"\",a=t(\"pushValue\",e.push);return{[t(\"xlsColName\")]:e.name||\"\",[t(\"xlsColFilmType\")]:e.type||\"\",[t(\"xlsColFormat\")]:e.format||\"\",[t(\"xlsColIso\")]:e.iso||\"\",[t(\"xlsColTotalFrames\")]:e.frames||\"\",[t(\"xlsColFramesShot\")]:o,[t(\"xlsColFramesLeft\")]:null!=l?Math.max(0,l-o):\"\",[t(\"xlsColCamera\")]:e.camera||\"\",[t(\"xlsColStatus\")]:n,[t(\"xlsColPushPull\")]:a,[t(\"xlsColLoadedOn\")]:e.date||\"\",[t(\"xlsColNotes\")]:e.notes||\"\"}}),l=[];rolls.forEach(e=>{(e.frameLog||[]).forEach((o,n)=>{o&&(o.fl||o.ap||o.sh||o.note)&&l.push({[t(\"xlsColRoll\")]:e.name||\"\",[t(\"xlsColFrameNo\")]:n+1,[t(\"xlsColFocalLength\")]:o.fl||\"\",[t(\"xlsColAperture\")]:o.ap?\"f\/\"+o.ap:\"\",[t(\"xlsColShutterSpeed\")]:o.sh||\"\",[t(\"xlsColNote\")]:o.note||\"\"})})});const o=XLSX.utils.book_new(),n=XLSX.utils.json_to_sheet(e);if(n[\"!cols\"]=[{wch:26},{wch:14},{wch:12},{wch:8},{wch:12},{wch:14},{wch:8},{wch:20},{wch:12},{wch:10},{wch:12},{wch:30}],XLSX.utils.book_append_sheet(o,n,t(\"xlsSheetRolls\")),l.length){const e=XLSX.utils.json_to_sheet(l);e[\"!cols\"]=[{wch:26},{wch:8},{wch:14},{wch:8},{wch:14},{wch:30}],XLSX.utils.book_append_sheet(o,e,t(\"xlsSheetFrames\"))}const a=new Date,s=[String(a.getDate()).padStart(2,\"0\"),String(a.getMonth()+1).padStart(2,\"0\"),a.getFullYear()].join(\"-\"),r=XLSX.write(o,{bookType:\"xlsx\",type:\"array\"});shareOrDownloadFile(new Blob([r],{type:\"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\"}),\"roll-tracker-\"+s+\".xlsx\",\"application\/vnd.openxmlformats-officedocument.spreadsheetml.sheet\")}function importJSON(e){const l=e.target.files[0];if(!l)return;const o=new FileReader;o.onload=function(e){try{const l=JSON.parse(e.target.result),o=Array.isArray(l)?l:l.rolls||[];if(!o.length)return void alert(t(\"alertNoRollsInFile\"));if(confirm(t(\"confirmMergeImport\",o.length))){const e=new Set(rolls.map(e=>e.id));o.forEach(t=>{e.has(t.id)||rolls.push(t)})}else rolls=o;save(),render()}catch(e){alert(t(\"alertImportFailed\"))}},o.readAsText(l),e.target.value=\"\"}function escHtml(e){return String(e||\"\").replace(\/&\/g,\"&amp;\").replace(\/<\/g,\"&lt;\").replace(\/>\/g,\"&gt;\").replace(\/\"\/g,\"&quot;\")}function todayDE(){const e=new Date;return[String(e.getDate()).padStart(2,\"0\"),String(e.getMonth()+1).padStart(2,\"0\"),e.getFullYear()].join(\".\")}load(),render();<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Roll Tracker i Roll Tracker Behalte den \u00dcberblick \u00fcber alle Rollen \u2013 Film, Kamera, Belichtungsdaten pro &hellip; <a title=\"Roll Tracker\" class=\"hm-read-more\" href=\"https:\/\/janrauwerdink-fotografie.de\/en\/roll-tracker\/\"><span class=\"screen-reader-text\">Roll Tracker<\/span>Read more<\/a><\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_kadence_starter_templates_imported_post":false,"footnotes":""},"class_list":["post-360","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/pages\/360","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/comments?post=360"}],"version-history":[{"count":11,"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/pages\/360\/revisions"}],"predecessor-version":[{"id":762,"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/pages\/360\/revisions\/762"}],"wp:attachment":[{"href":"https:\/\/janrauwerdink-fotografie.de\/en\/wp-json\/wp\/v2\/media?parent=360"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}