diff --git a/dist/bookmarklet-payload.js b/dist/bookmarklet-payload.js
index 33cae43..663f4b9 100755
--- a/dist/bookmarklet-payload.js
+++ b/dist/bookmarklet-payload.js
@@ -3,6 +3,6 @@ if(window.__KANTINE_LOADED){alert('Kantine Wrapper already loaded!');return;}
var s=document.createElement('style');s.textContent=':root { /* Premium Slate/Gray-Blue Palette - Light Mode */ --bg-body: #f1f5f9; /* Slate 100 */ --bg-card: #ffffff; --text-primary: #334155; /* Slate 700 */ --text-secondary: #64748b; --accent-color: #0f172a; /* Slate 900 (High contrast) */ --border-color: #cbd5e1; /* Slate 300 */ --banner-bg: #e2e8f0; --banner-text: #1e293b; --success-color: #059669; --error-color: #dc2626; --card-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05); --header-bg: rgba(255, 255, 255, 0.9); --header-border: 1px solid rgba(203, 213, 225, 0.6); } [data-theme="dark"] { /* Premium Slate/Gray-Blue Palette - Dark Mode */ --bg-body: #1e293b; /* Deep Slate Gray (Requested) */ --bg-card: #334155; /* Slate 700 */ --text-primary: #f8fafc; /* Slate 50 */ --text-secondary: #cbd5e1; /* Slate 300 */ --accent-color: #60a5fa; /* Blue 400 */ --border-color: #475569; /* Slate 600 */ --banner-bg: #475569; --banner-text: #e2e8f0; --header-bg: rgba(30, 41, 59, 0.9); --header-border: 1px solid rgba(71, 85, 105, 0.6); --card-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.4); } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: \'Inter\', system-ui, -apple-system, sans-serif; background-color: var(--bg-body); color: var(--text-primary); transition: background-color 0.3s ease, color 0.3s ease; line-height: 1.5; -webkit-font-smoothing: antialiased; } /* Fix scrolling bug: Reset html/body styles from host page */ /* IMPORTANT: html must NOT have overflow set, or it creates a scroll container that breaks position: sticky */ html { height: auto !important; min-height: 100% !important; overflow: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } body { height: auto !important; min-height: 100% !important; overflow-x: clip !important; /* clip prevents horizontal overflow without breaking sticky */ overflow-y: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } /* Header */ .app-header { flex-shrink: 0; z-index: 100; backdrop-filter: blur(12px); background-color: var(--header-bg); border-bottom: var(--header-border); padding: 1rem 0; } .header-content { width: 100%; /* Full width */ padding: 0 2rem; /* Comfortable padding */ display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem; } .brand { display: flex; align-items: center; gap: 0.75rem; } .brand-text { display: flex; flex-direction: column; } .brand h1 { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.025em; margin-bottom: 0; } .subtitle { font-size: 0.85rem; color: var(--text-secondary); font-weight: 400; margin-left: 2px; } .logo-icon { font-size: 1.5rem; color: var(--accent-color); } /* Controls */ .controls { display: flex; align-items: center; gap: 1.5rem; justify-self: end; } /* Header Week Info (centered) */ .header-week-info { text-align: center; line-height: 1.3; } .header-center-wrapper { display: flex; flex-direction: row; align-items: center; gap: 1.5rem; justify-content: center; } .header-week-title { font-size: 1.1rem; font-weight: 600; color: var(--text-primary); } .header-week-subtitle { font-size: 0.85rem; color: var(--text-secondary); } /* Language Toggle (FR-100) */ .lang-toggle { display: inline-flex; gap: 0; border-radius: 6px; overflow: hidden; border: 1px solid var(--border-color); background: var(--bg-card); } .lang-btn { padding: 3px 10px; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.03em; background: transparent; color: var(--text-secondary); border: none; cursor: pointer; transition: all 0.2s; } .lang-btn:hover { color: var(--text-primary); background: rgba(100, 116, 139, 0.1); } .lang-btn.active { background: var(--accent-color); color: white; } .nav-group { display: flex; background-color: var(--bg-card); border: 1px solid var(--border-color); padding: 0.25rem; border-radius: 8px; } .nav-btn { background: none; border: none; padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500; color: var(--text-secondary); cursor: pointer; border-radius: 6px; transition: all 0.2s; display: flex; align-items: center; gap: 0.5rem; } .nav-btn:hover { color: var(--text-primary); background-color: rgba(100, 116, 139, 0.1); } .nav-btn.active { background-color: var(--accent-color); color: white; } /* Notification state for Next Week */ .nav-btn.new-week-available { animation: goldPulse 2s infinite; border-color: #f59e0b; color: var(--accent-color); } .nav-btn.new-week-available.active { color: white; } @keyframes goldPulse { 0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0); } 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); } } /* Badge for nav buttons (day count indicator) */ .nav-badge { background-color: var(--error-color); color: white; font-size: 0.75rem; font-weight: 600; padding: 0 6px; border-radius: 10px; min-width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; gap: 3px; line-height: 1; } .nav-badge .orderable { color: #fff; font-weight: 800; } .nav-badge .separator { opacity: 0.6; font-weight: 400; } .nav-badge .total { opacity: 0.8; font-weight: 400; } .nav-btn.active .nav-badge { background: rgba(255, 255, 255, 0.3); } /* Primary style for Login Button to match header */ #btn-login-open { background-color: var(--accent-color); color: white; padding: 0.5rem 1.25rem; border-radius: 8px; font-weight: 600; letter-spacing: 0.025em; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } #btn-login-open:hover { background-color: #334155; /* Slightly lighter than slate-900 */ transform: translateY(-1px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } /* User Badge Button (Login) */ .user-badge-btn { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 20px; font-size: 0.9rem; font-weight: 500; color: var(--text-primary); cursor: pointer; transition: all 0.2s; } .user-badge-btn:hover { background: rgba(100, 116, 139, 0.1); border-color: var(--accent-color); } .user-badge-btn .material-icons-round { font-size: 1.25rem; color: var(--accent-color); } .icon-btn { background: none; border: none; color: var(--text-primary); cursor: pointer; padding: 0.5rem; border-radius: 50%; transition: background-color 0.2s; display: flex; align-items: center; justify-content: center; } .icon-btn:hover { background-color: rgba(100, 116, 139, 0.1); } /* Refresh button animation */ #btn-refresh.refreshing .material-icons-round { animation: rotate 1s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* Progress Modal */ .progress-container { margin-bottom: 1.5rem; } .progress-bar { width: 100%; height: 8px; background-color: var(--border-color); border-radius: 4px; overflow: hidden; margin-bottom: 0.75rem; } .progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent-color) 0%, #60a5fa 100%); width: 0%; transition: width 0.3s ease; border-radius: 4px; } .progress-percent { text-align: center; font-size: 1.5rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; } .progress-message { text-align: center; color: var(--text-secondary); font-size: 0.9rem; font-weight: 500; } .weekly-cost { background-color: rgba(59, 130, 246, 0.1); /* Blue tint */ color: var(--accent-color); padding: 0.4rem 0.8rem; border-radius: 8px; font-weight: 600; font-size: 0.9rem; display: flex; align-items: center; gap: 0.5rem; border: 1px solid rgba(59, 130, 246, 0.2); } .weekly-cost .material-icons-round { font-size: 18px; } /* Container - flex column, full width so child scrollbar is at edge */ .container { flex: 1; width: 100%; overflow: hidden; padding: 0 0 0 0; /* Only top padding, no horizontal so child fills width */ display: flex; flex-direction: column; } /* Add horizontal padding to direct children of container to maintain layout */ .container>*:not(.menu-grid) { padding-left: 2rem; padding-right: 2rem; } /* Banner */ .banner { background-color: var(--banner-bg); color: var(--banner-text); padding: 0.75rem 1rem; border-radius: 8px; display: flex; align-items: center; gap: 0.5rem; margin-bottom: 2rem; font-size: 0.875rem; font-weight: 500; border: 1px solid var(--border-color); max-width: fit-content; } /* User Badge */ .user-badge { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); /* Changed from --surface */ border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 20px; font-size: 0.9rem; font-weight: 500; } .icon-btn-small { background: none; border: none; padding: 4px; cursor: pointer; color: var(--text-secondary); /* Changed from --text-muted */ display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s; } .icon-btn-small:hover { color: var(--error-color); /* Changed from --danger */ background: rgba(239, 68, 68, 0.1); } /* Modal */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; transition: all 0.3s; } .modal.hidden { opacity: 0; pointer-events: none; } .modal-content { background: var(--bg-card); width: 90%; max-width: 400px; border-radius: 16px; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); overflow: hidden; animation: modalSlide 0.3s ease-out; } /* History Modal specific */ .history-modal-content { max-width: 600px; max-height: 85vh; display: flex; flex-direction: column; } .history-modal-content .modal-body { overflow-y: auto; padding: 0; /* Padding is handled by inner elements */ } /* History Styles */ .history-year-group { margin-bottom: 16px; } .history-year-header { background: var(--bg-card); padding: 12px 20px; margin: 0; font-size: 1.2rem; font-weight: 700; color: var(--text-primary); border-bottom: 2px solid var(--border-color); position: sticky; top: 0; z-index: 12; } .history-month-group { border-bottom: 1px solid var(--border-color); } .history-month-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; margin: 0; font-size: 1.05rem; font-weight: 600; color: var(--text-primary); background: var(--bg-body); cursor: pointer; transition: background 0.2s; } .history-month-header:hover { background: var(--border-color); /* Slight hover effect */ } .history-month-summary { display: flex; align-items: center; gap: 12px; font-size: 0.95rem; color: var(--text-secondary); } .history-month-content { display: none; /* Collapsed by default */ background: var(--bg-card); } .history-month-group.open .history-month-content { display: block; /* Expanded when open class is present */ } .history-month-group.open .history-month-header .material-icons-round { transform: rotate(180deg); } .history-month-header .material-icons-round { transition: transform 0.3s; font-size: 20px; } .history-week-group { padding: 12px 20px; border-bottom: 1px dashed var(--border-color); } .history-week-group:last-child { border-bottom: none; } .history-week-header { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; font-weight: 600; color: var(--text-secondary); margin-bottom: 10px; } .history-week-summary { font-size: 0.85rem; font-weight: 500; background: rgba(100, 116, 139, 0.1); padding: 4px 10px; border-radius: 12px; } .history-items { display: flex; flex-direction: column; gap: 8px; } .history-item { display: grid; grid-template-columns: 50px 1fr auto; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-body); border-radius: 8px; border: 1px solid var(--border-color); } .history-item-date { font-size: 0.85rem; color: var(--text-secondary); font-weight: 500; } .history-item-details { display: flex; flex-direction: column; gap: 4px; } .history-item-name { font-size: 0.95rem; font-weight: 500; color: var(--text-primary); } .history-item-price { font-weight: 600; color: var(--text-primary); } .history-item-status { font-size: 0.8rem; font-weight: 600; color: var(--text-primary); text-transform: uppercase; letter-spacing: 0.5px; } .history-item-cancelled { opacity: 0.5; filter: grayscale(1); } .history-item-price-cancelled { text-decoration: line-through; color: var(--text-secondary); } @keyframes modalSlide { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px; border-bottom: 1px solid var(--border-color); } .modal-header h2 { margin: 0; font-size: 1.25rem; } .modal-body { padding: 20px; } #login-form { padding: 20px; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 6px; font-weight: 500; font-size: 0.9rem; } .form-group input { width: 100%; padding: 10px 12px; border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 8px; background: var(--bg-body); /* Changed from --bg */ color: var(--text-primary); /* Changed from --text */ font-family: inherit; transition: border-color 0.2s; } .form-group input:focus { outline: none; border-color: var(--accent-color); /* Changed from --primary */ } .help-text { display: block; margin-top: 4px; color: var(--text-secondary); /* Changed from --text-muted */ font-size: 0.75rem; } .error-msg { margin-bottom: 16px; padding: 10px; background: rgba(239, 68, 68, 0.1); color: var(--error-color); /* Changed from --danger */ border-radius: 8px; font-size: 0.85rem; text-align: center; } .modal-actions { margin-top: 24px; } .btn-primary.wide { width: 100%; justify-content: center; } .hidden { display: none !important; } /* Menu Grid Container */ .menu-grid { display: flex; flex-direction: column; flex: 1; overflow: hidden; gap: 1rem; } .week-section { margin-bottom: 2rem; } .week-header { margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); padding-bottom: 1rem; text-align: center; } .week-title { font-size: 1.75rem; font-weight: 700; color: var(--text-primary); } .week-range { color: var(--text-secondary); font-size: 0.9rem; margin-top: 0.25rem; } /* Full-viewport layout: header + scrollable content + footer */ #kantine-wrapper { display: flex; flex-direction: column; height: 100vh; height: 100dvh; /* Dynamic viewport height for mobile browsers */ overflow: hidden; } .days-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.75rem; flex: 1; overflow-y: auto; /* This is the scroll container at the window edge */ align-content: start; padding: 0 2rem 2rem 2rem; } /* Card */ .menu-card { background-color: var(--bg-card); border-radius: 12px; border: 1px solid var(--border-color); box-shadow: var(--card-shadow); overflow: clip; /* Clips scrolling content behind sticky header */ transition: box-shadow 0.2s ease; display: flex; flex-direction: column; } /* Past Day Styling - Target specific elements so ordered items can remain visible AND preserve sticky context */ /* We MUST apply filter/opacity to children, not the parent .menu-card, or else position: sticky breaks */ /* Header keeps fully opaque background to hide scrolling items, only grayscales */ .menu-card.past-day .card-header { filter: grayscale(0.8); transition: filter 0.3s; } /* Items become semi-transparent */ .menu-card.past-day .menu-item:not(.ordered) { opacity: 0.6; filter: grayscale(0.8); transition: opacity 0.3s, filter 0.3s; } .menu-card.past-day:hover .card-header { filter: grayscale(0.4); } .menu-card.past-day:hover .menu-item:not(.ordered) { opacity: 0.8; filter: grayscale(0.4); } /* Past ordered items get no special frame or shadow, but remain visually distinct by staying fully opaque (via the :not(.ordered) selector above) */ .menu-item.today-ordered { border: 2px solid #8b5cf6; box-shadow: 0 0 30px rgba(139, 92, 246, 0.6); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: pulse-glow-strong 3s infinite; } @keyframes pulse-glow-strong { 0% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } 50% { box-shadow: 0 0 40px rgba(139, 92, 246, 0.8); } 100% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } } .menu-card:hover { box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); } .card-header { padding: 1rem 1.25rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: baseline; background-color: var(--bg-card); /* Removed border-radius: 12px 12px 0 0; .menu-card\'s overflow: clip will round the corners initially. When sticky at the top, it will be square and perfectly hide scrolling content! */ /* Sticky within .container scroll area */ position: sticky; top: 0; z-index: 90; } .card-body { padding: 1.25rem; display: grid; grid-template-rows: auto; align-content: start; } .day-name { font-size: 1.125rem; font-weight: 600; } .day-date { font-size: 0.875rem; color: var(--text-secondary); } .empty-state { color: var(--text-secondary); font-style: italic; text-align: center; padding: 1rem; } /* Menu Items */ .menu-item { margin-bottom: 1.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); } .menu-item:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .item-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; gap: 1rem; } .item-name { font-weight: 600; color: var(--text-primary); font-size: 1rem; } .item-price { font-weight: 700; color: var(--accent-color); white-space: nowrap; } .item-desc { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.6; margin-bottom: 0.75rem; white-space: pre-wrap; } .badges { display: flex; gap: 0.5rem; margin-left: auto; } .item-status-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; } .badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; } .badge.available { background-color: rgba(16, 185, 129, 0.1); /* Emerald 500 / 10% */ color: var(--success-color); border: 1px solid rgba(16, 185, 129, 0.2); } .badge.sold-out { background-color: rgba(239, 68, 68, 0.1); /* Red 500 / 10% */ color: var(--error-color); border: 1px solid rgba(239, 68, 68, 0.2); } .badge.ordered { background-color: rgba(139, 92, 246, 0.1); /* Violet 500 / 10% */ color: #8b5cf6; border: 1px solid rgba(139, 92, 246, 0.2); gap: 4px; } .badge.ordered .material-icons-round { font-size: 1rem; } /* Loading */ .loading-state { text-align: center; padding: 4rem; color: var(--text-secondary); } .spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--accent-color); border-radius: 50%; margin: 0 auto 1rem; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Footer */ .app-footer { flex-shrink: 0; text-align: center; padding: 0.4rem 2rem; color: var(--text-secondary); font-size: 0.8rem; border-top: 1px solid var(--border-color); } /* === Order / Cancel Buttons (inline in status row) === */ .btn-order { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border: none; border-radius: 6px; background: var(--success-color); color: white; font-size: 0.75rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-order .material-icons-round { font-size: 16px; } .btn-order:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-order:disabled { opacity: 0.5; cursor: not-allowed; } .btn-order.loading { pointer-events: none; opacity: 0.6; } .btn-order-compact { padding: 2px 4px; gap: 0; } .btn-order-compact .material-icons-round { font-size: 16px; } .btn-cancel { display: inline-flex; align-items: center; justify-content: center; padding: 4px 6px; border: none; border-radius: 6px; background: var(--error-color); color: white; font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-cancel .material-icons-round { font-size: 16px; } .btn-cancel:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-cancel:disabled { opacity: 0.5; cursor: not-allowed; } /* Past days: hide action buttons */ .past-day .item-actions { display: none; } /* Order count badge (for multi-orders) */ .order-count-badge { display: inline-flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.3); color: white; font-size: 0.65rem; font-weight: 700; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; margin-left: 4px; line-height: 1; } /* === Toast Notifications === */ #toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 10000; display: flex; flex-direction: column; gap: 8px; pointer-events: none; } .toast { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 8px; font-size: 0.85rem; font-weight: 500; font-family: \'Inter\', sans-serif; color: white; backdrop-filter: blur(10px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); pointer-events: auto; transform: translateX(120%); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; } .toast.show { transform: translateX(0); opacity: 1; } .toast .material-icons-round { font-size: 18px; } .toast-success { background: rgba(5, 150, 105, 0.95); } .toast-error { background: rgba(220, 38, 38, 0.95); } .toast-info { background: rgba(59, 130, 246, 0.95); } /* === Mobile Responsiveness === */ @media (max-width: 600px) { .header-content { flex-direction: column; gap: 1rem; padding: 0.75rem; } .week-nav { width: 100%; justify-content: center; } .nav-pills { width: 100%; justify-content: space-between; } .nav-btn { flex: 1; justify-content: center; padding: 0.5rem; font-size: 0.85rem; } .days-grid { grid-template-columns: 1fr; /* Force single column */ } .main-content { padding: 1rem; } .week-title { font-size: 1.5rem; } /* Adjust toast position for mobile */ .toast-container { bottom: 1rem; right: 1rem; left: 1rem; /* Center on mobile */ width: auto; } .menu-card { margin-bottom: 1rem; } } /* === Flagging & Notification Styles === */ .btn-flag { display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 1px solid var(--text-secondary); color: var(--text-secondary); border-radius: 6px; padding: 4px; cursor: pointer; transition: all 0.2s; margin-right: 0.5rem; width: 28px; height: 28px; } .btn-flag:hover { background: rgba(234, 179, 8, 0.1); /* Yellow-500 / 10% */ color: #eab308; border-color: #eab308; } .btn-flag.active { background: rgba(234, 179, 8, 0.1); color: #eab308; border-color: #eab308; } .btn-flag .material-icons-round { font-size: 1.1rem; } /* Flagged & Sold Out (Yellow Glow) */ .menu-item.flagged-sold-out { border: 1px solid #eab308; box-shadow: 0 0 10px rgba(234, 179, 8, 0.2); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: yellow-pulse 3s infinite; } @keyframes yellow-pulse { 0% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } 50% { box-shadow: 0 0 16px rgba(234, 179, 8, 0.5); } 100% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } } /* Flagged & Available (Green Glow) */ .menu-item.flagged-available { border: 2px solid var(--success-color); box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: green-pulse 3s infinite; } @keyframes green-pulse { 0% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } 50% { box-shadow: 0 0 20px rgba(16, 185, 129, 0.6); } 100% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } } /* Day Header Badges */ .day-header-left { display: flex; align-items: center; gap: 0.75rem; } .menu-code-badge { font-size: 0.75rem; font-weight: 700; color: #8b5cf6; /* Violet 500 */ background-color: rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.3); padding: 2px 6px; border-radius: 6px; line-height: normal; display: inline-block; } /* Detailed Badge Colors */ .nav-badge.badge-violet { background-color: #8b5cf6; } .nav-badge.badge-green { background-color: var(--success-color); } .nav-badge.badge-red { background-color: var(--error-color); } .nav-badge.badge-blue { background-color: var(--accent-color); } /* Day Header Status Colors (User Request) */ .card-header.header-violet { background-color: var(--bg-card); background-image: linear-gradient(rgba(139, 92, 246, 0.15), rgba(139, 92, 246, 0.15)); border-bottom: 2px solid #8b5cf6; } .card-header.header-green { background-color: var(--bg-card); background-image: linear-gradient(rgba(16, 185, 129, 0.15), rgba(16, 185, 129, 0.15)); border-bottom: 2px solid var(--success-color); } .card-header.header-red { background-color: var(--bg-card); background-image: linear-gradient(rgba(239, 68, 68, 0.15), rgba(239, 68, 68, 0.15)); border-bottom: 2px solid var(--error-color); } .card-header.header-violet .day-name, .card-header.header-green .day-name, .card-header.header-red .day-name { font-weight: 700; color: var(--text-primary); /* Ensure text remains standard color */ } /* Update Icon */ .update-icon { display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; background-color: rgba(16, 185, 129, 0.2); /* Green tint */ color: var(--success-color); border-radius: 50%; width: 24px; height: 24px; cursor: pointer; font-size: 14px; transition: all 0.2s; text-decoration: none; animation: pulse 2s infinite; } .update-icon:hover { background-color: var(--success-color); color: white; transform: scale(1.1); } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } } /* Order Countdown */ #order-countdown { background: rgba(255, 255, 255, 0.1); padding: 0.25rem 0.75rem; border-radius: 99px; font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; border: 1px solid var(--border-color); } #order-countdown span { opacity: 0.7; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; } #order-countdown.urgent { background: rgba(239, 68, 68, 0.2); border-color: rgba(239, 68, 68, 0.5); color: #ef4444; animation: pulse-red 2s infinite; } @keyframes pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } } /* Smart Highlights (Blue Glow - matches today-ordered/flagged pattern) */ .menu-item.highlight-glow { border: 2px solid rgba(59, 130, 246, 0.7); box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: blue-pulse 3s infinite; } @keyframes blue-pulse { 0% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } 50% { box-shadow: 0 0 25px rgba(59, 130, 246, 0.6); } 100% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } } /* Nav Badge with Count */ .nav-badge.has-highlights { background-color: var(--bg-card); /* Neutral background */ color: var(--text-primary); border: 1px solid var(--border-color); padding: 2px 6px; } .nav-badge .highlight-count { color: #3b82f6; /* Blue 500 */ font-weight: 700; margin-left: 4px; } /* Tag Management Modal */ #tags-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; min-height: 50px; } /* Tag badges styled consistently with .badge (verfügbar/ausverkauft) */ .tag-badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; background-color: rgba(59, 130, 246, 0.1); color: #3b82f6; border: 1px solid rgba(59, 130, 246, 0.2); gap: 4px; } .tag-remove { cursor: pointer; opacity: 0.7; font-size: 1.1em; line-height: 1; transition: all 0.2s; } .tag-remove:hover { opacity: 1; color: #ef4444; } .input-group { display: flex; gap: 0.5rem; } .input-group input { flex: 1; padding: 0.75rem; background: var(--bg-body); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 8px; font-family: inherit; } /* Add tag button - styled like .btn-order with nav-btn.active color */ #btn-add-tag { display: inline-flex; align-items: center; gap: 4px; padding: 0.5rem 1rem; border: none; border-radius: 6px; background: var(--accent-color); color: white; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; white-space: nowrap; } #btn-add-tag:hover { filter: brightness(1.15); transform: translateY(-1px); } .matched-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; /* Space between tags and title */ margin-top: -5px; /* Pull closer to header */ } .tag-badge-small { display: inline-flex; align-items: center; font-size: 0.7rem; padding: 2px 8px; border-radius: 4px; background: rgba(59, 130, 246, 0.15); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } [data-theme="light"] .tag-badge-small { background: rgba(37, 99, 235, 0.1); color: #2563eb; border: 1px solid rgba(37, 99, 235, 0.2); } /* Installer Changelog */ .changelog-container ul { padding-left: 1.5rem; margin: 0.5rem 0; } .changelog-container li { margin-bottom: 0.4rem; line-height: 1.5; } .changelog-container h3 { margin-top: 1.5rem; margin-bottom: 0.5rem; font-size: 1.1em; color: var(--accent-color); } /* === Version Menu === */ .version-tag { cursor: pointer; transition: opacity 0.2s ease, text-decoration 0.2s ease; } .version-tag:hover { opacity: 1 !important; text-decoration: underline; } .version-list { list-style: none; padding: 0; margin: 0; } .version-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; border-radius: 8px; margin-bottom: 4px; transition: background 0.2s; } .version-item:hover { background: rgba(100, 116, 139, 0.08); } .version-item.current { background: rgba(2, 154, 168, 0.1); border: 1px solid rgba(2, 154, 168, 0.25); } [data-theme="dark"] .version-item:hover { background: rgba(255, 255, 255, 0.05); } [data-theme="dark"] .version-item.current { background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } .version-info { display: flex; align-items: center; gap: 10px; } .badge-current { font-size: 0.75rem; font-weight: 600; color: var(--success-color); padding: 2px 8px; border-radius: 4px; background: rgba(5, 150, 105, 0.1); } .badge-new { font-size: 0.75rem; font-weight: 600; color: #029aa8; padding: 2px 8px; border-radius: 4px; background: rgba(2, 154, 168, 0.1); } [data-theme="dark"] .badge-new { color: #60a5fa; background: rgba(96, 165, 250, 0.12); } .install-link { font-size: 0.8rem; font-weight: 500; padding: 4px 12px; border-radius: 6px; background: rgba(2, 154, 168, 0.1); color: #029aa8; text-decoration: none; border: 1px solid rgba(2, 154, 168, 0.25); transition: all 0.2s; white-space: nowrap; } .install-link:hover { background: rgba(2, 154, 168, 0.2); border-color: rgba(2, 154, 168, 0.4); } [data-theme="dark"] .install-link { color: #60a5fa; background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } [data-theme="dark"] .install-link:hover { background: rgba(96, 165, 250, 0.2); border-color: rgba(96, 165, 250, 0.4); } .dev-toggle { padding: 10px 14px; border-radius: 8px; background: rgba(100, 116, 139, 0.05); border: 1px solid var(--border-color); } .dev-toggle input[type="checkbox"] { accent-color: #029aa8; width: 16px; height: 16px; } [data-theme="dark"] .dev-toggle input[type="checkbox"] { accent-color: #60a5fa; } ';document.head.appendChild(s);
// Inject JS logic
var sc=document.createElement('script');
-sc.textContent="function showErrorModal(e,t,n,a){const s=\"error-modal\";let o=document.getElementById(s);o&&o.remove(),o=document.createElement(\"div\"),o.id=s,o.className=\"modal hidden\",o.innerHTML=`\\n
\\n \\n
\\n
${t}
\\n
\\n \\n ${n}\\n open_in_new \\n \\n
\\n
\\n
\\n `,document.body.appendChild(o),document.getElementById(\"btn-error-redirect\").addEventListener(\"click\",()=>{window.location.href=a}),requestAnimationFrame(()=>{o.classList.remove(\"hidden\")})}!function(){\"use strict\";if(window.__KANTINE_LOADED)return;window.__KANTINE_LOADED=!0;const e=\"https://api.bessa.app/v1\",t=\"c3418725e95a9f90e3645cbc846b4d67c7c66131\",n=591,a=\"TauNeutrino/kantine-overview\",s=`https://api.github.com/repos/${a}`,o=`https://htmlpreview.github.io/?https://github.com/${a}/blob`;let r=[],i=U(new Date),l=(new Date).getFullYear(),c=\"this-week\",d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\"),u=new Map,g=new Set(JSON.parse(localStorage.getItem(\"kantine_flags\")||\"[]\")),h=null,p=localStorage.getItem(\"kantine_lang\")||\"de\";function f(e){return{Authorization:`Token ${e||t}`,Accept:\"application/json\",\"Content-Type\":\"application/json\",\"X-Client-Version\":\"1.7.0_prod/2026-01-26\"}}function v(){if(!d)try{const e=localStorage.getItem(\"AkitaStores\");if(e){const t=JSON.parse(e);t.auth&&t.auth.token&&(console.log(\"Found existing Bessa session!\"),d=t.auth.token,localStorage.setItem(\"kantine_authToken\",d),t.auth.user&&(m=t.auth.user.id||\"unknown\",localStorage.setItem(\"kantine_currentUser\",m),t.auth.user.firstName&&localStorage.setItem(\"kantine_firstName\",t.auth.user.firstName),t.auth.user.lastName&&localStorage.setItem(\"kantine_lastName\",t.auth.user.lastName)))}}catch(e){console.warn(\"Failed to parse AkitaStores:\",e)}d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\");const e=localStorage.getItem(\"kantine_firstName\"),t=document.getElementById(\"btn-login-open\"),n=document.getElementById(\"user-info\"),a=document.getElementById(\"user-id-display\");d?(t.classList.add(\"hidden\"),n.classList.remove(\"hidden\"),a.textContent=e||(m?`User ${m}`:\"Angemeldet\"),y()):(t.classList.remove(\"hidden\"),n.classList.add(\"hidden\"),a.textContent=\"\"),z()}async function y(){if(d)try{const t=await fetch(`${e}/user/orders/?venue=591&ordering=-created&limit=50`,{headers:f(d)}),n=await t.json();if(t.ok){u=new Map;const e=n.results||[];for(const t of e){if(9===t.order_state)continue;const e=t.date.split(\"T\")[0];for(const n of t.items||[]){const a=`${e}_${n.article}`;u.has(a)||u.set(a,[]),u.get(a).push(t.id)}}console.log(`Fetched ${e.length} orders, mapped active ones.`),z(),$()}}catch(e){console.error(\"Error fetching orders:\",e)}}let b=null;function w(e){const t=document.getElementById(\"history-content\");if(!e||0===e.length)return void(t.innerHTML='Keine Bestellungen gefunden.
');const n={};e.forEach(e=>{const t=new Date(e.date),a=t.getFullYear(),s=t.getMonth(),o=`${a}-${s.toString().padStart(2,\"0\")}`,r=t.toLocaleString(\"de-AT\",{month:\"long\"}),i=U(t);n[a]||(n[a]={year:a,months:{}}),n[a].months[o]||(n[a].months[o]={name:r,year:a,monthIndex:s,count:0,total:0,weeks:{}}),n[a].months[o].weeks[i]||(n[a].months[o].weeks[i]={label:`KW ${i}`,items:[],count:0,total:0});(e.items||[]).forEach(t=>{const s=parseFloat(t.price||e.total||0);n[a].months[o].weeks[i].items.push({date:e.date,name:t.name||\"Men\u00fc\",price:s,state:e.order_state}),9!==e.order_state&&(n[a].months[o].weeks[i].count++,n[a].months[o].weeks[i].total+=s,n[a].months[o].count++,n[a].months[o].total+=s)})});const a=Object.keys(n).sort((e,t)=>t-e);let s=\"\";a.forEach(e=>{const t=n[e];s+=`\\n `;Object.keys(t.months).sort((e,t)=>t.localeCompare(e)).forEach(e=>{const n=t.months[e];s+=`
\\n \\n
`;Object.keys(n.weeks).sort((e,t)=>parseInt(t)-parseInt(e)).forEach(e=>{const t=n.weeks[e];s+=`
\\n `,t.items.forEach(e=>{const t=new Date(e.date).toLocaleDateString(\"de-AT\",{weekday:\"short\",day:\"2-digit\",month:\"2-digit\"});let n=\"\";n=9===e.state?'
Storniert ':8===e.state?'
Abgeschlossen ':'
\u00dcbertragen ',s+=`\\n
\\n
${t}
\\n
\\n
${J(e.name)} \\n
${n}
\\n
\\n
\u20ac${e.price.toFixed(2)}
\\n
`}),s+=\"
\"}),s+=\"
\"}),s+=\"
\"}),t.innerHTML=s;t.querySelectorAll(\".history-month-header\").forEach(e=>{e.addEventListener(\"click\",()=>{const t=e.parentElement;t.classList.contains(\"open\")?(t.classList.remove(\"open\"),e.setAttribute(\"aria-expanded\",\"false\")):(t.classList.add(\"open\"),e.setAttribute(\"aria-expanded\",\"true\"))})})}function k(){localStorage.setItem(\"kantine_flags\",JSON.stringify([...g]))}function A(){const e=document.getElementById(\"alarm-bell\"),t=document.getElementById(\"alarm-bell-icon\");if(!e||!t)return;if(0===g.size)return e.classList.add(\"hidden\"),e.style.display=\"none\",t.style.color=\"var(--text-secondary)\",void(t.style.textShadow=\"none\");e.classList.remove(\"hidden\"),e.style.display=\"inline-flex\";let n=!1;for(const e of r)if(e.days){for(const t of e.days)if(t.items){for(const e of t.items)if(e.available&&g.has(e.id)){n=!0;break}if(n)break}if(n)break}let a=localStorage.getItem(\"kantine_last_updated\"),s=\"gerade eben\";a||(a=(new Date).toISOString(),localStorage.setItem(\"kantine_last_updated\",a));const o=new Date(a),i=Date.now()-o.getTime(),l=Math.floor(i/6e4);s=l<1?\"gerade eben\":l<60?`vor ${l} Min.`:`vor ${Math.floor(l/60)} Std.`,e.title=`Zuletzt gepr\u00fcft: ${s}`,n?(t.style.color=\"#10b981\",t.style.textShadow=\"0 0 10px rgba(16, 185, 129, 0.4)\"):(t.style.color=\"#f59e0b\",t.style.textShadow=\"0 0 10px rgba(245, 158, 11, 0.4)\")}function E(n,a,s,o){const i=`${n}_${a}`;let l=!1;g.has(i)?(g.delete(i),F(`Flag entfernt f\u00fcr ${s}`,\"success\")):(g.add(i),l=!0,F(`Benachrichtigung aktiviert f\u00fcr ${s}`,\"success\"),\"default\"===Notification.permission&&Notification.requestPermission()),k(),A(),z(),l&&async function(){if(0===g.size)return;const n=d||t,a=new Set;for(const e of g){const[t]=e.split(\"_\");a.add(t)}let s=!1;for(const t of a)try{const a=await fetch(`${e}/venues/591/menu/7/${t}/`,{headers:f(n)});if(!a.ok)continue;const o=(await a.json()).results||[];let i=[];for(const e of o)e.items&&Array.isArray(e.items)&&(i=i.concat(e.items));for(let e of r){if(!e.days)continue;let n=e.days.find(e=>e.date===t);n&&(n.items=i.map(e=>{const n=!1===e.amount_tracking,a=parseInt(e.available_amount)>0;return{id:`${t}_${e.id}`,articleId:e.id,name:e.name||\"Unknown\",description:e.description||\"\",price:parseFloat(e.price)||0,available:n||a,availableAmount:parseInt(e.available_amount)||0,amountTracking:!1!==e.amount_tracking}}),s=!0)}}catch(e){console.error(\"Error refreshing flag date\",t,e)}s&&(O(),q((new Date).toISOString()),A(),z())}()}function I(){h||d&&(h=setInterval(()=>async function(){if(0===g.size||!d)return;console.log(`Polling ${g.size} flagged items...`);for(const t of g){const[n,a]=t.split(\"_\"),s=parseInt(a);try{const t=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(d)});if(!t.ok)continue;const a=(await t.json()).results||[];let o=null;for(const e of a)if(e.items&&(o=e.items.find(e=>e.id===s||e.article===s),o))break;if(o){if(!1===o.amount_tracking||parseInt(o.available_amount)>0){const e=o.name||\"Unbekannt\";F(`${e} ist jetzt verf\u00fcgbar!`,\"success\"),\"granted\"===Notification.permission&&new Notification(\"Kantine Wrapper\",{body:`${e} ist jetzt verf\u00fcgbar!`,icon:\"\ud83c\udf7d\ufe0f\"}),M()}}}catch(e){console.error(`Poll error for ${t}:`,e),await new Promise(e=>setTimeout(e,200))}}}(),3e5),console.log(\"Polling started (every 5 min)\"))}let L=JSON.parse(localStorage.getItem(\"kantine_highlightTags\")||\"[]\");function S(){localStorage.setItem(\"kantine_highlightTags\",JSON.stringify(L)),z(),$()}function B(){const e=document.getElementById(\"tags-list\");e.innerHTML=\"\",L.forEach(t=>{const n=document.createElement(\"span\");n.className=\"tag-badge\",n.innerHTML=`${t} × `,e.appendChild(n)}),e.querySelectorAll(\".tag-remove\").forEach(e=>{e.addEventListener(\"click\",e=>{var t;t=e.target.dataset.tag,L=L.filter(e=>e!==t),S(),B()})})}function x(e){return e?(e=e.toLowerCase(),L.filter(t=>e.includes(t))):[]}const C=\"kantine_menuCache\",D=\"kantine_menuCacheTs\";function O(){try{localStorage.setItem(C,JSON.stringify(r)),localStorage.setItem(D,(new Date).toISOString())}catch(e){console.warn(\"Failed to cache menu data:\",e)}}async function M(){const n=document.getElementById(\"loading\"),a=document.getElementById(\"progress-modal\"),s=document.getElementById(\"progress-fill\"),o=document.getElementById(\"progress-percent\"),c=document.getElementById(\"progress-message\");n.classList.remove(\"hidden\");const m=d||t;try{a.classList.remove(\"hidden\"),c.textContent=\"Hole verf\u00fcgbare Daten...\",s.style.width=\"0%\",o.textContent=\"0%\";const t=await fetch(`${e}/venues/591/menu/dates/`,{headers:f(m)});if(!t.ok)throw new Error(`Failed to fetch dates: ${t.status}`);let n=(await t.json()).results||[];const d=new Date;d.setDate(d.getDate()-7);const u=d.toISOString().split(\"T\")[0];n=n.filter(e=>e.date>=u).sort((e,t)=>e.date.localeCompare(t.date)).slice(0,30);const g=n.length;c.textContent=`${g} Tage gefunden. Lade Details...`;const h=[];let p=0;for(const t of n){const n=t.date,a=Math.round((p+1)/g*100);s.style.width=`${a}%`,o.textContent=`${a}%`,c.textContent=`Lade Men\u00fc f\u00fcr ${n}...`;try{const a=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(m)});if(a.ok){const e=await a.json();0===p&&console.log(\"[Kantine Debug] Raw API response for\",n,\":\",JSON.stringify(e).substring(0,2e3));const s=e.results||[];let o=[];for(const e of s)e.items&&Array.isArray(e.items)&&(o=o.concat(e.items));o.length>0&&(0===p&&(console.log(\"[Kantine Debug] First item keys:\",Object.keys(o[0])),console.log(\"[Kantine Debug] First item:\",JSON.stringify(o[0]).substring(0,500))),h.push({date:n,menu_items:o,orders:t.orders||[]}))}}catch(e){console.error(`Failed to fetch details for ${n}:`,e)}p++,await new Promise(e=>setTimeout(e,100))}const y=new Map;r&&r.length>0&&r.forEach(e=>{const t=`${e.year}-${e.weekNumber}`;try{y.set(t,{year:e.year,weekNumber:e.weekNumber,days:e.days?e.days.map(e=>({...e,items:e.items?[...e.items]:[]})):[]})}catch(e){console.warn(\"Error hydrating week:\",e)}});for(const e of h){const t=new Date(e.date),n=U(t),a=G(t),s=`${a}-${n}`;y.has(s)||y.set(s,{year:a,weekNumber:n,days:[]});const o=y.get(s),r=t.toLocaleDateString(\"en-US\",{weekday:\"long\"}),i=new Date(e.date);i.setHours(10,0,0,0);const l={date:e.date,weekday:r,orderCutoff:i.toISOString(),items:e.menu_items.map(t=>{const n=!1===t.amount_tracking,a=parseInt(t.available_amount)>0;return{id:`${e.date}_${t.id}`,articleId:t.id,name:t.name||\"Unknown\",description:t.description||\"\",price:parseFloat(t.price)||0,available:n||a,availableAmount:parseInt(t.available_amount)||0,amountTracking:!1!==t.amount_tracking}})},c=o.days.findIndex(t=>t.date===e.date);c>=0?o.days[c]=l:o.days.push(l)}r=Array.from(y.values()).sort((e,t)=>e.year!==t.year?e.year-t.year:e.weekNumber-t.weekNumber),r.forEach(e=>{e.days&&e.days.sort((e,t)=>e.date.localeCompare(t.date))}),O(),q((new Date).toISOString()),i=U(new Date),l=(new Date).getFullYear(),v(),z(),$(),A(),c.textContent=\"Fertig!\",setTimeout(()=>a.classList.add(\"hidden\"),500)}catch(e){console.error(\"Error fetching menu:\",e),a.classList.add(\"hidden\"),showErrorModal(\"Keine Verbindung\",`Die Men\u00fcdaten konnten nicht geladen werden. M\u00f6glicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.${e.message} `,\"Zur Original-Seite\",\"https://web.bessa.app/knapp-kantine\")}finally{n.classList.add(\"hidden\")}}let N=null,T=null;function q(e){const t=document.getElementById(\"last-updated-subtitle\");if(e){N=e;try{const n=new Date(e),a=n.toLocaleTimeString(\"de-DE\",{hour:\"2-digit\",minute:\"2-digit\"}),s=n.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),o=function(e){const t=Date.now()-e.getTime(),n=Math.floor(t/6e4);if(n<1)return\"gerade eben\";if(1===n)return\"vor 1 min.\";if(n<60)return`vor ${n} min.`;const a=Math.floor(n/60);return 1===a?\"vor 1 Std.\":`vor ${a} Std.`}(n);t.textContent=`Aktualisiert: ${s} ${a} (${o})`}catch(e){t.textContent=\"\"}T||(T=setInterval(()=>{N&&q(N)},6e4))}}function F(e,t=\"info\"){let n=document.getElementById(\"toast-container\");n||(n=document.createElement(\"div\"),n.id=\"toast-container\",document.body.appendChild(n));const a=document.createElement(\"div\");a.className=`toast toast-${t}`;const s=\"success\"===t?\"check_circle\":\"error\"===t?\"error\":\"info\";a.innerHTML=`${s} ${e} `,n.appendChild(a),requestAnimationFrame(()=>a.classList.add(\"show\")),setTimeout(()=>{a.classList.remove(\"show\"),setTimeout(()=>a.remove(),300)},3e3)}function $(){const e=document.getElementById(\"btn-next-week\");let t=i+1,n=l;t>52&&(t=1,n++);const a=r.find(e=>e.weekNumber===t&&e.year===n);let s=0,o=0,c=0,d=0;a&&a.days&&a.days.forEach(e=>{if(e.items&&e.items.length>0){s++;const t=e.items.some(e=>e.available);t&&o++;let n=!1;e.items.forEach(t=>{const a=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${a}`;u.has(s)&&u.get(s).length>0&&(n=!0)}),n&&c++,t&&!n&&d++}});let m=e.querySelector(\".nav-badge\");if(s>0){m||(m=document.createElement(\"span\"),m.className=\"nav-badge\",e.appendChild(m)),m.title=`${c} bestellt / ${o} bestellbar / ${s} gesamt`,m.innerHTML=`${c} / ${o} / ${s} `,m.classList.remove(\"badge-violet\",\"badge-green\",\"badge-red\",\"badge-blue\"),c>0&&0===d?m.classList.add(\"badge-violet\"):d>0?m.classList.add(\"badge-green\"):0===o?m.classList.add(\"badge-red\"):m.classList.add(\"badge-blue\");let r=0;if(a&&a.days&&a.days.forEach(e=>{e.items.forEach(e=>{const t=x(e.name),n=x(e.description);(t.length>0||n.length>0)&&r++})}),r>0&&(m.innerHTML+=`(${r}) `,m.title+=` \u2022 ${r} Highlights gefunden`,m.classList.add(\"has-highlights\")),0===c){e.classList.add(\"new-week-available\");const a=`kantine_notified_nextweek_${n}_${t}`;localStorage.getItem(a)||(localStorage.setItem(a,\"true\"),F(\"Neue Men\u00fcdaten f\u00fcr n\u00e4chste Woche verf\u00fcgbar!\",\"info\"))}else e.classList.remove(\"new-week-available\")}else m&&m.remove()}function z(){const t=document.getElementById(\"menu-container\");if(!t)return;t.innerHTML=\"\";let a=i,s=l;\"next-week\"===c&&(a++,a>52&&(a=1,s++));const o=r.flatMap(e=>e.days||[]).filter(e=>{const t=new Date(e.date);return U(t)===a&&G(t)===s});if(0===o.length)return t.innerHTML=`\\n \\n
Keine Men\u00fcdaten f\u00fcr KW ${a} (${s}) verf\u00fcgbar.
\\n
Versuchen Sie eine andere Woche oder schauen Sie sp\u00e4ter vorbei. \\n
`,void document.getElementById(\"weekly-cost-display\").classList.add(\"hidden\");!function(e){let t=0;e&&e.length>0&&e.forEach(e=>{e.items&&e.items.forEach(n=>{const a=n.articleId||parseInt(n.id.split(\"_\")[1]),s=`${e.date}_${a}`,o=u.get(s)||[];o.length>0&&(t+=n.price*o.length)})});const n=document.getElementById(\"weekly-cost-display\");t>0?(n.innerHTML=`shopping_bag Gesamt: ${t.toFixed(2).replace(\".\",\",\")} \u20ac `,n.classList.remove(\"hidden\")):n.classList.add(\"hidden\")}(o);const m=document.getElementById(\"header-week-info\"),h=\"this-week\"===c?\"Diese Woche\":\"N\u00e4chste Woche\";m.innerHTML=`\\n \\n `;const v=document.createElement(\"div\");v.className=\"days-grid\",o.sort((e,t)=>e.date.localeCompare(t.date));o.filter(e=>{const t=new Date(e.date).getDay();return 0!==t&&6!==t}).forEach(t=>{const a=function(t){if(!t.items||0===t.items.length)return null;const a=document.createElement(\"div\");a.className=\"menu-card\";const s=new Date,o=new Date(t.date);let r=!1;if(t.orderCutoff)r=s>=new Date(t.orderCutoff);else{const e=new Date;e.setHours(0,0,0,0);const n=new Date(t.date);n.setHours(0,0,0,0),r=n{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`,s=(u.get(a)||[]).length;if(s>0){const t=e.name.match(/([M][1-9][Ff]?)/);if(t){let e=t[1];s>1&&(e+=\"+\"),i.push(e)}}});const l=document.createElement(\"div\");l.className=\"card-header\";const c=o.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),m=i.map(e=>``).join(\"\");let h=\"\";const v=t.items&&t.items.some(e=>{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`;return u.has(a)&&u.get(a).length>0}),w=t.items&&t.items.some(e=>e.available);h=v?\"header-violet\":w&&!r?\"header-green\":\"header-red\";h&&l.classList.add(h);l.innerHTML=`\\n \\n ${c} `,a.appendChild(l);var k;const A=document.createElement(\"div\");A.className=\"card-body\";const I=(new Date).toISOString().split(\"T\")[0],L=t.date===I,S=[...t.items].sort((e,n)=>{if(L){const a=e.articleId||parseInt(e.id.split(\"_\")[1]),s=n.articleId||parseInt(n.id.split(\"_\")[1]),o=u.has(`${t.date}_${a}`),r=u.has(`${t.date}_${s}`);if(o&&!r)return-1;if(!o&&r)return 1}return e.name.localeCompare(n.name)});return S.forEach(a=>{const o=document.createElement(\"div\");o.className=\"menu-item\";const i=a.articleId||parseInt(a.id.split(\"_\")[1]),l=`${t.date}_${i}`,c=(u.get(l)||[]).length;let m=\"\";m=a.available?a.amountTracking?`Verf\u00fcgbar (${a.availableAmount}) `:'Verf\u00fcgbar ':'Ausverkauft ';let h=\"\";if(c>0){h=`check_circle Bestellt${c>1?`${c} `:\"\"} `,o.classList.add(\"ordered\"),new Date(t.date).toDateString()===s.toDateString()&&o.classList.add(\"today-ordered\")}const v=`${t.date}_${i}`,w=g.has(v);w&&o.classList.add(a.available?\"flagged-available\":\"flagged-sold-out\");const k=[...new Set([...x(a.name),...x(a.description)])];k.length>0&&o.classList.add(\"highlight-glow\");let I=\"\",L=\"\",S=\"\";if(d&&!r){const e=w?\"notifications_active\":\"notifications_none\",n=w?\"btn-flag active\":\"btn-flag\",s=w?\"Benachrichtigung deaktivieren\":\"Benachrichtigen wenn verf\u00fcgbar\";if(a.available&&!w||(S=`${e} `),a.available&&(I=c>0?`add `:`add_shopping_cart Bestellen `),c>0){const e=1===c?\"close\":\"remove\",n=1===c?\"Bestellung stornieren\":\"Eine Bestellung stornieren\";L=`${e} `}}let B=\"\";if(k.length>0){B=`${k.map(e=>`star ${J(e)} `).join(\"\")}
`}o.innerHTML=`\\n \\n \\n ${h}\\n ${L}\\n ${I}\\n ${S}\\n
${m}
\\n
\\n ${B}\\n ${J(function(e){if(\"all\"===p)return e||\"\";const t=function(e){if(!e)return{de:\"\",en:\"\",raw:\"\"};let t=e.replace(/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?=\\S)/g,\"($1)\\n\u2022 \");t.startsWith(\"\u2022 \")||(t=\"\u2022 \"+t);function n(e){let t=0,n=0;return e.forEach(e=>{const a=e.toLowerCase().replace(/[^a-z\u00e4\u00f6\u00fc\u00df]/g,\"\");if(a){let s=0,o=0;W.includes(a)?s=a.length:W.forEach(e=>{a.includes(e)&&e.length>s&&(s=e.length)}),P.includes(a)?o=a.length:P.forEach(e=>{a.includes(e)&&e.length>o&&(o=e.length)}),s>0&&(t+=s/a.length),o>0&&(n+=o/a.length),/^[A-Z\u00c4\u00d6\u00dc]/.test(e)&&(t+=.5)}}),{de:t,en:n}}function a(e){const t=e.trim().split(/\\s+/);if(t.length<2)return{enPart:e,nextDe:\"\"};let a=-1,s=-9999;for(let e=1;el.en&&m>s&&(s=m,a=e)}return-1!==a?{enPart:t.slice(0,a).join(\" \"),nextDe:t.slice(a).join(\" \")}:{enPart:e,nextDe:\"\"}}const s=e.split(/\\s*\\/\\s*(?![A-Z,]+\\))/);if(s.length>4)return{de:t,en:\"\",raw:t};const o=[],r=[];o.push(s[0].trim());const i=/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*/;for(let e=1;e0&&(o[o.length-1]=o[o.length-1]+\"(\"+s+\")\"),i&&o.push(i)}else{const e=a(t);r.push(e.enPart),e.nextDe&&o.push(e.nextDe)}}1===s.length&&0===r.length&&r.push(o[0]);if(o.length>r.length)for(let e=r.length;e0&&!l.startsWith(\"\u2022 \")&&(l=\"\u2022 \"+l);let c=r.join(\"\\n\u2022 \");r.length>0&&!c.startsWith(\"\u2022 \")&&(c=\"\u2022 \"+c);return{de:l,en:c,raw:t}}(e);return\"en\"===p?t.en||t.raw:t.de||t.raw}(a.description))}
`;const C=o.querySelector(\".btn-order\");C&&C.addEventListener(\"click\",t=>{t.stopPropagation();const a=t.currentTarget;a.disabled=!0,a.classList.add(\"loading\"),async function(t,a,s,o,r){if(d)try{const i=await fetch(`${e}/auth/user/`,{headers:f(d)});if(!i.ok)return void F(\"Fehler: Benutzerdaten konnten nicht geladen werden\",\"error\");const l=await i.json(),c=(new Date).toISOString(),m={uuid:crypto.randomUUID(),created:c,updated:c,order_type:7,items:[{article:a,course_group:null,modifiers:[],uuid:crypto.randomUUID(),name:s,description:r||\"\",price:String(parseFloat(o)),amount:1,vat:\"10.00\",comment:\"\"}],table:null,total:parseFloat(o),tip:0,currency:\"EUR\",venue:n,states:[],order_state:1,date:`${t}T10:30:00Z`,payment_method:\"payroll\",customer:{first_name:l.first_name,last_name:l.last_name,email:l.email,newsletter:!1},preorder:!0,delivery_fee:0,cash_box_table_name:null,take_away:!1},u=await fetch(`${e}/user/orders/`,{method:\"POST\",headers:f(d),body:JSON.stringify(m)});if(u.ok||201===u.status)F(`Bestellt: ${s}`,\"success\"),b=null,await y();else{const e=await u.json();F(`Fehler: ${e.detail||e.non_field_errors?.[0]||\"Bestellung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Order error:\",e),F(\"Netzwerkfehler bei Bestellung\",\"error\")}}(a.dataset.date,parseInt(a.dataset.article),a.dataset.name,parseFloat(a.dataset.price),a.dataset.desc||\"\").finally(()=>{a.disabled=!1,a.classList.remove(\"loading\")})});const D=o.querySelector(\".btn-cancel\");D&&D.addEventListener(\"click\",t=>{t.stopPropagation();const n=t.currentTarget;n.disabled=!0,async function(t,n,a){if(!d)return;const s=`${t}_${n}`,o=u.get(s);if(!o||0===o.length)return;const r=o[o.length-1];try{const t=await fetch(`${e}/user/orders/${r}/cancel/`,{method:\"PATCH\",headers:f(d),body:JSON.stringify({})});t.ok?(F(`Storniert: ${a}`,\"success\"),b=null,await y()):F(`Fehler: ${(await t.json()).detail||\"Stornierung fehlgeschlagen\"}`,\"error\")}catch(e){console.error(\"Cancel error:\",e),F(\"Netzwerkfehler bei Stornierung\",\"error\")}}(n.dataset.date,parseInt(n.dataset.article),n.dataset.name).finally(()=>{n.disabled=!1})});const O=o.querySelector(\".btn-flag\");O&&O.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;E(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,t.dataset.cutoff)}),A.appendChild(o)}),a.appendChild(A),a}(t);a&&v.appendChild(a)}),t.appendChild(v),setTimeout(()=>function(e){const t=e.querySelectorAll(\".menu-card\");if(0===t.length)return;let n=0;t.forEach(e=>{n=Math.max(n,e.querySelectorAll(\".menu-item\").length)});for(let e=0;e{const s=t.querySelectorAll(\".menu-item\");s[e]&&(s[e].style.height=\"auto\",n=Math.max(n,s[e].offsetHeight),a.push(s[e]))}),a.forEach(e=>{e.style.height=`${n}px`})}}(v),0)}function j(e,t){if(!e||!t)return!1;const n=e.replace(/^v/,\"\").split(\".\").map(Number),a=t.replace(/^v/,\"\").split(\".\").map(Number);for(let e=0;e(a[e]||0))return!0;if((n[e]||0)<(a[e]||0))return!1}return!1}async function H(e){const t=e?`${s}/tags?per_page=20`:`${s}/releases?per_page=20`,n=await fetch(t,{headers:{Accept:\"application/vnd.github.v3+json\"}});if(!n.ok){if(403===n.status)throw new Error(\"API Rate Limit erreicht (403). Bitte sp\u00e4ter erneut versuchen.\");throw new Error(`GitHub API ${n.status}`)}return(await n.json()).map(t=>{const n=e?t.name:t.tag_name;return{tag:n,name:e?n:t.name||n,url:`${o}/${n}/dist/install.html`,body:t.body||\"\"}})}async function K(){const e=\"v1.6.7\",t=\"true\"===localStorage.getItem(\"kantine_dev_mode\");try{const n=await H(t);if(!n.length)return;localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:t,versions:n}));const a=n[0].tag;if(console.log(`[Kantine] Version Check: Local [${e}] vs Latest [${a}] (${t?\"dev\":\"stable\"})`),!j(a,e))return;console.log(`[Kantine] Update verf\u00fcgbar: ${a}`);const s=document.querySelector(\".header-left h1\");if(s&&!s.querySelector(\".update-icon\")){const e=document.createElement(\"a\");e.className=\"update-icon\",e.href=n[0].url,e.target=\"_blank\",e.innerHTML=\"\ud83c\udd95\",e.title=`Update: ${a} \u2014 Klick zum Installieren`,e.style.cssText=\"margin-left:8px;font-size:1em;text-decoration:none;cursor:pointer;vertical-align:middle;\",s.appendChild(e)}}catch(e){console.warn(\"[Kantine] Version check failed:\",e)}}function Q(){if(!d||!m)return void X();const e=new Date,t=e.getDay();if(0===t||6===t)return void X();const n=e.toISOString().split(\"T\")[0];let a=!1;for(const e of u.keys())if(e.startsWith(n)){a=!0;break}if(a)return void X();const s=new Date;s.setHours(10,0,0,0);const o=s-e;if(o<=0)return void X();const r=Math.floor(o/36e5),i=Math.floor(o%36e5/6e4),l=document.querySelector(\".header-center-wrapper\");if(!l)return;let c=document.getElementById(\"order-countdown\");if(c||(c=document.createElement(\"div\"),c.id=\"order-countdown\",l.insertBefore(c,l.firstChild)),c.innerHTML=`Bestellschluss: ${r}h ${i}m `,o<36e5){c.classList.add(\"urgent\");const e=`kantine_notified_${n}`;localStorage.getItem(e)||(\"granted\"===Notification.permission?new Notification(\"Kantine: Bestellschluss naht!\",{body:\"Du hast heute noch nichts bestellt. Nur noch 1 Stunde!\",icon:\"\u23f3\"}):\"default\"===Notification.permission&&Notification.requestPermission(),localStorage.setItem(e,\"true\"))}else c.classList.remove(\"urgent\")}function X(){const e=document.getElementById(\"order-countdown\");e&&e.remove()}function U(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate())),n=t.getUTCDay()||7;t.setUTCDate(t.getUTCDate()+4-n);const a=new Date(Date.UTC(t.getUTCFullYear(),0,1));return Math.ceil(((t-a)/864e5+1)/7)}function G(e){const t=new Date(e.getTime());return t.setDate(t.getDate()+3-(t.getDay()+6)%7),t.getFullYear()}function J(e){const t=document.createElement(\"div\");return t.textContent=e||\"\",t.innerHTML}setInterval(Q,6e4),setTimeout(Q,1e3);const W=[\"apfel\",\"aubergine\",\"auflauf\",\"beere\",\"blumenkohl\",\"bohne\",\"braten\",\"brokkoli\",\"brot\",\"brust\",\"br\u00f6tchen\",\"butter\",\"chili\",\"dessert\",\"dip\",\"eier\",\"eintopf\",\"eis\",\"erbse\",\"erdbeer\",\"essig\",\"filet\",\"fisch\",\"fisole\",\"fleckerl\",\"fleisch\",\"fl\u00fcgel\",\"frucht\",\"f\u00fcr\",\"gebraten\",\"gem\u00fcse\",\"gew\u00fcrz\",\"gratin\",\"grie\u00df\",\"gulasch\",\"gurke\",\"himbeer\",\"honig\",\"huhn\",\"h\u00e4hnchen\",\"jambalaya\",\"joghurt\",\"karotte\",\"kartoffel\",\"keule\",\"kirsch\",\"knacker\",\"knoblauch\",\"kn\u00f6del\",\"kompott\",\"kraut\",\"kr\u00e4uter\",\"kuchen\",\"k\u00e4se\",\"k\u00fcrbis\",\"lauch\",\"mandel\",\"milch\",\"mild\",\"mit\",\"mohn\",\"most\",\"m\u00f6hre\",\"natur\",\"nockerl\",\"nudel\",\"nuss\",\"nu\u00df\",\"obst\",\"oder\",\"olive\",\"paprika\",\"pfanne\",\"pfannkuchen\",\"pfeffer\",\"pikant\",\"pilz\",\"plunder\",\"p\u00fcree\",\"ragout\",\"rahm\",\"reis\",\"rind\",\"sahne\",\"salami\",\"salat\",\"salz\",\"sauer\",\"scharf\",\"schinken\",\"schnitte\",\"schnitzel\",\"schoko\",\"schupf\",\"schwein\",\"sellerie\",\"senf\",\"sosse\",\"so\u00dfe\",\"spargel\",\"sp\u00e4tzle\",\"speck\",\"spie\u00df\",\"spinat\",\"steak\",\"suppe\",\"s\u00fc\u00df\",\"tofu\",\"tomate\",\"topfen\",\"torte\",\"tr\u00fcffel\",\"und\",\"vanille\",\"vogerl\",\"vom\",\"wien\",\"wurst\",\"zucchini\",\"zum\",\"zur\",\"zwiebel\",\"\u00f6l\"],P=[\"almond\",\"and\",\"apple\",\"asparagus\",\"bacon\",\"baked\",\"ball\",\"bean\",\"beef\",\"berry\",\"bread\",\"breast\",\"broccoli\",\"bun\",\"butter\",\"cabbage\",\"cake\",\"caper\",\"carrot\",\"casserole\",\"cauliflower\",\"celery\",\"cheese\",\"cherry\",\"chicken\",\"chili\",\"choco\",\"chocolate\",\"cider\",\"cilantro\",\"coffee\",\"compote\",\"cream\",\"cucumber\",\"curd\",\"danish\",\"dessert\",\"dip\",\"dumpling\",\"egg\",\"eggplant\",\"filet\",\"fish\",\"for\",\"fried\",\"from\",\"fruit\",\"garlic\",\"goulash\",\"gratin\",\"ham\",\"herb\",\"honey\",\"hot\",\"ice\",\"jambalaya\",\"leek\",\"leg\",\"mash\",\"meat\",\"mexican\",\"mild\",\"milk\",\"mint\",\"mushroom\",\"mustard\",\"noodle\",\"nut\",\"oat\",\"oil\",\"olive\",\"onion\",\"or\",\"oven\",\"pan\",\"pancake\",\"pea\",\"pepper\",\"plain\",\"plate\",\"poppy\",\"pork\",\"potato\",\"pumpkin\",\"radish\",\"ragout\",\"raspberry\",\"rice\",\"roast\",\"roll\",\"salad\",\"salami\",\"salt\",\"sauce\",\"sausage\",\"shrimp\",\"skewer\",\"slice\",\"soup\",\"sour\",\"spice\",\"spicy\",\"spinach\",\"steak\",\"stew\",\"strawberr\",\"strawberry\",\"strudel\",\"sweet\",\"tart\",\"thyme\",\"to\",\"tofu\",\"tomat\",\"tomato\",\"truffle\",\"trukey\",\"turkey\",\"vanilla\",\"vegan\",\"vegetable\",\"vinegar\",\"wedge\",\"wing\",\"with\",\"wok\",\"yogurt\",\"zucchini\"];!function(){document.title=\"Kantine Weekly Menu\",document.querySelectorAll&&document.querySelectorAll('link[rel*=\"icon\"]').forEach(e=>e.remove());const e=document.createElement(\"link\");if(e.rel=\"icon\",e.type=\"image/png\",e.href=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAOUElEQVR4nNWYaXRVRbbH//tMd0xITAISyASBAGGSOYJP6fdEhAAiMjiAAxDoVsCWtpu0jdcrrUQFGYI2CQg8RIYwCQiCtjIIChImISASSJgTSYiZ7niqdn+4AQEbaIcP7+21zqqzzqmq86tdtXf96wD/x41+gz4UANylS5dE5mDU3r0H8uueyas1XC6l7tntLTWVgZXAkJXiN2ADAKhEhIg7IpaGhYWdZGYCoOIXDJ6uua6Y9mvhAIjOnTu3y8/Pf0RKqSckJDwD4L26d5IAbrtofs9LJOJVnxcCZGeGBcRWgKwsySpIWAXDQlAsDLZrBLVdzB3PfjpoxPe/FhCqpuLIkSPTwsPD9fDwcFlSUvLapEmT1mRlZVXi3ntV3r5dsCKp2uud57NadcUfBLTQbBOHhsFQwWAQQutClxI+gT8D/+m6uAkbAJHaNjXd4/H8T2bmJLFq1UoZCAQaLFy4cDIRSWzfznC56JsRGZ8319WOVr//ogwEGLW1fng8Jtdd8NSa8HhNeDxB8vpMGQjUBj21gZ8LSDfcMzMbxwuOvxnbKJbHjh1LnTt3Ufv37ydLS0uf7devXysAEm434HJp+54Zd7iFrvax6XoZGxYLGAoAjcGaCdYAaGBoADQCVNht+LmAXBeNV9rJpKSk3/v9/pavv/Z3GR5eT5FS0syZs9hqtRpbt259W9M0BkBwu024XNrep5872FzVHrABhawqBGYmEFQoodETIdSAYL/mQ7fBYgoVTHC7Je69VwMgMzMzY86cOTO5Y6cOcvjwJxUhBIQQSEpKUidOnCiqq6sfaNOmVT8AAoBaB2nsG/WHAw6FtsEwCAQJuiHciUBgGfSr8vaALpcCIr5r3rzk6AXvnmm28N1h2L7dJFXlhQsXTpZSRs2aOUsSEQkhQASYpolJkyZR47jGfPTo8beY2VLnfU1xuwMNc2e/Xk40Cj6/hKKEogPMVyiJADCkrvpuA1jnsYy8vHr7R406yVLsv2BYliW8P/+Z6Y2aNSwpKRn38MMDZffuPVQigmEY0DQdmqbB6XQqWVOzpN/vT0lISpgAIklut9lwXvYr5aqWKb0+wcwKJMAAsaJSKIx/zIQOOELAN4Uj4r4ffBC5q6r0lFXXZpaPGu+ul5v9vveOek/EnP9+evLy1W1yli7pFR+XIE+eLFRKS0ohhED9BvWRmJAIh8PB/Qf05w0bPqKcO++s75r68lM/SH5LeDwmARqYmUmBBpACeAKaaleDQSFVTdVZVt0TE5e8eciQS/8+DxJxv6VLG3z82GOlkTmz3qtyhr8SmTvLWpExbrj1HzMqizk48Ymc7EvVlyvQ7eFHyOP3w2qxAAT4fX4IIdC6TWtu2769svuTT9e/MemPf6wQ8q/S4zPBUgWIWVGkZrOqMVKOjrPY9x7y1mz1a3okCcEMljK0dm/YSeo8l5eXZ4y9dPZwZG72moqMcWOj5s7kmpjoScac6Vpx+86nXvPW8t83rI85mNwc8xctohbNmsFqs13t5vjx41i6YgVdPn2aB29co7xbcORFq8/PBKiAAkmQutWqNhBy/OmMcfPPAOg8f26v4/B/7FGNaAoEgvVQiZ8CEjFcLmXw4MHBF3JmT6kIc8yOzM3G5YxxY6NyZhkluvqnzKoKzOmUhsYR9fiFf24hpV44lrRMwf5du+DxeRHXuDGSU1rA/fLLtOpcMZ7ctD5dV1RIliCAhQKpWS1qAynHn84Yl80ul4b7gL09x+Z3zp1z/1GWnwnAHl8v3v9TQABwuyUBiuJ2ZzeeO8N6KTLyzbB/zKKLGePH9lmx5J7cQ/vbC0XhB5OaKobNjvUH98Ol62hy8CgulpfjYmkpurVOha33/Rjx4WroNrskVVXq5geaYVHrm3L86bETQnButwk3AJdL25vx3MGU+dkPlAtlWX5ZmQ1A7c0VRygtmHE5s6act1n/1pnp6y8GDE51HzvsmLLtc8CwwGrRETBNNI2IxHdPZlxturjgEJ7ashG6ZoAolEYlgdnQzcTI6LEnhzy+8CrctZaXp2LIEDF02bJEr81Wvv6hh6pvJYkILpequt1m7PJFr56tqJj8fGob9E9qigfXroKiKmBm+KRAQ7sdB4eOQITFhhWF32Lkp5tD6UGhkAAQUioOm9Lph9plF17MXFasqRvYFNdrxh8do8Dtvvr8VomaXa+8IgURHv54qzkqsWlw5hfbZa/VeSCFAMnQiEBSItbuRH1nOHws4f5yJ4LBIAxdD6kVyTCFUBb+d29e3LvvgHOGsb5Du/ZtANRpmRvM7ZbXbKm3FJUqABEZHd3H0NSNhceOyb8c2qe8u3c3oGqhllJC03UYRPhrlzS81KU7jpZdQt8P81BcXQOHocFjBjGlbQf8pWt3aHYHp6Wl0Z49e7bput4zEAioqEsnN7ObefCKWtErysreTE5Ols6ISH6tXUe4O3RC99hYpEREIL1pM8TYbPBIE3/buQ0Ttn2CVtEx2DJoGOLDHKitqsSygUPQ4lwJchYvBjNT9+53CwD3paQkP4Yr+/QvAFQAyObNk8cQUWqTpCbMzOrq1WuQXHQeO4eOQP6wEdgwYDDWpg9EpGbAolswe18+Ht+0Ds0jo/DRQ0OQ22cAhsY3gaNBA5w9fRpEhORmzYiZuaj4zFsTJkyIAOoEzM8AVADwo48+Gn3+wkUXM0u7w05EBI/XgxqWkMxwGlb4hYmudzbCugGPQFcAm8WCpceO4MG1y9E8Mgqj23WEKSXqhYUhGAyGemco9evHSCFk7KJFi14lInkLR/3bF0REctOmTS6FlOgnhj/OpaWlCgBER0ehrKwMChFqzCB6rVmBiTv+iXsaxWN1+iBACtgtVmw+dRI9VizG6apKaIqC0rIyOB0OMDNOnTqJoUOHKBmjR4rKyso/9OzZswNuMdU3AqoAZHp6emplZeWYJ4Y/Ll/660vKkcOHAQAdO3bGt0cOw2MG0f/DldhRfApv5+/BS19uQ6+EJKzqNwjCNOGwWJFfWoLfLV+MMz4PThw8iJatW4OIcPjIETRp2pRee30qHA6HumfPnuy6k+B/ZGqdXPrY4XTw+fPnTCEEx8fH8d59+czMvPPLnfy7lUsY06Zw+DvT2TlnGuOtV3nCtk+YmfnDwm9ZmzGVHXOmszJjKjd+7x1evP0zNr1e/qGqihvHNeZ9+0N9vT1jugmAU1KSn7nGQTf1oApAtG7duk9NTU3vF198UcTGNlIVRUHvB/tgissFE8DU8lJ8XlyEMJsdJjMkh/RmjNUGU0oMaJqC9x9Ih8fvhV03UFJdjQlHv8FuXy22rFqFiDsi0eGujggGgxg/fgK1b99OFhYWZblcrmiEAua6WaVrSmJm1TCMgw0b3tny2LFjbLXaFBBwuqgYWz7Zgs0JsVh36ADCwsMhZAjMKwVye6djVErqdSNfXVSIR9asgNNmQyAQhGax4IXGcRjZrBXimqdACBOGbmD37q9EWtrdalRM1LyK8ooMKeV1ufGGQ1DC2GAw2CorK0va7Q7FFAIEQlyTJHzePBHrjnwDZ71wmCwBlvAIE5NSWiLNE0DJ99+jrLwMBQUFmDF7Fs4uy8P8B/qgpqYGuq5BmkFknS7CRzIAVVGgajqCZhDduqWpo0aNEuWXykf16NEjDTcEDF2BzMzMjHrjjTeOde3aJfLLL79CwAwquqrBLwUGrF+FT747jrDwcJhCAmB4g0HM7Z2O3qqBN7Oz4fN6AWZYLBakpKRgwMCBSIxPwIqzpzBs5XI4LFYwS3i8Hvw57R680aMnhBRgBqoqK0VKSopaU1Oz3+v1dqkTGBJA6D8KEYmoqKg5ZeVlz369Z4/ZsVNnjYVAkICBG1Zjc+EJOO0OCCFBxPAEg3C17YDJ3e+FarXeNOL+d8kSHNr5BRo98yT+9MU2OKxWKESorq3BU+3uwvz7+wCSoaoqFixYIEaOHKkmJiZOKC4unn0lJggA9e3bN3Xjxo0Hhj06TFm2dBmxlORniYEb1mBz4XdwOuwQpgQR4KmqQs7Dg6F+uhXuadPRo3t3dOvWFQmJidBUDRcunMfevfnYtWsnQITxzz+PMU8/jaz8r5C57XM4nE6oRKiqrUXfZs2xvO9AOHUDADjt7jTe/dXu6jFjxqTm5ORcAECk6xoMw7Le6XSmF54sNJ0Op1oT8CuDN63D5sLvEO5wQAiBoBAiIAUtHDAITzVJAQCcOHEC69Z9iP37D+Dy5cuQLBEeFo4WLVugb5++SEtLu86jc747jHEb1sNmWFhXFbXKU4u0uASs7vsQGjrD+ey5c8HWqakGES2rqal5TAihUnx8/ONnzpxZEhsbi65du+L+nvfhWMe2nL19K4XXi0BQmCCG1Jx2ZXLrdihbsgKHi4qhqQrsNjscDgdM00QgEAAzwzAM6LoOv9+PyqpKCFNA0zQIKdGpVQsogwbg9QP7oAZNqSuKUlldhf9q0ZInWsJoUe487NixA+Xl5UhKSupfVFS0QfP7/cPtdntBxQ8/8Nq1a9G0VQvrZxcik1WrRZhSgBWiILMyslnKx6ULlzSYNjfHWpevfrZt/OgjyrJagsN63uP7oOBIV0gh7Dab/Pr7Uv2A03dx7dq15RarFXannbw+7xP5+fmbr+Q+AQIURYXP69XvzM3eUWmzdIPXC9UwECPly8Ujn5sCANZbBMXtjAH4fT7oRIiaOzO3ymoZzULC6vN7erVskbruwYHFXq+XDMPgQCCgEpG8cQ9UAMge773X5AR7p5ng2AjGgqLR43JlXp7KgwdLIvpF3rsKyUxEBBXguPnvTPAbets7/GJBwejf70KdDr1tB6ireTVbXiPBf6XRDeWPNz8Khuuc9pNjJ9WdjRmAcLsZeXkKhgz5rX5o83VlXp7KBQWhH6shXXhtnf8f9i8ccK5KeMWwRQAAAABJRU5ErkJggg==\",document.head.appendChild(e),!document.querySelector('link[href*=\"fonts.googleapis.com/css2?family=Inter\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\",document.head.appendChild(e)}if(!document.querySelector('link[href*=\"Material+Icons+Round\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/icon?family=Material+Icons+Round\",document.head.appendChild(e)}document.body.innerHTML=`\\n \\n \\n\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Initialisierung...
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Markiere Men\u00fcs automatisch, wenn sie diese Schlagw\u00f6rter enthalten.\\n
\\n
\\n \\n Hinzuf\u00fcgen \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Lade Historie...
\\n
\\n
\\n
\\n \\x3c!-- Dynamically populated --\\x3e\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Aktuell: v1.6.7 \\n
\\n
\\n \\n \\n Dev-Mode (alle Tags anzeigen) \\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n \\n update \\n Gerade aktualisiert \\n
\\n \\n
\\n
Lade Men\u00fcdaten...
\\n
\\n \\n \\n\\n \\n
`}(),function(){const n=document.getElementById(\"btn-this-week\"),a=document.getElementById(\"btn-next-week\"),s=document.getElementById(\"btn-refresh\"),o=document.getElementById(\"theme-toggle\"),r=document.getElementById(\"btn-login-open\"),i=document.getElementById(\"btn-login-close\"),l=document.getElementById(\"btn-logout\"),g=document.getElementById(\"login-form\"),k=document.getElementById(\"login-modal\"),A=document.getElementById(\"btn-highlights\"),E=document.getElementById(\"highlights-modal\"),x=document.getElementById(\"btn-highlights-close\"),C=document.getElementById(\"btn-add-tag\"),D=document.getElementById(\"tag-input\"),O=document.getElementById(\"btn-history\"),N=document.getElementById(\"history-modal\"),T=document.getElementById(\"btn-history-close\");document.querySelectorAll(\".lang-btn\").forEach(e=>{e.addEventListener(\"click\",()=>{p=e.dataset.lang,localStorage.setItem(\"kantine_lang\",p),document.querySelectorAll(\".lang-btn\").forEach(e=>e.classList.remove(\"active\")),e.classList.add(\"active\"),z()})}),A&&A.addEventListener(\"click\",()=>{E.classList.remove(\"hidden\")}),x&&x.addEventListener(\"click\",()=>{E.classList.add(\"hidden\")}),O.addEventListener(\"click\",()=>{d?(N.classList.remove(\"hidden\"),async function(){const t=document.getElementById(\"history-loading\"),n=document.getElementById(\"history-content\"),a=document.getElementById(\"history-progress-fill\"),s=document.getElementById(\"history-progress-text\");let o=[];if(b)o=b;else{const e=localStorage.getItem(\"kantine_history_cache\");if(e)try{o=JSON.parse(e),b=o}catch(e){console.warn(\"History cache parse error\",e)}}o.length>0&&w(o);if(!d)return;0===o.length&&(n.innerHTML=\"\",t.classList.remove(\"hidden\"));a.style.width=\"0%\",s.textContent=o.length>0?\"Suche nach neuen Bestellungen...\":\"Lade Bestellhistorie...\",o.length>0&&t.classList.remove(\"hidden\");let r=o.length>0?`${e}/user/orders/?venue=591&ordering=-created&limit=5`:`${e}/user/orders/?venue=591&ordering=-created&limit=50`,i=[],l=0,c=0===o.length,m=!1;try{for(;r&&!m;){const e=await fetch(r,{headers:f(d)});if(!e.ok)throw new Error(`Fetch failed: ${e.status}`);const t=await e.json();t.count&&0===l&&(l=t.count);const n=t.results||[];for(const e of n){const t=o.findIndex(t=>t.id===e.id);if(!c&&-1!==t){const n=o[t];if(n.updated===e.updated&&n.order_state===e.order_state){m=!0;break}}i.push(e)}if(!m&&c)if(l>0){const e=Math.round(i.length/l*100);a.style.width=`${e}%`,s.textContent=`Lade Bestellung ${i.length} von ${l}...`}else s.textContent=`Lade Bestellung ${i.length}...`;else m||(s.textContent=`${i.length} neue/ge\u00e4nderte Bestellungen gefunden...`);r=m?null:t.next}if(i.length>0){const e=new Map(o.map(e=>[e.id,e]));for(const t of i)e.set(t.id,t);const t=Array.from(e.values());t.sort((e,t)=>new Date(t.created)-new Date(e.created)),b=t;try{localStorage.setItem(\"kantine_history_cache\",JSON.stringify(t))}catch(e){console.warn(\"History cache write error\",e)}w(b)}}catch(e){console.error(\"Error in history sync:\",e),0===o.length?n.innerHTML='Fehler beim Laden der Historie.
':F(\"Hintergrund-Synchronisation fehlgeschlagen\",\"error\")}finally{t.classList.add(\"hidden\")}}()):k.classList.remove(\"hidden\")}),T.addEventListener(\"click\",()=>{N.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===N&&N.classList.add(\"hidden\"),e.target===E&&E.classList.add(\"hidden\")});const q=document.querySelector(\".version-tag\"),$=document.getElementById(\"version-modal\"),K=document.getElementById(\"btn-version-close\");q&&q.addEventListener(\"click\",e=>{e.preventDefault(),e.stopPropagation(),function(){const e=document.getElementById(\"version-modal\"),t=document.getElementById(\"version-list-container\"),n=document.getElementById(\"dev-mode-toggle\"),a=\"v1.6.7\";if(!e)return;e.classList.remove(\"hidden\");const s=document.getElementById(\"version-current\");s&&(s.textContent=a);const o=\"true\"===localStorage.getItem(\"kantine_dev_mode\");async function r(e){const s=n.checked;function o(e){if(!e||!e.length)return void(t.innerHTML='Keine Versionen gefunden.
');t.innerHTML='';const n=t.querySelector(\".version-list\");e.forEach(e=>{const t=e.tag===a,s=j(e.tag,a),o=document.createElement(\"li\");o.className=\"version-item\"+(t?\" current\":\"\");let r=\"\";t?r='\u2713 Installiert ':s&&(r='\u2b06 Neu! ');let i=\"\";t||(i=`Installieren `),o.innerHTML=`\\n \\n ${e.tag} \\n ${r}\\n
\\n ${i}\\n `,n.appendChild(o)})}t.innerHTML='Lade Versionen...
';try{const e=localStorage.getItem(\"kantine_version_cache\");let t=null;if(e)try{t=JSON.parse(e)}catch(e){}t&&t.devMode===s&&t.versions&&o(t.versions);const n=await H(s),a=JSON.stringify(n);a!==(t?JSON.stringify(t.versions):\"\")&&(localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:s,versions:n})),o(n))}catch(e){t.innerHTML=`Fehler: ${e.message}
`}}n.checked=o,r(!1),n.onchange=()=>{localStorage.setItem(\"kantine_dev_mode\",n.checked),localStorage.removeItem(\"kantine_version_cache\"),r(!0)}}()}),K&&K.addEventListener(\"click\",()=>{$.classList.add(\"hidden\")});const Q=document.getElementById(\"btn-clear-cache\");Q&&Q.addEventListener(\"click\",()=>{confirm(\"M\u00f6chtest du wirklich alle lokalen Daten (inkl. Login-Session, Cache und Einstellungen) l\u00f6schen? Die Seite wird danach neu geladen.\")&&(Object.keys(localStorage).forEach(e=>{e.startsWith(\"kantine_\")&&localStorage.removeItem(e)}),window.location.reload())}),window.addEventListener(\"click\",e=>{e.target===$&&$.classList.add(\"hidden\")}),C.addEventListener(\"click\",()=>{(function(e){if(e=e.trim().toLowerCase(),e&&!L.includes(e))return L.push(e),S(),!0;return!1})(D.value)&&(D.value=\"\",B())}),D.addEventListener(\"keypress\",e=>{\"Enter\"===e.key&&C.click()});const X=localStorage.getItem(\"theme\"),U=window.matchMedia(\"(prefers-color-scheme: dark)\").matches,G=o.querySelector(\".theme-icon\");\"dark\"===X||!X&&U?(document.documentElement.setAttribute(\"data-theme\",\"dark\"),G.textContent=\"dark_mode\"):(document.documentElement.setAttribute(\"data-theme\",\"light\"),G.textContent=\"light_mode\"),o.addEventListener(\"click\",()=>{const e=\"dark\"===document.documentElement.getAttribute(\"data-theme\")?\"light\":\"dark\";document.documentElement.setAttribute(\"data-theme\",e),localStorage.setItem(\"theme\",e),G.textContent=\"dark\"===e?\"dark_mode\":\"light_mode\"}),n.addEventListener(\"click\",()=>{\"this-week\"!==c&&(c=\"this-week\",n.classList.add(\"active\"),a.classList.remove(\"active\"),z())}),a.addEventListener(\"click\",()=>{a.classList.remove(\"new-week-available\"),\"next-week\"!==c&&(c=\"next-week\",a.classList.add(\"active\"),n.classList.remove(\"active\"),z())}),s.addEventListener(\"click\",()=>{d?M():k.classList.remove(\"hidden\")}),r.addEventListener(\"click\",()=>{k.classList.remove(\"hidden\"),document.getElementById(\"login-error\").classList.add(\"hidden\"),g.reset()}),i.addEventListener(\"click\",()=>{k.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===k&&k.classList.add(\"hidden\")}),g.addEventListener(\"submit\",async n=>{n.preventDefault();const a=document.getElementById(\"employee-id\").value.trim(),s=document.getElementById(\"password\").value,o=document.getElementById(\"login-error\"),r=g.querySelector('button[type=\"submit\"]'),i=r.textContent;r.disabled=!0,r.textContent=\"Wird eingeloggt...\";try{const n=`knapp-${a}@bessa.app`,r=await fetch(`${e}/auth/login/`,{method:\"POST\",headers:f(t),body:JSON.stringify({email:n,password:s})}),i=await r.json();if(r.ok){d=i.key,m=a,localStorage.setItem(\"kantine_authToken\",i.key),localStorage.setItem(\"kantine_currentUser\",a);try{const t=await fetch(`${e}/auth/user/`,{headers:f(d)});if(t.ok){const e=await t.json();e.first_name&&localStorage.setItem(\"kantine_firstName\",e.first_name),e.last_name&&localStorage.setItem(\"kantine_lastName\",e.last_name)}}catch(e){console.error(\"Failed to fetch user info:\",e)}v(),k.classList.add(\"hidden\"),y(),g.reset(),I(),M()}else o.textContent=i.non_field_errors?.[0]||i.error||\"Login fehlgeschlagen\",o.classList.remove(\"hidden\")}catch(e){console.error(\"Login error:\",e),o.textContent=\"Ein Fehler ist aufgetreten\",o.classList.remove(\"hidden\")}finally{r.disabled=!1,r.textContent=i}}),l.addEventListener(\"click\",()=>{localStorage.removeItem(\"kantine_authToken\"),localStorage.removeItem(\"kantine_currentUser\"),localStorage.removeItem(\"kantine_firstName\"),localStorage.removeItem(\"kantine_lastName\"),d=null,m=null,u=new Map,h&&(clearInterval(h),h=null,console.log(\"Polling stopped\")),v(),z()})}(),v(),function(){const e=new Date,t=e.toISOString().split(\"T\")[0];let n=!1;for(const a of[...g]){const[s]=a.split(\"_\");let o=!1;if(s=t&&(o=!0)}o&&(g.delete(a),n=!0)}n&&k()}();(function(){try{const e=localStorage.getItem(C),t=localStorage.getItem(D);if(console.log(`[Cache] localStorage: key=${!!e} (${e?e.length:0} chars), ts=${t}`),e){r=JSON.parse(e),i=U(new Date),l=(new Date).getFullYear(),console.log(`[Cache] Parsed ${r.length} weeks:`,r.map(e=>`KW${e.weekNumber}/${e.year} (${(e.days||[]).length} days)`)),z(),$(),A(),t&&q(t);try{const e=new Set;r.forEach(t=>{(t.days||[]).forEach(t=>{(t.items||[]).forEach(t=>{let n=(t.description||\"\").replace(/\\s+/g,\" \").trim();n&&n.includes(\" / \")&&e.add(n)})})});const t=Array.from(e).join(\"\\n\\n\");console.log(\"=== GEFUNDENE MEN\u00dc-TEXTE (\"+e.size+\") ===\"),console.log(t)}catch(e){}return console.log(\"Loaded menu from cache\"),!0}}catch(e){console.warn(\"Failed to load cached menu:\",e)}return!1})()?(document.getElementById(\"loading\").classList.add(\"hidden\"),!function(){const e=localStorage.getItem(D);if(!e)return console.log(\"[Cache] No timestamp found\"),!1;const t=Date.now()-new Date(e).getTime(),n=Math.round(t/6e4);if(t>36e5)return console.log(`[Cache] Stale: ${n}min old (max 60)`),!1;const a=U(new Date),s=G(new Date),o=r.some(e=>e.weekNumber===a&&e.year===s&&e.days&&e.days.length>0);return console.log(`[Cache] Age: ${n}min, looking for KW${a}/${s}, found: ${o}`),o}()?(console.log(\"Cache stale or incomplete \u2013 refreshing from API\"),M()):console.log(\"Cache fresh & complete \u2013 skipping API refresh\")):M(),d&&I(),K(),setInterval(K,36e5),console.log(\"Kantine Wrapper loaded \u2705\")}();\n";
+sc.textContent="function showErrorModal(e,t,n,a){const s=\"error-modal\";let o=document.getElementById(s);o&&o.remove(),o=document.createElement(\"div\"),o.id=s,o.className=\"modal hidden\",o.innerHTML=`\\n \\n \\n
\\n
${t}
\\n
\\n \\n ${n}\\n open_in_new \\n \\n
\\n
\\n
\\n `,document.body.appendChild(o),document.getElementById(\"btn-error-redirect\").addEventListener(\"click\",()=>{window.location.href=a}),requestAnimationFrame(()=>{o.classList.remove(\"hidden\")})}!function(){\"use strict\";if(window.__KANTINE_LOADED)return;window.__KANTINE_LOADED=!0;const e=\"https://api.bessa.app/v1\",t=\"c3418725e95a9f90e3645cbc846b4d67c7c66131\",n=591,a=\"TauNeutrino/kantine-overview\",s=`https://api.github.com/repos/${a}`,o=`https://htmlpreview.github.io/?https://github.com/${a}/blob`;let r=[],i=U(new Date),l=(new Date).getFullYear(),c=\"this-week\",d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\"),u=new Map,g=new Set(JSON.parse(localStorage.getItem(\"kantine_flags\")||\"[]\")),h=null,p=localStorage.getItem(\"kantine_lang\")||\"de\";function f(e){return{Authorization:`Token ${e||t}`,Accept:\"application/json\",\"Content-Type\":\"application/json\",\"X-Client-Version\":\"1.7.0_prod/2026-01-26\"}}function v(){if(!d)try{const e=localStorage.getItem(\"AkitaStores\");if(e){const t=JSON.parse(e);t.auth&&t.auth.token&&(console.log(\"Found existing Bessa session!\"),d=t.auth.token,localStorage.setItem(\"kantine_authToken\",d),t.auth.user&&(m=t.auth.user.id||\"unknown\",localStorage.setItem(\"kantine_currentUser\",m),t.auth.user.firstName&&localStorage.setItem(\"kantine_firstName\",t.auth.user.firstName),t.auth.user.lastName&&localStorage.setItem(\"kantine_lastName\",t.auth.user.lastName)))}}catch(e){console.warn(\"Failed to parse AkitaStores:\",e)}d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\");const e=localStorage.getItem(\"kantine_firstName\"),t=document.getElementById(\"btn-login-open\"),n=document.getElementById(\"user-info\"),a=document.getElementById(\"user-id-display\");d?(t.classList.add(\"hidden\"),n.classList.remove(\"hidden\"),a.textContent=e||(m?`User ${m}`:\"Angemeldet\"),y()):(t.classList.remove(\"hidden\"),n.classList.add(\"hidden\"),a.textContent=\"\"),z()}async function y(){if(d)try{const t=await fetch(`${e}/user/orders/?venue=591&ordering=-created&limit=50`,{headers:f(d)}),n=await t.json();if(t.ok){u=new Map;const e=n.results||[];for(const t of e){if(9===t.order_state)continue;const e=t.date.split(\"T\")[0];for(const n of t.items||[]){const a=`${e}_${n.article}`;u.has(a)||u.set(a,[]),u.get(a).push(t.id)}}console.log(`Fetched ${e.length} orders, mapped active ones.`),z(),$()}}catch(e){console.error(\"Error fetching orders:\",e)}}let b=null;function w(e){const t=document.getElementById(\"history-content\");if(!e||0===e.length)return void(t.innerHTML='Keine Bestellungen gefunden.
');const n={};e.forEach(e=>{const t=new Date(e.date),a=t.getFullYear(),s=t.getMonth(),o=`${a}-${s.toString().padStart(2,\"0\")}`,r=t.toLocaleString(\"de-AT\",{month:\"long\"}),i=U(t);n[a]||(n[a]={year:a,months:{}}),n[a].months[o]||(n[a].months[o]={name:r,year:a,monthIndex:s,count:0,total:0,weeks:{}}),n[a].months[o].weeks[i]||(n[a].months[o].weeks[i]={label:`KW ${i}`,items:[],count:0,total:0});(e.items||[]).forEach(t=>{const s=parseFloat(t.price||e.total||0);n[a].months[o].weeks[i].items.push({date:e.date,name:t.name||\"Men\u00fc\",price:s,state:e.order_state}),9!==e.order_state&&(n[a].months[o].weeks[i].count++,n[a].months[o].weeks[i].total+=s,n[a].months[o].count++,n[a].months[o].total+=s)})});const a=Object.keys(n).sort((e,t)=>t-e);let s=\"\";a.forEach(e=>{const t=n[e];s+=`\\n `;Object.keys(t.months).sort((e,t)=>t.localeCompare(e)).forEach(e=>{const n=t.months[e];s+=`
\\n \\n
`;Object.keys(n.weeks).sort((e,t)=>parseInt(t)-parseInt(e)).forEach(e=>{const t=n.weeks[e];s+=`
\\n `,t.items.forEach(e=>{const t=new Date(e.date).toLocaleDateString(\"de-AT\",{weekday:\"short\",day:\"2-digit\",month:\"2-digit\"});let n=\"\";n=9===e.state?'
Storniert ':8===e.state?'
Abgeschlossen ':'
\u00dcbertragen ',s+=`\\n
\\n
${t}
\\n
\\n
${J(e.name)} \\n
${n}
\\n
\\n
\u20ac${e.price.toFixed(2)}
\\n
`}),s+=\"
\"}),s+=\"
\"}),s+=\"
\"}),t.innerHTML=s;t.querySelectorAll(\".history-month-header\").forEach(e=>{e.addEventListener(\"click\",()=>{const t=e.parentElement;t.classList.contains(\"open\")?(t.classList.remove(\"open\"),e.setAttribute(\"aria-expanded\",\"false\")):(t.classList.add(\"open\"),e.setAttribute(\"aria-expanded\",\"true\"))})})}function k(){localStorage.setItem(\"kantine_flags\",JSON.stringify([...g]))}function A(){const e=document.getElementById(\"alarm-bell\"),t=document.getElementById(\"alarm-bell-icon\");if(!e||!t)return;if(0===g.size)return e.classList.add(\"hidden\"),e.style.display=\"none\",t.style.color=\"var(--text-secondary)\",void(t.style.textShadow=\"none\");e.classList.remove(\"hidden\"),e.style.display=\"inline-flex\";let n=!1;for(const e of r)if(e.days){for(const t of e.days)if(t.items){for(const e of t.items)if(e.available&&g.has(e.id)){n=!0;break}if(n)break}if(n)break}let a=localStorage.getItem(\"kantine_last_updated\"),s=\"gerade eben\";a||(a=(new Date).toISOString(),localStorage.setItem(\"kantine_last_updated\",a));const o=new Date(a),i=Date.now()-o.getTime(),l=Math.floor(i/6e4);s=l<1?\"gerade eben\":l<60?`vor ${l} Min.`:`vor ${Math.floor(l/60)} Std.`,e.title=`Zuletzt gepr\u00fcft: ${s}`,n?(t.style.color=\"#10b981\",t.style.textShadow=\"0 0 10px rgba(16, 185, 129, 0.4)\"):(t.style.color=\"#f59e0b\",t.style.textShadow=\"0 0 10px rgba(245, 158, 11, 0.4)\")}function E(n,a,s,o){const i=`${n}_${a}`;let l=!1;g.has(i)?(g.delete(i),F(`Flag entfernt f\u00fcr ${s}`,\"success\")):(g.add(i),l=!0,F(`Benachrichtigung aktiviert f\u00fcr ${s}`,\"success\"),\"default\"===Notification.permission&&Notification.requestPermission()),k(),A(),z(),l&&async function(){if(0===g.size)return;const n=d||t,a=new Set;for(const e of g){const[t]=e.split(\"_\");a.add(t)}let s=!1;for(const t of a)try{const a=await fetch(`${e}/venues/591/menu/7/${t}/`,{headers:f(n)});if(!a.ok)continue;const o=(await a.json()).results||[];let i=[];for(const e of o)e.items&&Array.isArray(e.items)&&(i=i.concat(e.items));for(let e of r){if(!e.days)continue;let n=e.days.find(e=>e.date===t);n&&(n.items=i.map(e=>{const n=!1===e.amount_tracking,a=parseInt(e.available_amount)>0;return{id:`${t}_${e.id}`,articleId:e.id,name:e.name||\"Unknown\",description:e.description||\"\",price:parseFloat(e.price)||0,available:n||a,availableAmount:parseInt(e.available_amount)||0,amountTracking:!1!==e.amount_tracking}}),s=!0)}}catch(e){console.error(\"Error refreshing flag date\",t,e)}s&&(O(),q((new Date).toISOString()),A(),z())}()}function I(){h||d&&(h=setInterval(()=>async function(){if(0===g.size||!d)return;console.log(`Polling ${g.size} flagged items...`);for(const t of g){const[n,a]=t.split(\"_\"),s=parseInt(a);try{const t=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(d)});if(!t.ok)continue;const a=(await t.json()).results||[];let o=null;for(const e of a)if(e.items&&(o=e.items.find(e=>e.id===s||e.article===s),o))break;if(o){if(!1===o.amount_tracking||parseInt(o.available_amount)>0){const e=o.name||\"Unbekannt\";F(`${e} ist jetzt verf\u00fcgbar!`,\"success\"),\"granted\"===Notification.permission&&new Notification(\"Kantine Wrapper\",{body:`${e} ist jetzt verf\u00fcgbar!`,icon:\"\ud83c\udf7d\ufe0f\"}),M()}}}catch(e){console.error(`Poll error for ${t}:`,e),await new Promise(e=>setTimeout(e,200))}}}(),3e5),console.log(\"Polling started (every 5 min)\"))}let L=JSON.parse(localStorage.getItem(\"kantine_highlightTags\")||\"[]\");function S(){localStorage.setItem(\"kantine_highlightTags\",JSON.stringify(L)),z(),$()}function B(){const e=document.getElementById(\"tags-list\");e.innerHTML=\"\",L.forEach(t=>{const n=document.createElement(\"span\");n.className=\"tag-badge\",n.innerHTML=`${t} × `,e.appendChild(n)}),e.querySelectorAll(\".tag-remove\").forEach(e=>{e.addEventListener(\"click\",e=>{var t;t=e.target.dataset.tag,L=L.filter(e=>e!==t),S(),B()})})}function x(e){return e?(e=e.toLowerCase(),L.filter(t=>e.includes(t))):[]}const C=\"kantine_menuCache\",D=\"kantine_menuCacheTs\";function O(){try{localStorage.setItem(C,JSON.stringify(r)),localStorage.setItem(D,(new Date).toISOString())}catch(e){console.warn(\"Failed to cache menu data:\",e)}}async function M(){const n=document.getElementById(\"loading\"),a=document.getElementById(\"progress-modal\"),s=document.getElementById(\"progress-fill\"),o=document.getElementById(\"progress-percent\"),c=document.getElementById(\"progress-message\");n.classList.remove(\"hidden\");const m=d||t;try{a.classList.remove(\"hidden\"),c.textContent=\"Hole verf\u00fcgbare Daten...\",s.style.width=\"0%\",o.textContent=\"0%\";const t=await fetch(`${e}/venues/591/menu/dates/`,{headers:f(m)});if(!t.ok)throw new Error(`Failed to fetch dates: ${t.status}`);let n=(await t.json()).results||[];const d=new Date;d.setDate(d.getDate()-7);const u=d.toISOString().split(\"T\")[0];n=n.filter(e=>e.date>=u).sort((e,t)=>e.date.localeCompare(t.date)).slice(0,30);const g=n.length;c.textContent=`${g} Tage gefunden. Lade Details...`;const h=[];let p=0;for(const t of n){const n=t.date,a=Math.round((p+1)/g*100);s.style.width=`${a}%`,o.textContent=`${a}%`,c.textContent=`Lade Men\u00fc f\u00fcr ${n}...`;try{const a=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(m)});if(a.ok){const e=await a.json();0===p&&console.log(\"[Kantine Debug] Raw API response for\",n,\":\",JSON.stringify(e).substring(0,2e3));const s=e.results||[];let o=[];for(const e of s)e.items&&Array.isArray(e.items)&&(o=o.concat(e.items));o.length>0&&(0===p&&(console.log(\"[Kantine Debug] First item keys:\",Object.keys(o[0])),console.log(\"[Kantine Debug] First item:\",JSON.stringify(o[0]).substring(0,500))),h.push({date:n,menu_items:o,orders:t.orders||[]}))}}catch(e){console.error(`Failed to fetch details for ${n}:`,e)}p++,await new Promise(e=>setTimeout(e,100))}const y=new Map;r&&r.length>0&&r.forEach(e=>{const t=`${e.year}-${e.weekNumber}`;try{y.set(t,{year:e.year,weekNumber:e.weekNumber,days:e.days?e.days.map(e=>({...e,items:e.items?[...e.items]:[]})):[]})}catch(e){console.warn(\"Error hydrating week:\",e)}});for(const e of h){const t=new Date(e.date),n=U(t),a=G(t),s=`${a}-${n}`;y.has(s)||y.set(s,{year:a,weekNumber:n,days:[]});const o=y.get(s),r=t.toLocaleDateString(\"en-US\",{weekday:\"long\"}),i=new Date(e.date);i.setHours(10,0,0,0);const l={date:e.date,weekday:r,orderCutoff:i.toISOString(),items:e.menu_items.map(t=>{const n=!1===t.amount_tracking,a=parseInt(t.available_amount)>0;return{id:`${e.date}_${t.id}`,articleId:t.id,name:t.name||\"Unknown\",description:t.description||\"\",price:parseFloat(t.price)||0,available:n||a,availableAmount:parseInt(t.available_amount)||0,amountTracking:!1!==t.amount_tracking}})},c=o.days.findIndex(t=>t.date===e.date);c>=0?o.days[c]=l:o.days.push(l)}r=Array.from(y.values()).sort((e,t)=>e.year!==t.year?e.year-t.year:e.weekNumber-t.weekNumber),r.forEach(e=>{e.days&&e.days.sort((e,t)=>e.date.localeCompare(t.date))}),O(),q((new Date).toISOString()),i=U(new Date),l=(new Date).getFullYear(),v(),z(),$(),A(),c.textContent=\"Fertig!\",setTimeout(()=>a.classList.add(\"hidden\"),500)}catch(e){console.error(\"Error fetching menu:\",e),a.classList.add(\"hidden\"),showErrorModal(\"Keine Verbindung\",`Die Men\u00fcdaten konnten nicht geladen werden. M\u00f6glicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.${e.message} `,\"Zur Original-Seite\",\"https://web.bessa.app/knapp-kantine\")}finally{n.classList.add(\"hidden\")}}let N=null,T=null;function q(e){const t=document.getElementById(\"last-updated-subtitle\");if(e){N=e;try{const n=new Date(e),a=n.toLocaleTimeString(\"de-DE\",{hour:\"2-digit\",minute:\"2-digit\"}),s=n.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),o=function(e){const t=Date.now()-e.getTime(),n=Math.floor(t/6e4);if(n<1)return\"gerade eben\";if(1===n)return\"vor 1 min.\";if(n<60)return`vor ${n} min.`;const a=Math.floor(n/60);return 1===a?\"vor 1 Std.\":`vor ${a} Std.`}(n);t.textContent=`Aktualisiert: ${s} ${a} (${o})`}catch(e){t.textContent=\"\"}T||(T=setInterval(()=>{N&&q(N)},6e4))}}function F(e,t=\"info\"){let n=document.getElementById(\"toast-container\");n||(n=document.createElement(\"div\"),n.id=\"toast-container\",document.body.appendChild(n));const a=document.createElement(\"div\");a.className=`toast toast-${t}`;const s=\"success\"===t?\"check_circle\":\"error\"===t?\"error\":\"info\";a.innerHTML=`${s} ${e} `,n.appendChild(a),requestAnimationFrame(()=>a.classList.add(\"show\")),setTimeout(()=>{a.classList.remove(\"show\"),setTimeout(()=>a.remove(),300)},3e3)}function $(){const e=document.getElementById(\"btn-next-week\");let t=i+1,n=l;t>52&&(t=1,n++);const a=r.find(e=>e.weekNumber===t&&e.year===n);let s=0,o=0,c=0,d=0;a&&a.days&&a.days.forEach(e=>{if(e.items&&e.items.length>0){s++;const t=e.items.some(e=>e.available);t&&o++;let n=!1;e.items.forEach(t=>{const a=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${a}`;u.has(s)&&u.get(s).length>0&&(n=!0)}),n&&c++,t&&!n&&d++}});let m=e.querySelector(\".nav-badge\");if(s>0){m||(m=document.createElement(\"span\"),m.className=\"nav-badge\",e.appendChild(m)),m.title=`${c} bestellt / ${o} bestellbar / ${s} gesamt`,m.innerHTML=`${c} / ${o} / ${s} `,m.classList.remove(\"badge-violet\",\"badge-green\",\"badge-red\",\"badge-blue\"),c>0&&0===d?m.classList.add(\"badge-violet\"):d>0?m.classList.add(\"badge-green\"):0===o?m.classList.add(\"badge-red\"):m.classList.add(\"badge-blue\");let r=0;if(a&&a.days&&a.days.forEach(e=>{e.items.forEach(e=>{const t=x(e.name),n=x(e.description);(t.length>0||n.length>0)&&r++})}),r>0&&(m.innerHTML+=`(${r}) `,m.title+=` \u2022 ${r} Highlights gefunden`,m.classList.add(\"has-highlights\")),0===c){e.classList.add(\"new-week-available\");const a=`kantine_notified_nextweek_${n}_${t}`;localStorage.getItem(a)||(localStorage.setItem(a,\"true\"),F(\"Neue Men\u00fcdaten f\u00fcr n\u00e4chste Woche verf\u00fcgbar!\",\"info\"))}else e.classList.remove(\"new-week-available\")}else m&&m.remove()}function z(){const t=document.getElementById(\"menu-container\");if(!t)return;t.innerHTML=\"\";let a=i,s=l;\"next-week\"===c&&(a++,a>52&&(a=1,s++));const o=r.flatMap(e=>e.days||[]).filter(e=>{const t=new Date(e.date);return U(t)===a&&G(t)===s});if(0===o.length)return t.innerHTML=`\\n \\n
Keine Men\u00fcdaten f\u00fcr KW ${a} (${s}) verf\u00fcgbar.
\\n
Versuchen Sie eine andere Woche oder schauen Sie sp\u00e4ter vorbei. \\n
`,void document.getElementById(\"weekly-cost-display\").classList.add(\"hidden\");!function(e){let t=0;e&&e.length>0&&e.forEach(e=>{e.items&&e.items.forEach(n=>{const a=n.articleId||parseInt(n.id.split(\"_\")[1]),s=`${e.date}_${a}`,o=u.get(s)||[];o.length>0&&(t+=n.price*o.length)})});const n=document.getElementById(\"weekly-cost-display\");t>0?(n.innerHTML=`shopping_bag Gesamt: ${t.toFixed(2).replace(\".\",\",\")} \u20ac `,n.classList.remove(\"hidden\")):n.classList.add(\"hidden\")}(o);const m=document.getElementById(\"header-week-info\"),h=\"this-week\"===c?\"Diese Woche\":\"N\u00e4chste Woche\";m.innerHTML=`\\n \\n `;const v=document.createElement(\"div\");v.className=\"days-grid\",o.sort((e,t)=>e.date.localeCompare(t.date));o.filter(e=>{const t=new Date(e.date).getDay();return 0!==t&&6!==t}).forEach(t=>{const a=function(t){if(!t.items||0===t.items.length)return null;const a=document.createElement(\"div\");a.className=\"menu-card\";const s=new Date,o=new Date(t.date);let r=!1;if(t.orderCutoff)r=s>=new Date(t.orderCutoff);else{const e=new Date;e.setHours(0,0,0,0);const n=new Date(t.date);n.setHours(0,0,0,0),r=n{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`,s=(u.get(a)||[]).length;if(s>0){const t=e.name.match(/([M][1-9][Ff]?)/);if(t){let e=t[1];s>1&&(e+=\"+\"),i.push(e)}}});const l=document.createElement(\"div\");l.className=\"card-header\";const c=o.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),m=i.map(e=>``).join(\"\");let h=\"\";const v=t.items&&t.items.some(e=>{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`;return u.has(a)&&u.get(a).length>0}),w=t.items&&t.items.some(e=>e.available);h=v?\"header-violet\":w&&!r?\"header-green\":\"header-red\";h&&l.classList.add(h);l.innerHTML=`\\n \\n ${c} `,a.appendChild(l);var k;const A=document.createElement(\"div\");A.className=\"card-body\";const I=(new Date).toISOString().split(\"T\")[0],L=t.date===I,S=[...t.items].sort((e,n)=>{if(L){const a=e.articleId||parseInt(e.id.split(\"_\")[1]),s=n.articleId||parseInt(n.id.split(\"_\")[1]),o=u.has(`${t.date}_${a}`),r=u.has(`${t.date}_${s}`);if(o&&!r)return-1;if(!o&&r)return 1}return e.name.localeCompare(n.name)});return S.forEach(a=>{const o=document.createElement(\"div\");o.className=\"menu-item\";const i=a.articleId||parseInt(a.id.split(\"_\")[1]),l=`${t.date}_${i}`,c=(u.get(l)||[]).length;let m=\"\";m=a.available?a.amountTracking?`Verf\u00fcgbar (${a.availableAmount}) `:'Verf\u00fcgbar ':'Ausverkauft ';let h=\"\";if(c>0){h=`check_circle Bestellt${c>1?`${c} `:\"\"} `,o.classList.add(\"ordered\"),new Date(t.date).toDateString()===s.toDateString()&&o.classList.add(\"today-ordered\")}const v=`${t.date}_${i}`,w=g.has(v);w&&o.classList.add(a.available?\"flagged-available\":\"flagged-sold-out\");const k=[...new Set([...x(a.name),...x(a.description)])];k.length>0&&o.classList.add(\"highlight-glow\");let I=\"\",L=\"\",S=\"\";if(d&&!r){const e=w?\"notifications_active\":\"notifications_none\",n=w?\"btn-flag active\":\"btn-flag\",s=w?\"Benachrichtigung deaktivieren\":\"Benachrichtigen wenn verf\u00fcgbar\";if(a.available&&!w||(S=`${e} `),a.available&&(I=c>0?`add `:`add_shopping_cart Bestellen `),c>0){const e=1===c?\"close\":\"remove\",n=1===c?\"Bestellung stornieren\":\"Eine Bestellung stornieren\";L=`${e} `}}let B=\"\";if(k.length>0){B=`${k.map(e=>`star ${J(e)} `).join(\"\")}
`}o.innerHTML=`\\n \\n \\n ${h}\\n ${L}\\n ${I}\\n ${S}\\n
${m}
\\n
\\n ${B}\\n ${J(function(e){if(\"all\"===p)return e||\"\";const t=function(e){if(!e)return{de:\"\",en:\"\",raw:\"\"};let t=e.replace(/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?=\\S)/g,\"($1)\\n\u2022 \");t.startsWith(\"\u2022 \")||(t=\"\u2022 \"+t);function n(e){let t=0,n=0;return e.forEach(e=>{const a=e.toLowerCase().replace(/[^a-z\u00e4\u00f6\u00fc\u00df]/g,\"\");if(a){let s=0,o=0;W.includes(a)?s=a.length:W.forEach(e=>{a.includes(e)&&e.length>s&&(s=e.length)}),P.includes(a)?o=a.length:P.forEach(e=>{a.includes(e)&&e.length>o&&(o=e.length)}),s>0&&(t+=s/a.length),o>0&&(n+=o/a.length),/^[A-Z\u00c4\u00d6\u00dc]/.test(e)&&(t+=.5)}}),{de:t,en:n}}function a(e){const t=e.trim().split(/\\s+/);if(t.length<2)return{enPart:e,nextDe:\"\"};let a=-1,s=-9999;for(let e=1;el.en&&m>s&&(s=m,a=e)}return-1!==a?{enPart:t.slice(0,a).join(\" \"),nextDe:t.slice(a).join(\" \")}:{enPart:e,nextDe:\"\"}}const s=e.split(/\\s*\\/\\s*(?![A-Z,]+\\))/);if(s.length>4)return{de:t,en:\"\",raw:t};const o=[],r=[];o.push(s[0].trim());const i=/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*/;for(let e=1;e0&&(o[o.length-1]=o[o.length-1]+\"(\"+s+\")\"),i&&o.push(i)}else{const e=a(t);r.push(e.enPart),e.nextDe&&o.push(e.nextDe)}}1===s.length&&0===r.length&&r.push(o[0]);if(o.length>r.length)for(let e=r.length;e0&&!l.startsWith(\"\u2022 \")&&(l=\"\u2022 \"+l);let c=r.join(\"\\n\u2022 \");r.length>0&&!c.startsWith(\"\u2022 \")&&(c=\"\u2022 \"+c);return{de:l,en:c,raw:t}}(e);return\"en\"===p?t.en||t.raw:t.de||t.raw}(a.description))}
`;const C=o.querySelector(\".btn-order\");C&&C.addEventListener(\"click\",t=>{t.stopPropagation();const a=t.currentTarget;a.disabled=!0,a.classList.add(\"loading\"),async function(t,a,s,o,r){if(d)try{const i=await fetch(`${e}/auth/user/`,{headers:f(d)});if(!i.ok)return void F(\"Fehler: Benutzerdaten konnten nicht geladen werden\",\"error\");const l=await i.json(),c=(new Date).toISOString(),m={uuid:crypto.randomUUID(),created:c,updated:c,order_type:7,items:[{article:a,course_group:null,modifiers:[],uuid:crypto.randomUUID(),name:s,description:r||\"\",price:String(parseFloat(o)),amount:1,vat:\"10.00\",comment:\"\"}],table:null,total:parseFloat(o),tip:0,currency:\"EUR\",venue:n,states:[],order_state:1,date:`${t}T10:30:00Z`,payment_method:\"payroll\",customer:{first_name:l.first_name,last_name:l.last_name,email:l.email,newsletter:!1},preorder:!0,delivery_fee:0,cash_box_table_name:null,take_away:!1},u=await fetch(`${e}/user/orders/`,{method:\"POST\",headers:f(d),body:JSON.stringify(m)});if(u.ok||201===u.status)F(`Bestellt: ${s}`,\"success\"),b=null,await y();else{const e=await u.json();F(`Fehler: ${e.detail||e.non_field_errors?.[0]||\"Bestellung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Order error:\",e),F(\"Netzwerkfehler bei Bestellung\",\"error\")}}(a.dataset.date,parseInt(a.dataset.article),a.dataset.name,parseFloat(a.dataset.price),a.dataset.desc||\"\").finally(()=>{a.disabled=!1,a.classList.remove(\"loading\")})});const D=o.querySelector(\".btn-cancel\");D&&D.addEventListener(\"click\",t=>{t.stopPropagation();const n=t.currentTarget;n.disabled=!0,async function(t,n,a){if(!d)return;const s=`${t}_${n}`,o=u.get(s);if(!o||0===o.length)return;const r=o[o.length-1];try{const t=await fetch(`${e}/user/orders/${r}/cancel/`,{method:\"PATCH\",headers:f(d),body:JSON.stringify({})});t.ok?(F(`Storniert: ${a}`,\"success\"),b=null,await y()):F(`Fehler: ${(await t.json()).detail||\"Stornierung fehlgeschlagen\"}`,\"error\")}catch(e){console.error(\"Cancel error:\",e),F(\"Netzwerkfehler bei Stornierung\",\"error\")}}(n.dataset.date,parseInt(n.dataset.article),n.dataset.name).finally(()=>{n.disabled=!1})});const O=o.querySelector(\".btn-flag\");O&&O.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;E(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,t.dataset.cutoff)}),A.appendChild(o)}),a.appendChild(A),a}(t);a&&v.appendChild(a)}),t.appendChild(v),setTimeout(()=>function(e){const t=e.querySelectorAll(\".menu-card\");if(0===t.length)return;let n=0;t.forEach(e=>{n=Math.max(n,e.querySelectorAll(\".menu-item\").length)});for(let e=0;e{const s=t.querySelectorAll(\".menu-item\");s[e]&&(s[e].style.height=\"auto\",n=Math.max(n,s[e].offsetHeight),a.push(s[e]))}),a.forEach(e=>{e.style.height=`${n}px`})}}(v),0)}function j(e,t){if(!e||!t)return!1;const n=e.replace(/^v/,\"\").split(\".\").map(Number),a=t.replace(/^v/,\"\").split(\".\").map(Number);for(let e=0;e(a[e]||0))return!0;if((n[e]||0)<(a[e]||0))return!1}return!1}async function H(e){const t=e?`${s}/tags?per_page=20`:`${s}/releases?per_page=20`,n=await fetch(t,{headers:{Accept:\"application/vnd.github.v3+json\"}});if(!n.ok){if(403===n.status)throw new Error(\"API Rate Limit erreicht (403). Bitte sp\u00e4ter erneut versuchen.\");throw new Error(`GitHub API ${n.status}`)}return(await n.json()).map(t=>{const n=e?t.name:t.tag_name;return{tag:n,name:e?n:t.name||n,url:`${o}/${n}/dist/install.html`,body:t.body||\"\"}})}async function K(){const e=\"v1.6.8\",t=\"true\"===localStorage.getItem(\"kantine_dev_mode\");try{const n=await H(t);if(!n.length)return;localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:t,versions:n}));const a=n[0].tag;if(console.log(`[Kantine] Version Check: Local [${e}] vs Latest [${a}] (${t?\"dev\":\"stable\"})`),!j(a,e))return;console.log(`[Kantine] Update verf\u00fcgbar: ${a}`);const s=document.querySelector(\".header-left h1\");if(s&&!s.querySelector(\".update-icon\")){const e=document.createElement(\"a\");e.className=\"update-icon\",e.href=n[0].url,e.target=\"_blank\",e.innerHTML=\"\ud83c\udd95\",e.title=`Update: ${a} \u2014 Klick zum Installieren`,e.style.cssText=\"margin-left:8px;font-size:1em;text-decoration:none;cursor:pointer;vertical-align:middle;\",s.appendChild(e)}}catch(e){console.warn(\"[Kantine] Version check failed:\",e)}}function Q(){if(!d||!m)return void X();const e=new Date,t=e.getDay();if(0===t||6===t)return void X();const n=e.toISOString().split(\"T\")[0];let a=!1;for(const e of u.keys())if(e.startsWith(n)){a=!0;break}if(a)return void X();const s=new Date;s.setHours(10,0,0,0);const o=s-e;if(o<=0)return void X();const r=Math.floor(o/36e5),i=Math.floor(o%36e5/6e4),l=document.querySelector(\".header-center-wrapper\");if(!l)return;let c=document.getElementById(\"order-countdown\");if(c||(c=document.createElement(\"div\"),c.id=\"order-countdown\",l.insertBefore(c,l.firstChild)),c.innerHTML=`Bestellschluss: ${r}h ${i}m `,o<36e5){c.classList.add(\"urgent\");const e=`kantine_notified_${n}`;localStorage.getItem(e)||(\"granted\"===Notification.permission?new Notification(\"Kantine: Bestellschluss naht!\",{body:\"Du hast heute noch nichts bestellt. Nur noch 1 Stunde!\",icon:\"\u23f3\"}):\"default\"===Notification.permission&&Notification.requestPermission(),localStorage.setItem(e,\"true\"))}else c.classList.remove(\"urgent\")}function X(){const e=document.getElementById(\"order-countdown\");e&&e.remove()}function U(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate())),n=t.getUTCDay()||7;t.setUTCDate(t.getUTCDate()+4-n);const a=new Date(Date.UTC(t.getUTCFullYear(),0,1));return Math.ceil(((t-a)/864e5+1)/7)}function G(e){const t=new Date(e.getTime());return t.setDate(t.getDate()+3-(t.getDay()+6)%7),t.getFullYear()}function J(e){const t=document.createElement(\"div\");return t.textContent=e||\"\",t.innerHTML}setInterval(Q,6e4),setTimeout(Q,1e3);const W=[\"apfel\",\"aubergine\",\"auflauf\",\"beere\",\"blumenkohl\",\"bohne\",\"braten\",\"brokkoli\",\"brot\",\"brust\",\"br\u00f6tchen\",\"butter\",\"chili\",\"dessert\",\"dip\",\"eier\",\"eintopf\",\"eis\",\"erbse\",\"erdbeer\",\"essig\",\"filet\",\"fisch\",\"fisole\",\"fleckerl\",\"fleisch\",\"fl\u00fcgel\",\"frucht\",\"f\u00fcr\",\"gebraten\",\"gem\u00fcse\",\"gew\u00fcrz\",\"gratin\",\"grie\u00df\",\"gulasch\",\"gurke\",\"himbeer\",\"honig\",\"huhn\",\"h\u00e4hnchen\",\"jambalaya\",\"joghurt\",\"karotte\",\"kartoffel\",\"keule\",\"kirsch\",\"knacker\",\"knoblauch\",\"kn\u00f6del\",\"kompott\",\"kraut\",\"kr\u00e4uter\",\"kuchen\",\"k\u00e4se\",\"k\u00fcrbis\",\"lauch\",\"mandel\",\"milch\",\"mild\",\"mit\",\"mohn\",\"most\",\"m\u00f6hre\",\"natur\",\"nockerl\",\"nudel\",\"nuss\",\"nu\u00df\",\"obst\",\"oder\",\"olive\",\"paprika\",\"pfanne\",\"pfannkuchen\",\"pfeffer\",\"pikant\",\"pilz\",\"plunder\",\"p\u00fcree\",\"ragout\",\"rahm\",\"reis\",\"rind\",\"sahne\",\"salami\",\"salat\",\"salz\",\"sauer\",\"scharf\",\"schinken\",\"schnitte\",\"schnitzel\",\"schoko\",\"schupf\",\"schwein\",\"sellerie\",\"senf\",\"sosse\",\"so\u00dfe\",\"spargel\",\"sp\u00e4tzle\",\"speck\",\"spie\u00df\",\"spinat\",\"steak\",\"suppe\",\"s\u00fc\u00df\",\"tofu\",\"tomate\",\"topfen\",\"torte\",\"tr\u00fcffel\",\"und\",\"vanille\",\"vogerl\",\"vom\",\"wien\",\"wurst\",\"zucchini\",\"zum\",\"zur\",\"zwiebel\",\"\u00f6l\"],P=[\"almond\",\"and\",\"apple\",\"asparagus\",\"bacon\",\"baked\",\"ball\",\"bean\",\"beef\",\"berry\",\"bread\",\"breast\",\"broccoli\",\"bun\",\"butter\",\"cabbage\",\"cake\",\"caper\",\"carrot\",\"casserole\",\"cauliflower\",\"celery\",\"cheese\",\"cherry\",\"chicken\",\"chili\",\"choco\",\"chocolate\",\"cider\",\"cilantro\",\"coffee\",\"compote\",\"cream\",\"cucumber\",\"curd\",\"danish\",\"dessert\",\"dip\",\"dumpling\",\"egg\",\"eggplant\",\"filet\",\"fish\",\"for\",\"fried\",\"from\",\"fruit\",\"garlic\",\"goulash\",\"gratin\",\"ham\",\"herb\",\"honey\",\"hot\",\"ice\",\"jambalaya\",\"leek\",\"leg\",\"mash\",\"meat\",\"mexican\",\"mild\",\"milk\",\"mint\",\"mushroom\",\"mustard\",\"noodle\",\"nut\",\"oat\",\"oil\",\"olive\",\"onion\",\"or\",\"oven\",\"pan\",\"pancake\",\"pea\",\"pepper\",\"plain\",\"plate\",\"poppy\",\"pork\",\"potato\",\"pumpkin\",\"radish\",\"ragout\",\"raspberry\",\"rice\",\"roast\",\"roll\",\"salad\",\"salami\",\"salt\",\"sauce\",\"sausage\",\"shrimp\",\"skewer\",\"slice\",\"soup\",\"sour\",\"spice\",\"spicy\",\"spinach\",\"steak\",\"stew\",\"strawberr\",\"strawberry\",\"strudel\",\"sweet\",\"tart\",\"thyme\",\"to\",\"tofu\",\"tomat\",\"tomato\",\"truffle\",\"trukey\",\"turkey\",\"vanilla\",\"vegan\",\"vegetable\",\"vinegar\",\"wedge\",\"wing\",\"with\",\"wok\",\"yogurt\",\"zucchini\"];!function(){document.title=\"Kantine Weekly Menu\",document.querySelectorAll&&document.querySelectorAll('link[rel*=\"icon\"]').forEach(e=>e.remove());const e=document.createElement(\"link\");if(e.rel=\"icon\",e.type=\"image/png\",e.href=\"data:image/png;base64,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\",document.head.appendChild(e),!document.querySelector('link[href*=\"fonts.googleapis.com/css2?family=Inter\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\",document.head.appendChild(e)}if(!document.querySelector('link[href*=\"Material+Icons+Round\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/icon?family=Material+Icons+Round\",document.head.appendChild(e)}document.body.innerHTML=`\\n \\n \\n\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Initialisierung...
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Markiere Men\u00fcs automatisch, wenn sie diese Schlagw\u00f6rter enthalten.\\n
\\n
\\n \\n Hinzuf\u00fcgen \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Lade Historie...
\\n
\\n
\\n
\\n \\x3c!-- Dynamically populated --\\x3e\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Aktuell: v1.6.8 \\n
\\n
\\n \\n \\n Dev-Mode (alle Tags anzeigen) \\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n \\n update \\n Gerade aktualisiert \\n
\\n \\n
\\n
Lade Men\u00fcdaten...
\\n
\\n \\n \\n\\n \\n
`}(),function(){const n=document.getElementById(\"btn-this-week\"),a=document.getElementById(\"btn-next-week\"),s=document.getElementById(\"btn-refresh\"),o=document.getElementById(\"theme-toggle\"),r=document.getElementById(\"btn-login-open\"),i=document.getElementById(\"btn-login-close\"),l=document.getElementById(\"btn-logout\"),g=document.getElementById(\"login-form\"),k=document.getElementById(\"login-modal\"),A=document.getElementById(\"btn-highlights\"),E=document.getElementById(\"highlights-modal\"),x=document.getElementById(\"btn-highlights-close\"),C=document.getElementById(\"btn-add-tag\"),D=document.getElementById(\"tag-input\"),O=document.getElementById(\"btn-history\"),N=document.getElementById(\"history-modal\"),T=document.getElementById(\"btn-history-close\");document.querySelectorAll(\".lang-btn\").forEach(e=>{e.addEventListener(\"click\",()=>{p=e.dataset.lang,localStorage.setItem(\"kantine_lang\",p),document.querySelectorAll(\".lang-btn\").forEach(e=>e.classList.remove(\"active\")),e.classList.add(\"active\"),z()})}),A&&A.addEventListener(\"click\",()=>{E.classList.remove(\"hidden\")}),x&&x.addEventListener(\"click\",()=>{E.classList.add(\"hidden\")}),O.addEventListener(\"click\",()=>{d?(N.classList.remove(\"hidden\"),async function(){const t=document.getElementById(\"history-loading\"),n=document.getElementById(\"history-content\"),a=document.getElementById(\"history-progress-fill\"),s=document.getElementById(\"history-progress-text\");let o=[];if(b)o=b;else{const e=localStorage.getItem(\"kantine_history_cache\");if(e)try{o=JSON.parse(e),b=o}catch(e){console.warn(\"History cache parse error\",e)}}o.length>0&&w(o);if(!d)return;0===o.length&&(n.innerHTML=\"\",t.classList.remove(\"hidden\"));a.style.width=\"0%\",s.textContent=o.length>0?\"Suche nach neuen Bestellungen...\":\"Lade Bestellhistorie...\",o.length>0&&t.classList.remove(\"hidden\");let r=o.length>0?`${e}/user/orders/?venue=591&ordering=-created&limit=5`:`${e}/user/orders/?venue=591&ordering=-created&limit=50`,i=[],l=0,c=0===o.length,m=!1;try{for(;r&&!m;){const e=await fetch(r,{headers:f(d)});if(!e.ok)throw new Error(`Fetch failed: ${e.status}`);const t=await e.json();t.count&&0===l&&(l=t.count);const n=t.results||[];for(const e of n){const t=o.findIndex(t=>t.id===e.id);if(!c&&-1!==t){const n=o[t];if(n.updated===e.updated&&n.order_state===e.order_state){m=!0;break}}i.push(e)}if(!m&&c)if(l>0){const e=Math.round(i.length/l*100);a.style.width=`${e}%`,s.textContent=`Lade Bestellung ${i.length} von ${l}...`}else s.textContent=`Lade Bestellung ${i.length}...`;else m||(s.textContent=`${i.length} neue/ge\u00e4nderte Bestellungen gefunden...`);r=m?null:t.next}if(i.length>0){const e=new Map(o.map(e=>[e.id,e]));for(const t of i)e.set(t.id,t);const t=Array.from(e.values());t.sort((e,t)=>new Date(t.created)-new Date(e.created)),b=t;try{localStorage.setItem(\"kantine_history_cache\",JSON.stringify(t))}catch(e){console.warn(\"History cache write error\",e)}w(b)}}catch(e){console.error(\"Error in history sync:\",e),0===o.length?n.innerHTML='Fehler beim Laden der Historie.
':F(\"Hintergrund-Synchronisation fehlgeschlagen\",\"error\")}finally{t.classList.add(\"hidden\")}}()):k.classList.remove(\"hidden\")}),T.addEventListener(\"click\",()=>{N.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===N&&N.classList.add(\"hidden\"),e.target===E&&E.classList.add(\"hidden\")});const q=document.querySelector(\".version-tag\"),$=document.getElementById(\"version-modal\"),K=document.getElementById(\"btn-version-close\");q&&q.addEventListener(\"click\",e=>{e.preventDefault(),e.stopPropagation(),function(){const e=document.getElementById(\"version-modal\"),t=document.getElementById(\"version-list-container\"),n=document.getElementById(\"dev-mode-toggle\"),a=\"v1.6.8\";if(!e)return;e.classList.remove(\"hidden\");const s=document.getElementById(\"version-current\");s&&(s.textContent=a);const o=\"true\"===localStorage.getItem(\"kantine_dev_mode\");async function r(e){const s=n.checked;function o(e){if(!e||!e.length)return void(t.innerHTML='Keine Versionen gefunden.
');t.innerHTML='';const n=t.querySelector(\".version-list\");e.forEach(e=>{const t=e.tag===a,s=j(e.tag,a),o=document.createElement(\"li\");o.className=\"version-item\"+(t?\" current\":\"\");let r=\"\";t?r='\u2713 Installiert ':s&&(r='\u2b06 Neu! ');let i=\"\";t||(i=`Installieren `),o.innerHTML=`\\n \\n ${e.tag} \\n ${r}\\n
\\n ${i}\\n `,n.appendChild(o)})}t.innerHTML='Lade Versionen...
';try{const e=localStorage.getItem(\"kantine_version_cache\");let t=null;if(e)try{t=JSON.parse(e)}catch(e){}t&&t.devMode===s&&t.versions&&o(t.versions);const n=await H(s),a=JSON.stringify(n);a!==(t?JSON.stringify(t.versions):\"\")&&(localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:s,versions:n})),o(n))}catch(e){t.innerHTML=`Fehler: ${e.message}
`}}n.checked=o,r(!1),n.onchange=()=>{localStorage.setItem(\"kantine_dev_mode\",n.checked),localStorage.removeItem(\"kantine_version_cache\"),r(!0)}}()}),K&&K.addEventListener(\"click\",()=>{$.classList.add(\"hidden\")});const Q=document.getElementById(\"btn-clear-cache\");Q&&Q.addEventListener(\"click\",()=>{confirm(\"M\u00f6chtest du wirklich alle lokalen Daten (inkl. Login-Session, Cache und Einstellungen) l\u00f6schen? Die Seite wird danach neu geladen.\")&&(Object.keys(localStorage).forEach(e=>{e.startsWith(\"kantine_\")&&localStorage.removeItem(e)}),window.location.reload())}),window.addEventListener(\"click\",e=>{e.target===$&&$.classList.add(\"hidden\")}),C.addEventListener(\"click\",()=>{(function(e){if(e=e.trim().toLowerCase(),e&&!L.includes(e))return L.push(e),S(),!0;return!1})(D.value)&&(D.value=\"\",B())}),D.addEventListener(\"keypress\",e=>{\"Enter\"===e.key&&C.click()});const X=localStorage.getItem(\"theme\"),U=window.matchMedia(\"(prefers-color-scheme: dark)\").matches,G=o.querySelector(\".theme-icon\");\"dark\"===X||!X&&U?(document.documentElement.setAttribute(\"data-theme\",\"dark\"),G.textContent=\"dark_mode\"):(document.documentElement.setAttribute(\"data-theme\",\"light\"),G.textContent=\"light_mode\"),o.addEventListener(\"click\",()=>{const e=\"dark\"===document.documentElement.getAttribute(\"data-theme\")?\"light\":\"dark\";document.documentElement.setAttribute(\"data-theme\",e),localStorage.setItem(\"theme\",e),G.textContent=\"dark\"===e?\"dark_mode\":\"light_mode\"}),n.addEventListener(\"click\",()=>{\"this-week\"!==c&&(c=\"this-week\",n.classList.add(\"active\"),a.classList.remove(\"active\"),z())}),a.addEventListener(\"click\",()=>{a.classList.remove(\"new-week-available\"),\"next-week\"!==c&&(c=\"next-week\",a.classList.add(\"active\"),n.classList.remove(\"active\"),z())}),s.addEventListener(\"click\",()=>{d?M():k.classList.remove(\"hidden\")}),r.addEventListener(\"click\",()=>{k.classList.remove(\"hidden\"),document.getElementById(\"login-error\").classList.add(\"hidden\"),g.reset()}),i.addEventListener(\"click\",()=>{k.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===k&&k.classList.add(\"hidden\")}),g.addEventListener(\"submit\",async n=>{n.preventDefault();const a=document.getElementById(\"employee-id\").value.trim(),s=document.getElementById(\"password\").value,o=document.getElementById(\"login-error\"),r=g.querySelector('button[type=\"submit\"]'),i=r.textContent;r.disabled=!0,r.textContent=\"Wird eingeloggt...\";try{const n=`knapp-${a}@bessa.app`,r=await fetch(`${e}/auth/login/`,{method:\"POST\",headers:f(t),body:JSON.stringify({email:n,password:s})}),i=await r.json();if(r.ok){d=i.key,m=a,localStorage.setItem(\"kantine_authToken\",i.key),localStorage.setItem(\"kantine_currentUser\",a);try{const t=await fetch(`${e}/auth/user/`,{headers:f(d)});if(t.ok){const e=await t.json();e.first_name&&localStorage.setItem(\"kantine_firstName\",e.first_name),e.last_name&&localStorage.setItem(\"kantine_lastName\",e.last_name)}}catch(e){console.error(\"Failed to fetch user info:\",e)}v(),k.classList.add(\"hidden\"),y(),g.reset(),I(),M()}else o.textContent=i.non_field_errors?.[0]||i.error||\"Login fehlgeschlagen\",o.classList.remove(\"hidden\")}catch(e){console.error(\"Login error:\",e),o.textContent=\"Ein Fehler ist aufgetreten\",o.classList.remove(\"hidden\")}finally{r.disabled=!1,r.textContent=i}}),l.addEventListener(\"click\",()=>{localStorage.removeItem(\"kantine_authToken\"),localStorage.removeItem(\"kantine_currentUser\"),localStorage.removeItem(\"kantine_firstName\"),localStorage.removeItem(\"kantine_lastName\"),d=null,m=null,u=new Map,h&&(clearInterval(h),h=null,console.log(\"Polling stopped\")),v(),z()})}(),v(),function(){const e=new Date,t=e.toISOString().split(\"T\")[0];let n=!1;for(const a of[...g]){const[s]=a.split(\"_\");let o=!1;if(s=t&&(o=!0)}o&&(g.delete(a),n=!0)}n&&k()}();(function(){try{const e=localStorage.getItem(C),t=localStorage.getItem(D);if(console.log(`[Cache] localStorage: key=${!!e} (${e?e.length:0} chars), ts=${t}`),e){r=JSON.parse(e),i=U(new Date),l=(new Date).getFullYear(),console.log(`[Cache] Parsed ${r.length} weeks:`,r.map(e=>`KW${e.weekNumber}/${e.year} (${(e.days||[]).length} days)`)),z(),$(),A(),t&&q(t);try{const e=new Set;r.forEach(t=>{(t.days||[]).forEach(t=>{(t.items||[]).forEach(t=>{let n=(t.description||\"\").replace(/\\s+/g,\" \").trim();n&&n.includes(\" / \")&&e.add(n)})})});const t=Array.from(e).join(\"\\n\\n\");console.log(\"=== GEFUNDENE MEN\u00dc-TEXTE (\"+e.size+\") ===\"),console.log(t)}catch(e){}return console.log(\"Loaded menu from cache\"),!0}}catch(e){console.warn(\"Failed to load cached menu:\",e)}return!1})()?(document.getElementById(\"loading\").classList.add(\"hidden\"),!function(){const e=localStorage.getItem(D);if(!e)return console.log(\"[Cache] No timestamp found\"),!1;const t=Date.now()-new Date(e).getTime(),n=Math.round(t/6e4);if(t>36e5)return console.log(`[Cache] Stale: ${n}min old (max 60)`),!1;const a=U(new Date),s=G(new Date),o=r.some(e=>e.weekNumber===a&&e.year===s&&e.days&&e.days.length>0);return console.log(`[Cache] Age: ${n}min, looking for KW${a}/${s}, found: ${o}`),o}()?(console.log(\"Cache stale or incomplete \u2013 refreshing from API\"),M()):console.log(\"Cache fresh & complete \u2013 skipping API refresh\")):M(),d&&I(),K(),setInterval(K,36e5),console.log(\"Kantine Wrapper loaded \u2705\")}();\n";
document.head.appendChild(sc);
})();
diff --git a/dist/bookmarklet.txt b/dist/bookmarklet.txt
index 0be2e6e..dba9d67 100755
--- a/dist/bookmarklet.txt
+++ b/dist/bookmarklet.txt
@@ -1 +1 @@
-javascript:javascript:(function(){ if(window.__KANTINE_LOADED){alert('Kantine Wrapper already loaded!');return;} var s=document.createElement('style');s.textContent=':root { /* Premium Slate/Gray-Blue Palette - Light Mode */ --bg-body: #f1f5f9; /* Slate 100 */ --bg-card: #ffffff; --text-primary: #334155; /* Slate 700 */ --text-secondary: #64748b; --accent-color: #0f172a; /* Slate 900 (High contrast) */ --border-color: #cbd5e1; /* Slate 300 */ --banner-bg: #e2e8f0; --banner-text: #1e293b; --success-color: #059669; --error-color: #dc2626; --card-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05); --header-bg: rgba(255, 255, 255, 0.9); --header-border: 1px solid rgba(203, 213, 225, 0.6); } [data-theme="dark"] { /* Premium Slate/Gray-Blue Palette - Dark Mode */ --bg-body: #1e293b; /* Deep Slate Gray (Requested) */ --bg-card: #334155; /* Slate 700 */ --text-primary: #f8fafc; /* Slate 50 */ --text-secondary: #cbd5e1; /* Slate 300 */ --accent-color: #60a5fa; /* Blue 400 */ --border-color: #475569; /* Slate 600 */ --banner-bg: #475569; --banner-text: #e2e8f0; --header-bg: rgba(30, 41, 59, 0.9); --header-border: 1px solid rgba(71, 85, 105, 0.6); --card-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.4); } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: \'Inter\', system-ui, -apple-system, sans-serif; background-color: var(--bg-body); color: var(--text-primary); transition: background-color 0.3s ease, color 0.3s ease; line-height: 1.5; -webkit-font-smoothing: antialiased; } /* Fix scrolling bug: Reset html/body styles from host page */ /* IMPORTANT: html must NOT have overflow set, or it creates a scroll container that breaks position: sticky */ html { height: auto !important; min-height: 100% !important; overflow: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } body { height: auto !important; min-height: 100% !important; overflow-x: clip !important; /* clip prevents horizontal overflow without breaking sticky */ overflow-y: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } /* Header */ .app-header { flex-shrink: 0; z-index: 100; backdrop-filter: blur(12px); background-color: var(--header-bg); border-bottom: var(--header-border); padding: 1rem 0; } .header-content { width: 100%; /* Full width */ padding: 0 2rem; /* Comfortable padding */ display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem; } .brand { display: flex; align-items: center; gap: 0.75rem; } .brand-text { display: flex; flex-direction: column; } .brand h1 { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.025em; margin-bottom: 0; } .subtitle { font-size: 0.85rem; color: var(--text-secondary); font-weight: 400; margin-left: 2px; } .logo-icon { font-size: 1.5rem; color: var(--accent-color); } /* Controls */ .controls { display: flex; align-items: center; gap: 1.5rem; justify-self: end; } /* Header Week Info (centered) */ .header-week-info { text-align: center; line-height: 1.3; } .header-center-wrapper { display: flex; flex-direction: row; align-items: center; gap: 1.5rem; justify-content: center; } .header-week-title { font-size: 1.1rem; font-weight: 600; color: var(--text-primary); } .header-week-subtitle { font-size: 0.85rem; color: var(--text-secondary); } /* Language Toggle (FR-100) */ .lang-toggle { display: inline-flex; gap: 0; border-radius: 6px; overflow: hidden; border: 1px solid var(--border-color); background: var(--bg-card); } .lang-btn { padding: 3px 10px; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.03em; background: transparent; color: var(--text-secondary); border: none; cursor: pointer; transition: all 0.2s; } .lang-btn:hover { color: var(--text-primary); background: rgba(100, 116, 139, 0.1); } .lang-btn.active { background: var(--accent-color); color: white; } .nav-group { display: flex; background-color: var(--bg-card); border: 1px solid var(--border-color); padding: 0.25rem; border-radius: 8px; } .nav-btn { background: none; border: none; padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500; color: var(--text-secondary); cursor: pointer; border-radius: 6px; transition: all 0.2s; display: flex; align-items: center; gap: 0.5rem; } .nav-btn:hover { color: var(--text-primary); background-color: rgba(100, 116, 139, 0.1); } .nav-btn.active { background-color: var(--accent-color); color: white; } /* Notification state for Next Week */ .nav-btn.new-week-available { animation: goldPulse 2s infinite; border-color: #f59e0b; color: var(--accent-color); } .nav-btn.new-week-available.active { color: white; } @keyframes goldPulse { 0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0); } 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); } } /* Badge for nav buttons (day count indicator) */ .nav-badge { background-color: var(--error-color); color: white; font-size: 0.75rem; font-weight: 600; padding: 0 6px; border-radius: 10px; min-width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; gap: 3px; line-height: 1; } .nav-badge .orderable { color: #fff; font-weight: 800; } .nav-badge .separator { opacity: 0.6; font-weight: 400; } .nav-badge .total { opacity: 0.8; font-weight: 400; } .nav-btn.active .nav-badge { background: rgba(255, 255, 255, 0.3); } /* Primary style for Login Button to match header */ #btn-login-open { background-color: var(--accent-color); color: white; padding: 0.5rem 1.25rem; border-radius: 8px; font-weight: 600; letter-spacing: 0.025em; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } #btn-login-open:hover { background-color: #334155; /* Slightly lighter than slate-900 */ transform: translateY(-1px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } /* User Badge Button (Login) */ .user-badge-btn { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 20px; font-size: 0.9rem; font-weight: 500; color: var(--text-primary); cursor: pointer; transition: all 0.2s; } .user-badge-btn:hover { background: rgba(100, 116, 139, 0.1); border-color: var(--accent-color); } .user-badge-btn .material-icons-round { font-size: 1.25rem; color: var(--accent-color); } .icon-btn { background: none; border: none; color: var(--text-primary); cursor: pointer; padding: 0.5rem; border-radius: 50%; transition: background-color 0.2s; display: flex; align-items: center; justify-content: center; } .icon-btn:hover { background-color: rgba(100, 116, 139, 0.1); } /* Refresh button animation */ #btn-refresh.refreshing .material-icons-round { animation: rotate 1s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* Progress Modal */ .progress-container { margin-bottom: 1.5rem; } .progress-bar { width: 100%; height: 8px; background-color: var(--border-color); border-radius: 4px; overflow: hidden; margin-bottom: 0.75rem; } .progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent-color) 0%, #60a5fa 100%); width: 0%; transition: width 0.3s ease; border-radius: 4px; } .progress-percent { text-align: center; font-size: 1.5rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; } .progress-message { text-align: center; color: var(--text-secondary); font-size: 0.9rem; font-weight: 500; } .weekly-cost { background-color: rgba(59, 130, 246, 0.1); /* Blue tint */ color: var(--accent-color); padding: 0.4rem 0.8rem; border-radius: 8px; font-weight: 600; font-size: 0.9rem; display: flex; align-items: center; gap: 0.5rem; border: 1px solid rgba(59, 130, 246, 0.2); } .weekly-cost .material-icons-round { font-size: 18px; } /* Container - flex column, full width so child scrollbar is at edge */ .container { flex: 1; width: 100%; overflow: hidden; padding: 0 0 0 0; /* Only top padding, no horizontal so child fills width */ display: flex; flex-direction: column; } /* Add horizontal padding to direct children of container to maintain layout */ .container>*:not(.menu-grid) { padding-left: 2rem; padding-right: 2rem; } /* Banner */ .banner { background-color: var(--banner-bg); color: var(--banner-text); padding: 0.75rem 1rem; border-radius: 8px; display: flex; align-items: center; gap: 0.5rem; margin-bottom: 2rem; font-size: 0.875rem; font-weight: 500; border: 1px solid var(--border-color); max-width: fit-content; } /* User Badge */ .user-badge { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); /* Changed from --surface */ border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 20px; font-size: 0.9rem; font-weight: 500; } .icon-btn-small { background: none; border: none; padding: 4px; cursor: pointer; color: var(--text-secondary); /* Changed from --text-muted */ display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s; } .icon-btn-small:hover { color: var(--error-color); /* Changed from --danger */ background: rgba(239, 68, 68, 0.1); } /* Modal */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; transition: all 0.3s; } .modal.hidden { opacity: 0; pointer-events: none; } .modal-content { background: var(--bg-card); width: 90%; max-width: 400px; border-radius: 16px; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); overflow: hidden; animation: modalSlide 0.3s ease-out; } /* History Modal specific */ .history-modal-content { max-width: 600px; max-height: 85vh; display: flex; flex-direction: column; } .history-modal-content .modal-body { overflow-y: auto; padding: 0; /* Padding is handled by inner elements */ } /* History Styles */ .history-year-group { margin-bottom: 16px; } .history-year-header { background: var(--bg-card); padding: 12px 20px; margin: 0; font-size: 1.2rem; font-weight: 700; color: var(--text-primary); border-bottom: 2px solid var(--border-color); position: sticky; top: 0; z-index: 12; } .history-month-group { border-bottom: 1px solid var(--border-color); } .history-month-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; margin: 0; font-size: 1.05rem; font-weight: 600; color: var(--text-primary); background: var(--bg-body); cursor: pointer; transition: background 0.2s; } .history-month-header:hover { background: var(--border-color); /* Slight hover effect */ } .history-month-summary { display: flex; align-items: center; gap: 12px; font-size: 0.95rem; color: var(--text-secondary); } .history-month-content { display: none; /* Collapsed by default */ background: var(--bg-card); } .history-month-group.open .history-month-content { display: block; /* Expanded when open class is present */ } .history-month-group.open .history-month-header .material-icons-round { transform: rotate(180deg); } .history-month-header .material-icons-round { transition: transform 0.3s; font-size: 20px; } .history-week-group { padding: 12px 20px; border-bottom: 1px dashed var(--border-color); } .history-week-group:last-child { border-bottom: none; } .history-week-header { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; font-weight: 600; color: var(--text-secondary); margin-bottom: 10px; } .history-week-summary { font-size: 0.85rem; font-weight: 500; background: rgba(100, 116, 139, 0.1); padding: 4px 10px; border-radius: 12px; } .history-items { display: flex; flex-direction: column; gap: 8px; } .history-item { display: grid; grid-template-columns: 50px 1fr auto; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-body); border-radius: 8px; border: 1px solid var(--border-color); } .history-item-date { font-size: 0.85rem; color: var(--text-secondary); font-weight: 500; } .history-item-details { display: flex; flex-direction: column; gap: 4px; } .history-item-name { font-size: 0.95rem; font-weight: 500; color: var(--text-primary); } .history-item-price { font-weight: 600; color: var(--text-primary); } .history-item-status { font-size: 0.8rem; font-weight: 600; color: var(--text-primary); text-transform: uppercase; letter-spacing: 0.5px; } .history-item-cancelled { opacity: 0.5; filter: grayscale(1); } .history-item-price-cancelled { text-decoration: line-through; color: var(--text-secondary); } @keyframes modalSlide { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px; border-bottom: 1px solid var(--border-color); } .modal-header h2 { margin: 0; font-size: 1.25rem; } .modal-body { padding: 20px; } #login-form { padding: 20px; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 6px; font-weight: 500; font-size: 0.9rem; } .form-group input { width: 100%; padding: 10px 12px; border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 8px; background: var(--bg-body); /* Changed from --bg */ color: var(--text-primary); /* Changed from --text */ font-family: inherit; transition: border-color 0.2s; } .form-group input:focus { outline: none; border-color: var(--accent-color); /* Changed from --primary */ } .help-text { display: block; margin-top: 4px; color: var(--text-secondary); /* Changed from --text-muted */ font-size: 0.75rem; } .error-msg { margin-bottom: 16px; padding: 10px; background: rgba(239, 68, 68, 0.1); color: var(--error-color); /* Changed from --danger */ border-radius: 8px; font-size: 0.85rem; text-align: center; } .modal-actions { margin-top: 24px; } .btn-primary.wide { width: 100%; justify-content: center; } .hidden { display: none !important; } /* Menu Grid Container */ .menu-grid { display: flex; flex-direction: column; flex: 1; overflow: hidden; gap: 1rem; } .week-section { margin-bottom: 2rem; } .week-header { margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); padding-bottom: 1rem; text-align: center; } .week-title { font-size: 1.75rem; font-weight: 700; color: var(--text-primary); } .week-range { color: var(--text-secondary); font-size: 0.9rem; margin-top: 0.25rem; } /* Full-viewport layout: header + scrollable content + footer */ #kantine-wrapper { display: flex; flex-direction: column; height: 100vh; height: 100dvh; /* Dynamic viewport height for mobile browsers */ overflow: hidden; } .days-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.75rem; flex: 1; overflow-y: auto; /* This is the scroll container at the window edge */ align-content: start; padding: 0 2rem 2rem 2rem; } /* Card */ .menu-card { background-color: var(--bg-card); border-radius: 12px; border: 1px solid var(--border-color); box-shadow: var(--card-shadow); overflow: clip; /* Clips scrolling content behind sticky header */ transition: box-shadow 0.2s ease; display: flex; flex-direction: column; } /* Past Day Styling - Target specific elements so ordered items can remain visible AND preserve sticky context */ /* We MUST apply filter/opacity to children, not the parent .menu-card, or else position: sticky breaks */ /* Header keeps fully opaque background to hide scrolling items, only grayscales */ .menu-card.past-day .card-header { filter: grayscale(0.8); transition: filter 0.3s; } /* Items become semi-transparent */ .menu-card.past-day .menu-item:not(.ordered) { opacity: 0.6; filter: grayscale(0.8); transition: opacity 0.3s, filter 0.3s; } .menu-card.past-day:hover .card-header { filter: grayscale(0.4); } .menu-card.past-day:hover .menu-item:not(.ordered) { opacity: 0.8; filter: grayscale(0.4); } /* Past ordered items get no special frame or shadow, but remain visually distinct by staying fully opaque (via the :not(.ordered) selector above) */ .menu-item.today-ordered { border: 2px solid #8b5cf6; box-shadow: 0 0 30px rgba(139, 92, 246, 0.6); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: pulse-glow-strong 3s infinite; } @keyframes pulse-glow-strong { 0% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } 50% { box-shadow: 0 0 40px rgba(139, 92, 246, 0.8); } 100% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } } .menu-card:hover { box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); } .card-header { padding: 1rem 1.25rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: baseline; background-color: var(--bg-card); /* Removed border-radius: 12px 12px 0 0; .menu-card\'s overflow: clip will round the corners initially. When sticky at the top, it will be square and perfectly hide scrolling content! */ /* Sticky within .container scroll area */ position: sticky; top: 0; z-index: 90; } .card-body { padding: 1.25rem; display: grid; grid-template-rows: auto; align-content: start; } .day-name { font-size: 1.125rem; font-weight: 600; } .day-date { font-size: 0.875rem; color: var(--text-secondary); } .empty-state { color: var(--text-secondary); font-style: italic; text-align: center; padding: 1rem; } /* Menu Items */ .menu-item { margin-bottom: 1.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); } .menu-item:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .item-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; gap: 1rem; } .item-name { font-weight: 600; color: var(--text-primary); font-size: 1rem; } .item-price { font-weight: 700; color: var(--accent-color); white-space: nowrap; } .item-desc { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.6; margin-bottom: 0.75rem; white-space: pre-wrap; } .badges { display: flex; gap: 0.5rem; margin-left: auto; } .item-status-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; } .badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; } .badge.available { background-color: rgba(16, 185, 129, 0.1); /* Emerald 500 / 10% */ color: var(--success-color); border: 1px solid rgba(16, 185, 129, 0.2); } .badge.sold-out { background-color: rgba(239, 68, 68, 0.1); /* Red 500 / 10% */ color: var(--error-color); border: 1px solid rgba(239, 68, 68, 0.2); } .badge.ordered { background-color: rgba(139, 92, 246, 0.1); /* Violet 500 / 10% */ color: #8b5cf6; border: 1px solid rgba(139, 92, 246, 0.2); gap: 4px; } .badge.ordered .material-icons-round { font-size: 1rem; } /* Loading */ .loading-state { text-align: center; padding: 4rem; color: var(--text-secondary); } .spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--accent-color); border-radius: 50%; margin: 0 auto 1rem; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Footer */ .app-footer { flex-shrink: 0; text-align: center; padding: 0.4rem 2rem; color: var(--text-secondary); font-size: 0.8rem; border-top: 1px solid var(--border-color); } /* === Order / Cancel Buttons (inline in status row) === */ .btn-order { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border: none; border-radius: 6px; background: var(--success-color); color: white; font-size: 0.75rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-order .material-icons-round { font-size: 16px; } .btn-order:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-order:disabled { opacity: 0.5; cursor: not-allowed; } .btn-order.loading { pointer-events: none; opacity: 0.6; } .btn-order-compact { padding: 2px 4px; gap: 0; } .btn-order-compact .material-icons-round { font-size: 16px; } .btn-cancel { display: inline-flex; align-items: center; justify-content: center; padding: 4px 6px; border: none; border-radius: 6px; background: var(--error-color); color: white; font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-cancel .material-icons-round { font-size: 16px; } .btn-cancel:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-cancel:disabled { opacity: 0.5; cursor: not-allowed; } /* Past days: hide action buttons */ .past-day .item-actions { display: none; } /* Order count badge (for multi-orders) */ .order-count-badge { display: inline-flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.3); color: white; font-size: 0.65rem; font-weight: 700; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; margin-left: 4px; line-height: 1; } /* === Toast Notifications === */ #toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 10000; display: flex; flex-direction: column; gap: 8px; pointer-events: none; } .toast { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 8px; font-size: 0.85rem; font-weight: 500; font-family: \'Inter\', sans-serif; color: white; backdrop-filter: blur(10px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); pointer-events: auto; transform: translateX(120%); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; } .toast.show { transform: translateX(0); opacity: 1; } .toast .material-icons-round { font-size: 18px; } .toast-success { background: rgba(5, 150, 105, 0.95); } .toast-error { background: rgba(220, 38, 38, 0.95); } .toast-info { background: rgba(59, 130, 246, 0.95); } /* === Mobile Responsiveness === */ @media (max-width: 600px) { .header-content { flex-direction: column; gap: 1rem; padding: 0.75rem; } .week-nav { width: 100%; justify-content: center; } .nav-pills { width: 100%; justify-content: space-between; } .nav-btn { flex: 1; justify-content: center; padding: 0.5rem; font-size: 0.85rem; } .days-grid { grid-template-columns: 1fr; /* Force single column */ } .main-content { padding: 1rem; } .week-title { font-size: 1.5rem; } /* Adjust toast position for mobile */ .toast-container { bottom: 1rem; right: 1rem; left: 1rem; /* Center on mobile */ width: auto; } .menu-card { margin-bottom: 1rem; } } /* === Flagging & Notification Styles === */ .btn-flag { display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 1px solid var(--text-secondary); color: var(--text-secondary); border-radius: 6px; padding: 4px; cursor: pointer; transition: all 0.2s; margin-right: 0.5rem; width: 28px; height: 28px; } .btn-flag:hover { background: rgba(234, 179, 8, 0.1); /* Yellow-500 / 10% */ color: #eab308; border-color: #eab308; } .btn-flag.active { background: rgba(234, 179, 8, 0.1); color: #eab308; border-color: #eab308; } .btn-flag .material-icons-round { font-size: 1.1rem; } /* Flagged & Sold Out (Yellow Glow) */ .menu-item.flagged-sold-out { border: 1px solid #eab308; box-shadow: 0 0 10px rgba(234, 179, 8, 0.2); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: yellow-pulse 3s infinite; } @keyframes yellow-pulse { 0% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } 50% { box-shadow: 0 0 16px rgba(234, 179, 8, 0.5); } 100% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } } /* Flagged & Available (Green Glow) */ .menu-item.flagged-available { border: 2px solid var(--success-color); box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: green-pulse 3s infinite; } @keyframes green-pulse { 0% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } 50% { box-shadow: 0 0 20px rgba(16, 185, 129, 0.6); } 100% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } } /* Day Header Badges */ .day-header-left { display: flex; align-items: center; gap: 0.75rem; } .menu-code-badge { font-size: 0.75rem; font-weight: 700; color: #8b5cf6; /* Violet 500 */ background-color: rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.3); padding: 2px 6px; border-radius: 6px; line-height: normal; display: inline-block; } /* Detailed Badge Colors */ .nav-badge.badge-violet { background-color: #8b5cf6; } .nav-badge.badge-green { background-color: var(--success-color); } .nav-badge.badge-red { background-color: var(--error-color); } .nav-badge.badge-blue { background-color: var(--accent-color); } /* Day Header Status Colors (User Request) */ .card-header.header-violet { background-color: var(--bg-card); background-image: linear-gradient(rgba(139, 92, 246, 0.15), rgba(139, 92, 246, 0.15)); border-bottom: 2px solid #8b5cf6; } .card-header.header-green { background-color: var(--bg-card); background-image: linear-gradient(rgba(16, 185, 129, 0.15), rgba(16, 185, 129, 0.15)); border-bottom: 2px solid var(--success-color); } .card-header.header-red { background-color: var(--bg-card); background-image: linear-gradient(rgba(239, 68, 68, 0.15), rgba(239, 68, 68, 0.15)); border-bottom: 2px solid var(--error-color); } .card-header.header-violet .day-name, .card-header.header-green .day-name, .card-header.header-red .day-name { font-weight: 700; color: var(--text-primary); /* Ensure text remains standard color */ } /* Update Icon */ .update-icon { display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; background-color: rgba(16, 185, 129, 0.2); /* Green tint */ color: var(--success-color); border-radius: 50%; width: 24px; height: 24px; cursor: pointer; font-size: 14px; transition: all 0.2s; text-decoration: none; animation: pulse 2s infinite; } .update-icon:hover { background-color: var(--success-color); color: white; transform: scale(1.1); } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } } /* Order Countdown */ #order-countdown { background: rgba(255, 255, 255, 0.1); padding: 0.25rem 0.75rem; border-radius: 99px; font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; border: 1px solid var(--border-color); } #order-countdown span { opacity: 0.7; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; } #order-countdown.urgent { background: rgba(239, 68, 68, 0.2); border-color: rgba(239, 68, 68, 0.5); color: #ef4444; animation: pulse-red 2s infinite; } @keyframes pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } } /* Smart Highlights (Blue Glow - matches today-ordered/flagged pattern) */ .menu-item.highlight-glow { border: 2px solid rgba(59, 130, 246, 0.7); box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: blue-pulse 3s infinite; } @keyframes blue-pulse { 0% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } 50% { box-shadow: 0 0 25px rgba(59, 130, 246, 0.6); } 100% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } } /* Nav Badge with Count */ .nav-badge.has-highlights { background-color: var(--bg-card); /* Neutral background */ color: var(--text-primary); border: 1px solid var(--border-color); padding: 2px 6px; } .nav-badge .highlight-count { color: #3b82f6; /* Blue 500 */ font-weight: 700; margin-left: 4px; } /* Tag Management Modal */ #tags-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; min-height: 50px; } /* Tag badges styled consistently with .badge (verfügbar/ausverkauft) */ .tag-badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; background-color: rgba(59, 130, 246, 0.1); color: #3b82f6; border: 1px solid rgba(59, 130, 246, 0.2); gap: 4px; } .tag-remove { cursor: pointer; opacity: 0.7; font-size: 1.1em; line-height: 1; transition: all 0.2s; } .tag-remove:hover { opacity: 1; color: #ef4444; } .input-group { display: flex; gap: 0.5rem; } .input-group input { flex: 1; padding: 0.75rem; background: var(--bg-body); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 8px; font-family: inherit; } /* Add tag button - styled like .btn-order with nav-btn.active color */ #btn-add-tag { display: inline-flex; align-items: center; gap: 4px; padding: 0.5rem 1rem; border: none; border-radius: 6px; background: var(--accent-color); color: white; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; white-space: nowrap; } #btn-add-tag:hover { filter: brightness(1.15); transform: translateY(-1px); } .matched-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; /* Space between tags and title */ margin-top: -5px; /* Pull closer to header */ } .tag-badge-small { display: inline-flex; align-items: center; font-size: 0.7rem; padding: 2px 8px; border-radius: 4px; background: rgba(59, 130, 246, 0.15); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } [data-theme="light"] .tag-badge-small { background: rgba(37, 99, 235, 0.1); color: #2563eb; border: 1px solid rgba(37, 99, 235, 0.2); } /* Installer Changelog */ .changelog-container ul { padding-left: 1.5rem; margin: 0.5rem 0; } .changelog-container li { margin-bottom: 0.4rem; line-height: 1.5; } .changelog-container h3 { margin-top: 1.5rem; margin-bottom: 0.5rem; font-size: 1.1em; color: var(--accent-color); } /* === Version Menu === */ .version-tag { cursor: pointer; transition: opacity 0.2s ease, text-decoration 0.2s ease; } .version-tag:hover { opacity: 1 !important; text-decoration: underline; } .version-list { list-style: none; padding: 0; margin: 0; } .version-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; border-radius: 8px; margin-bottom: 4px; transition: background 0.2s; } .version-item:hover { background: rgba(100, 116, 139, 0.08); } .version-item.current { background: rgba(2, 154, 168, 0.1); border: 1px solid rgba(2, 154, 168, 0.25); } [data-theme="dark"] .version-item:hover { background: rgba(255, 255, 255, 0.05); } [data-theme="dark"] .version-item.current { background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } .version-info { display: flex; align-items: center; gap: 10px; } .badge-current { font-size: 0.75rem; font-weight: 600; color: var(--success-color); padding: 2px 8px; border-radius: 4px; background: rgba(5, 150, 105, 0.1); } .badge-new { font-size: 0.75rem; font-weight: 600; color: #029aa8; padding: 2px 8px; border-radius: 4px; background: rgba(2, 154, 168, 0.1); } [data-theme="dark"] .badge-new { color: #60a5fa; background: rgba(96, 165, 250, 0.12); } .install-link { font-size: 0.8rem; font-weight: 500; padding: 4px 12px; border-radius: 6px; background: rgba(2, 154, 168, 0.1); color: #029aa8; text-decoration: none; border: 1px solid rgba(2, 154, 168, 0.25); transition: all 0.2s; white-space: nowrap; } .install-link:hover { background: rgba(2, 154, 168, 0.2); border-color: rgba(2, 154, 168, 0.4); } [data-theme="dark"] .install-link { color: #60a5fa; background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } [data-theme="dark"] .install-link:hover { background: rgba(96, 165, 250, 0.2); border-color: rgba(96, 165, 250, 0.4); } .dev-toggle { padding: 10px 14px; border-radius: 8px; background: rgba(100, 116, 139, 0.05); border: 1px solid var(--border-color); } .dev-toggle input[type="checkbox"] { accent-color: #029aa8; width: 16px; height: 16px; } [data-theme="dark"] .dev-toggle input[type="checkbox"] { accent-color: #60a5fa; } ';document.head.appendChild(s); // Inject JS logic var sc=document.createElement('script'); sc.textContent="function showErrorModal(e,t,n,a){const s=\"error-modal\";let o=document.getElementById(s);o&&o.remove(),o=document.createElement(\"div\"),o.id=s,o.className=\"modal hidden\",o.innerHTML=`\\n \\n \\n
\\n
${t}
\\n
\\n \\n ${n}\\n open_in_new \\n \\n
\\n
\\n
\\n `,document.body.appendChild(o),document.getElementById(\"btn-error-redirect\").addEventListener(\"click\",()=>{window.location.href=a}),requestAnimationFrame(()=>{o.classList.remove(\"hidden\")})}!function(){\"use strict\";if(window.__KANTINE_LOADED)return;window.__KANTINE_LOADED=!0;const e=\"https://api.bessa.app/v1\",t=\"c3418725e95a9f90e3645cbc846b4d67c7c66131\",n=591,a=\"TauNeutrino/kantine-overview\",s=`https://api.github.com/repos/${a}`,o=`https://htmlpreview.github.io/?https://github.com/${a}/blob`;let r=[],i=U(new Date),l=(new Date).getFullYear(),c=\"this-week\",d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\"),u=new Map,g=new Set(JSON.parse(localStorage.getItem(\"kantine_flags\")||\"[]\")),h=null,p=localStorage.getItem(\"kantine_lang\")||\"de\";function f(e){return{Authorization:`Token ${e||t}`,Accept:\"application/json\",\"Content-Type\":\"application/json\",\"X-Client-Version\":\"1.7.0_prod/2026-01-26\"}}function v(){if(!d)try{const e=localStorage.getItem(\"AkitaStores\");if(e){const t=JSON.parse(e);t.auth&&t.auth.token&&(console.log(\"Found existing Bessa session!\"),d=t.auth.token,localStorage.setItem(\"kantine_authToken\",d),t.auth.user&&(m=t.auth.user.id||\"unknown\",localStorage.setItem(\"kantine_currentUser\",m),t.auth.user.firstName&&localStorage.setItem(\"kantine_firstName\",t.auth.user.firstName),t.auth.user.lastName&&localStorage.setItem(\"kantine_lastName\",t.auth.user.lastName)))}}catch(e){console.warn(\"Failed to parse AkitaStores:\",e)}d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\");const e=localStorage.getItem(\"kantine_firstName\"),t=document.getElementById(\"btn-login-open\"),n=document.getElementById(\"user-info\"),a=document.getElementById(\"user-id-display\");d?(t.classList.add(\"hidden\"),n.classList.remove(\"hidden\"),a.textContent=e||(m?`User ${m}`:\"Angemeldet\"),y()):(t.classList.remove(\"hidden\"),n.classList.add(\"hidden\"),a.textContent=\"\"),z()}async function y(){if(d)try{const t=await fetch(`${e}/user/orders/?venue=591&ordering=-created&limit=50`,{headers:f(d)}),n=await t.json();if(t.ok){u=new Map;const e=n.results||[];for(const t of e){if(9===t.order_state)continue;const e=t.date.split(\"T\")[0];for(const n of t.items||[]){const a=`${e}_${n.article}`;u.has(a)||u.set(a,[]),u.get(a).push(t.id)}}console.log(`Fetched ${e.length} orders, mapped active ones.`),z(),$()}}catch(e){console.error(\"Error fetching orders:\",e)}}let b=null;function w(e){const t=document.getElementById(\"history-content\");if(!e||0===e.length)return void(t.innerHTML='Keine Bestellungen gefunden.
');const n={};e.forEach(e=>{const t=new Date(e.date),a=t.getFullYear(),s=t.getMonth(),o=`${a}-${s.toString().padStart(2,\"0\")}`,r=t.toLocaleString(\"de-AT\",{month:\"long\"}),i=U(t);n[a]||(n[a]={year:a,months:{}}),n[a].months[o]||(n[a].months[o]={name:r,year:a,monthIndex:s,count:0,total:0,weeks:{}}),n[a].months[o].weeks[i]||(n[a].months[o].weeks[i]={label:`KW ${i}`,items:[],count:0,total:0});(e.items||[]).forEach(t=>{const s=parseFloat(t.price||e.total||0);n[a].months[o].weeks[i].items.push({date:e.date,name:t.name||\"Men\u00fc\",price:s,state:e.order_state}),9!==e.order_state&&(n[a].months[o].weeks[i].count++,n[a].months[o].weeks[i].total+=s,n[a].months[o].count++,n[a].months[o].total+=s)})});const a=Object.keys(n).sort((e,t)=>t-e);let s=\"\";a.forEach(e=>{const t=n[e];s+=`\\n `;Object.keys(t.months).sort((e,t)=>t.localeCompare(e)).forEach(e=>{const n=t.months[e];s+=`
\\n \\n
`;Object.keys(n.weeks).sort((e,t)=>parseInt(t)-parseInt(e)).forEach(e=>{const t=n.weeks[e];s+=`
\\n `,t.items.forEach(e=>{const t=new Date(e.date).toLocaleDateString(\"de-AT\",{weekday:\"short\",day:\"2-digit\",month:\"2-digit\"});let n=\"\";n=9===e.state?'
Storniert ':8===e.state?'
Abgeschlossen ':'
\u00dcbertragen ',s+=`\\n
\\n
${t}
\\n
\\n
${J(e.name)} \\n
${n}
\\n
\\n
\u20ac${e.price.toFixed(2)}
\\n
`}),s+=\"
\"}),s+=\"
\"}),s+=\"
\"}),t.innerHTML=s;t.querySelectorAll(\".history-month-header\").forEach(e=>{e.addEventListener(\"click\",()=>{const t=e.parentElement;t.classList.contains(\"open\")?(t.classList.remove(\"open\"),e.setAttribute(\"aria-expanded\",\"false\")):(t.classList.add(\"open\"),e.setAttribute(\"aria-expanded\",\"true\"))})})}function k(){localStorage.setItem(\"kantine_flags\",JSON.stringify([...g]))}function A(){const e=document.getElementById(\"alarm-bell\"),t=document.getElementById(\"alarm-bell-icon\");if(!e||!t)return;if(0===g.size)return e.classList.add(\"hidden\"),e.style.display=\"none\",t.style.color=\"var(--text-secondary)\",void(t.style.textShadow=\"none\");e.classList.remove(\"hidden\"),e.style.display=\"inline-flex\";let n=!1;for(const e of r)if(e.days){for(const t of e.days)if(t.items){for(const e of t.items)if(e.available&&g.has(e.id)){n=!0;break}if(n)break}if(n)break}let a=localStorage.getItem(\"kantine_last_updated\"),s=\"gerade eben\";a||(a=(new Date).toISOString(),localStorage.setItem(\"kantine_last_updated\",a));const o=new Date(a),i=Date.now()-o.getTime(),l=Math.floor(i/6e4);s=l<1?\"gerade eben\":l<60?`vor ${l} Min.`:`vor ${Math.floor(l/60)} Std.`,e.title=`Zuletzt gepr\u00fcft: ${s}`,n?(t.style.color=\"#10b981\",t.style.textShadow=\"0 0 10px rgba(16, 185, 129, 0.4)\"):(t.style.color=\"#f59e0b\",t.style.textShadow=\"0 0 10px rgba(245, 158, 11, 0.4)\")}function E(n,a,s,o){const i=`${n}_${a}`;let l=!1;g.has(i)?(g.delete(i),F(`Flag entfernt f\u00fcr ${s}`,\"success\")):(g.add(i),l=!0,F(`Benachrichtigung aktiviert f\u00fcr ${s}`,\"success\"),\"default\"===Notification.permission&&Notification.requestPermission()),k(),A(),z(),l&&async function(){if(0===g.size)return;const n=d||t,a=new Set;for(const e of g){const[t]=e.split(\"_\");a.add(t)}let s=!1;for(const t of a)try{const a=await fetch(`${e}/venues/591/menu/7/${t}/`,{headers:f(n)});if(!a.ok)continue;const o=(await a.json()).results||[];let i=[];for(const e of o)e.items&&Array.isArray(e.items)&&(i=i.concat(e.items));for(let e of r){if(!e.days)continue;let n=e.days.find(e=>e.date===t);n&&(n.items=i.map(e=>{const n=!1===e.amount_tracking,a=parseInt(e.available_amount)>0;return{id:`${t}_${e.id}`,articleId:e.id,name:e.name||\"Unknown\",description:e.description||\"\",price:parseFloat(e.price)||0,available:n||a,availableAmount:parseInt(e.available_amount)||0,amountTracking:!1!==e.amount_tracking}}),s=!0)}}catch(e){console.error(\"Error refreshing flag date\",t,e)}s&&(O(),q((new Date).toISOString()),A(),z())}()}function I(){h||d&&(h=setInterval(()=>async function(){if(0===g.size||!d)return;console.log(`Polling ${g.size} flagged items...`);for(const t of g){const[n,a]=t.split(\"_\"),s=parseInt(a);try{const t=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(d)});if(!t.ok)continue;const a=(await t.json()).results||[];let o=null;for(const e of a)if(e.items&&(o=e.items.find(e=>e.id===s||e.article===s),o))break;if(o){if(!1===o.amount_tracking||parseInt(o.available_amount)>0){const e=o.name||\"Unbekannt\";F(`${e} ist jetzt verf\u00fcgbar!`,\"success\"),\"granted\"===Notification.permission&&new Notification(\"Kantine Wrapper\",{body:`${e} ist jetzt verf\u00fcgbar!`,icon:\"\ud83c\udf7d\ufe0f\"}),M()}}}catch(e){console.error(`Poll error for ${t}:`,e),await new Promise(e=>setTimeout(e,200))}}}(),3e5),console.log(\"Polling started (every 5 min)\"))}let L=JSON.parse(localStorage.getItem(\"kantine_highlightTags\")||\"[]\");function S(){localStorage.setItem(\"kantine_highlightTags\",JSON.stringify(L)),z(),$()}function B(){const e=document.getElementById(\"tags-list\");e.innerHTML=\"\",L.forEach(t=>{const n=document.createElement(\"span\");n.className=\"tag-badge\",n.innerHTML=`${t} × `,e.appendChild(n)}),e.querySelectorAll(\".tag-remove\").forEach(e=>{e.addEventListener(\"click\",e=>{var t;t=e.target.dataset.tag,L=L.filter(e=>e!==t),S(),B()})})}function x(e){return e?(e=e.toLowerCase(),L.filter(t=>e.includes(t))):[]}const C=\"kantine_menuCache\",D=\"kantine_menuCacheTs\";function O(){try{localStorage.setItem(C,JSON.stringify(r)),localStorage.setItem(D,(new Date).toISOString())}catch(e){console.warn(\"Failed to cache menu data:\",e)}}async function M(){const n=document.getElementById(\"loading\"),a=document.getElementById(\"progress-modal\"),s=document.getElementById(\"progress-fill\"),o=document.getElementById(\"progress-percent\"),c=document.getElementById(\"progress-message\");n.classList.remove(\"hidden\");const m=d||t;try{a.classList.remove(\"hidden\"),c.textContent=\"Hole verf\u00fcgbare Daten...\",s.style.width=\"0%\",o.textContent=\"0%\";const t=await fetch(`${e}/venues/591/menu/dates/`,{headers:f(m)});if(!t.ok)throw new Error(`Failed to fetch dates: ${t.status}`);let n=(await t.json()).results||[];const d=new Date;d.setDate(d.getDate()-7);const u=d.toISOString().split(\"T\")[0];n=n.filter(e=>e.date>=u).sort((e,t)=>e.date.localeCompare(t.date)).slice(0,30);const g=n.length;c.textContent=`${g} Tage gefunden. Lade Details...`;const h=[];let p=0;for(const t of n){const n=t.date,a=Math.round((p+1)/g*100);s.style.width=`${a}%`,o.textContent=`${a}%`,c.textContent=`Lade Men\u00fc f\u00fcr ${n}...`;try{const a=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(m)});if(a.ok){const e=await a.json();0===p&&console.log(\"[Kantine Debug] Raw API response for\",n,\":\",JSON.stringify(e).substring(0,2e3));const s=e.results||[];let o=[];for(const e of s)e.items&&Array.isArray(e.items)&&(o=o.concat(e.items));o.length>0&&(0===p&&(console.log(\"[Kantine Debug] First item keys:\",Object.keys(o[0])),console.log(\"[Kantine Debug] First item:\",JSON.stringify(o[0]).substring(0,500))),h.push({date:n,menu_items:o,orders:t.orders||[]}))}}catch(e){console.error(`Failed to fetch details for ${n}:`,e)}p++,await new Promise(e=>setTimeout(e,100))}const y=new Map;r&&r.length>0&&r.forEach(e=>{const t=`${e.year}-${e.weekNumber}`;try{y.set(t,{year:e.year,weekNumber:e.weekNumber,days:e.days?e.days.map(e=>({...e,items:e.items?[...e.items]:[]})):[]})}catch(e){console.warn(\"Error hydrating week:\",e)}});for(const e of h){const t=new Date(e.date),n=U(t),a=G(t),s=`${a}-${n}`;y.has(s)||y.set(s,{year:a,weekNumber:n,days:[]});const o=y.get(s),r=t.toLocaleDateString(\"en-US\",{weekday:\"long\"}),i=new Date(e.date);i.setHours(10,0,0,0);const l={date:e.date,weekday:r,orderCutoff:i.toISOString(),items:e.menu_items.map(t=>{const n=!1===t.amount_tracking,a=parseInt(t.available_amount)>0;return{id:`${e.date}_${t.id}`,articleId:t.id,name:t.name||\"Unknown\",description:t.description||\"\",price:parseFloat(t.price)||0,available:n||a,availableAmount:parseInt(t.available_amount)||0,amountTracking:!1!==t.amount_tracking}})},c=o.days.findIndex(t=>t.date===e.date);c>=0?o.days[c]=l:o.days.push(l)}r=Array.from(y.values()).sort((e,t)=>e.year!==t.year?e.year-t.year:e.weekNumber-t.weekNumber),r.forEach(e=>{e.days&&e.days.sort((e,t)=>e.date.localeCompare(t.date))}),O(),q((new Date).toISOString()),i=U(new Date),l=(new Date).getFullYear(),v(),z(),$(),A(),c.textContent=\"Fertig!\",setTimeout(()=>a.classList.add(\"hidden\"),500)}catch(e){console.error(\"Error fetching menu:\",e),a.classList.add(\"hidden\"),showErrorModal(\"Keine Verbindung\",`Die Men\u00fcdaten konnten nicht geladen werden. M\u00f6glicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.${e.message} `,\"Zur Original-Seite\",\"https://web.bessa.app/knapp-kantine\")}finally{n.classList.add(\"hidden\")}}let N=null,T=null;function q(e){const t=document.getElementById(\"last-updated-subtitle\");if(e){N=e;try{const n=new Date(e),a=n.toLocaleTimeString(\"de-DE\",{hour:\"2-digit\",minute:\"2-digit\"}),s=n.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),o=function(e){const t=Date.now()-e.getTime(),n=Math.floor(t/6e4);if(n<1)return\"gerade eben\";if(1===n)return\"vor 1 min.\";if(n<60)return`vor ${n} min.`;const a=Math.floor(n/60);return 1===a?\"vor 1 Std.\":`vor ${a} Std.`}(n);t.textContent=`Aktualisiert: ${s} ${a} (${o})`}catch(e){t.textContent=\"\"}T||(T=setInterval(()=>{N&&q(N)},6e4))}}function F(e,t=\"info\"){let n=document.getElementById(\"toast-container\");n||(n=document.createElement(\"div\"),n.id=\"toast-container\",document.body.appendChild(n));const a=document.createElement(\"div\");a.className=`toast toast-${t}`;const s=\"success\"===t?\"check_circle\":\"error\"===t?\"error\":\"info\";a.innerHTML=`${s} ${e} `,n.appendChild(a),requestAnimationFrame(()=>a.classList.add(\"show\")),setTimeout(()=>{a.classList.remove(\"show\"),setTimeout(()=>a.remove(),300)},3e3)}function $(){const e=document.getElementById(\"btn-next-week\");let t=i+1,n=l;t>52&&(t=1,n++);const a=r.find(e=>e.weekNumber===t&&e.year===n);let s=0,o=0,c=0,d=0;a&&a.days&&a.days.forEach(e=>{if(e.items&&e.items.length>0){s++;const t=e.items.some(e=>e.available);t&&o++;let n=!1;e.items.forEach(t=>{const a=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${a}`;u.has(s)&&u.get(s).length>0&&(n=!0)}),n&&c++,t&&!n&&d++}});let m=e.querySelector(\".nav-badge\");if(s>0){m||(m=document.createElement(\"span\"),m.className=\"nav-badge\",e.appendChild(m)),m.title=`${c} bestellt / ${o} bestellbar / ${s} gesamt`,m.innerHTML=`${c} / ${o} / ${s} `,m.classList.remove(\"badge-violet\",\"badge-green\",\"badge-red\",\"badge-blue\"),c>0&&0===d?m.classList.add(\"badge-violet\"):d>0?m.classList.add(\"badge-green\"):0===o?m.classList.add(\"badge-red\"):m.classList.add(\"badge-blue\");let r=0;if(a&&a.days&&a.days.forEach(e=>{e.items.forEach(e=>{const t=x(e.name),n=x(e.description);(t.length>0||n.length>0)&&r++})}),r>0&&(m.innerHTML+=`(${r}) `,m.title+=` \u2022 ${r} Highlights gefunden`,m.classList.add(\"has-highlights\")),0===c){e.classList.add(\"new-week-available\");const a=`kantine_notified_nextweek_${n}_${t}`;localStorage.getItem(a)||(localStorage.setItem(a,\"true\"),F(\"Neue Men\u00fcdaten f\u00fcr n\u00e4chste Woche verf\u00fcgbar!\",\"info\"))}else e.classList.remove(\"new-week-available\")}else m&&m.remove()}function z(){const t=document.getElementById(\"menu-container\");if(!t)return;t.innerHTML=\"\";let a=i,s=l;\"next-week\"===c&&(a++,a>52&&(a=1,s++));const o=r.flatMap(e=>e.days||[]).filter(e=>{const t=new Date(e.date);return U(t)===a&&G(t)===s});if(0===o.length)return t.innerHTML=`\\n \\n
Keine Men\u00fcdaten f\u00fcr KW ${a} (${s}) verf\u00fcgbar.
\\n
Versuchen Sie eine andere Woche oder schauen Sie sp\u00e4ter vorbei. \\n
`,void document.getElementById(\"weekly-cost-display\").classList.add(\"hidden\");!function(e){let t=0;e&&e.length>0&&e.forEach(e=>{e.items&&e.items.forEach(n=>{const a=n.articleId||parseInt(n.id.split(\"_\")[1]),s=`${e.date}_${a}`,o=u.get(s)||[];o.length>0&&(t+=n.price*o.length)})});const n=document.getElementById(\"weekly-cost-display\");t>0?(n.innerHTML=`shopping_bag Gesamt: ${t.toFixed(2).replace(\".\",\",\")} \u20ac `,n.classList.remove(\"hidden\")):n.classList.add(\"hidden\")}(o);const m=document.getElementById(\"header-week-info\"),h=\"this-week\"===c?\"Diese Woche\":\"N\u00e4chste Woche\";m.innerHTML=`\\n \\n `;const v=document.createElement(\"div\");v.className=\"days-grid\",o.sort((e,t)=>e.date.localeCompare(t.date));o.filter(e=>{const t=new Date(e.date).getDay();return 0!==t&&6!==t}).forEach(t=>{const a=function(t){if(!t.items||0===t.items.length)return null;const a=document.createElement(\"div\");a.className=\"menu-card\";const s=new Date,o=new Date(t.date);let r=!1;if(t.orderCutoff)r=s>=new Date(t.orderCutoff);else{const e=new Date;e.setHours(0,0,0,0);const n=new Date(t.date);n.setHours(0,0,0,0),r=n{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`,s=(u.get(a)||[]).length;if(s>0){const t=e.name.match(/([M][1-9][Ff]?)/);if(t){let e=t[1];s>1&&(e+=\"+\"),i.push(e)}}});const l=document.createElement(\"div\");l.className=\"card-header\";const c=o.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),m=i.map(e=>``).join(\"\");let h=\"\";const v=t.items&&t.items.some(e=>{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`;return u.has(a)&&u.get(a).length>0}),w=t.items&&t.items.some(e=>e.available);h=v?\"header-violet\":w&&!r?\"header-green\":\"header-red\";h&&l.classList.add(h);l.innerHTML=`\\n \\n ${c} `,a.appendChild(l);var k;const A=document.createElement(\"div\");A.className=\"card-body\";const I=(new Date).toISOString().split(\"T\")[0],L=t.date===I,S=[...t.items].sort((e,n)=>{if(L){const a=e.articleId||parseInt(e.id.split(\"_\")[1]),s=n.articleId||parseInt(n.id.split(\"_\")[1]),o=u.has(`${t.date}_${a}`),r=u.has(`${t.date}_${s}`);if(o&&!r)return-1;if(!o&&r)return 1}return e.name.localeCompare(n.name)});return S.forEach(a=>{const o=document.createElement(\"div\");o.className=\"menu-item\";const i=a.articleId||parseInt(a.id.split(\"_\")[1]),l=`${t.date}_${i}`,c=(u.get(l)||[]).length;let m=\"\";m=a.available?a.amountTracking?`Verf\u00fcgbar (${a.availableAmount}) `:'Verf\u00fcgbar ':'Ausverkauft ';let h=\"\";if(c>0){h=`check_circle Bestellt${c>1?`${c} `:\"\"} `,o.classList.add(\"ordered\"),new Date(t.date).toDateString()===s.toDateString()&&o.classList.add(\"today-ordered\")}const v=`${t.date}_${i}`,w=g.has(v);w&&o.classList.add(a.available?\"flagged-available\":\"flagged-sold-out\");const k=[...new Set([...x(a.name),...x(a.description)])];k.length>0&&o.classList.add(\"highlight-glow\");let I=\"\",L=\"\",S=\"\";if(d&&!r){const e=w?\"notifications_active\":\"notifications_none\",n=w?\"btn-flag active\":\"btn-flag\",s=w?\"Benachrichtigung deaktivieren\":\"Benachrichtigen wenn verf\u00fcgbar\";if(a.available&&!w||(S=`${e} `),a.available&&(I=c>0?`add `:`add_shopping_cart Bestellen `),c>0){const e=1===c?\"close\":\"remove\",n=1===c?\"Bestellung stornieren\":\"Eine Bestellung stornieren\";L=`${e} `}}let B=\"\";if(k.length>0){B=`${k.map(e=>`star ${J(e)} `).join(\"\")}
`}o.innerHTML=`\\n \\n \\n ${h}\\n ${L}\\n ${I}\\n ${S}\\n
${m}
\\n
\\n ${B}\\n ${J(function(e){if(\"all\"===p)return e||\"\";const t=function(e){if(!e)return{de:\"\",en:\"\",raw:\"\"};let t=e.replace(/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?=\\S)/g,\"($1)\\n\u2022 \");t.startsWith(\"\u2022 \")||(t=\"\u2022 \"+t);function n(e){let t=0,n=0;return e.forEach(e=>{const a=e.toLowerCase().replace(/[^a-z\u00e4\u00f6\u00fc\u00df]/g,\"\");if(a){let s=0,o=0;W.includes(a)?s=a.length:W.forEach(e=>{a.includes(e)&&e.length>s&&(s=e.length)}),P.includes(a)?o=a.length:P.forEach(e=>{a.includes(e)&&e.length>o&&(o=e.length)}),s>0&&(t+=s/a.length),o>0&&(n+=o/a.length),/^[A-Z\u00c4\u00d6\u00dc]/.test(e)&&(t+=.5)}}),{de:t,en:n}}function a(e){const t=e.trim().split(/\\s+/);if(t.length<2)return{enPart:e,nextDe:\"\"};let a=-1,s=-9999;for(let e=1;el.en&&m>s&&(s=m,a=e)}return-1!==a?{enPart:t.slice(0,a).join(\" \"),nextDe:t.slice(a).join(\" \")}:{enPart:e,nextDe:\"\"}}const s=e.split(/\\s*\\/\\s*(?![A-Z,]+\\))/);if(s.length>4)return{de:t,en:\"\",raw:t};const o=[],r=[];o.push(s[0].trim());const i=/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*/;for(let e=1;e0&&(o[o.length-1]=o[o.length-1]+\"(\"+s+\")\"),i&&o.push(i)}else{const e=a(t);r.push(e.enPart),e.nextDe&&o.push(e.nextDe)}}1===s.length&&0===r.length&&r.push(o[0]);if(o.length>r.length)for(let e=r.length;e0&&!l.startsWith(\"\u2022 \")&&(l=\"\u2022 \"+l);let c=r.join(\"\\n\u2022 \");r.length>0&&!c.startsWith(\"\u2022 \")&&(c=\"\u2022 \"+c);return{de:l,en:c,raw:t}}(e);return\"en\"===p?t.en||t.raw:t.de||t.raw}(a.description))}
`;const C=o.querySelector(\".btn-order\");C&&C.addEventListener(\"click\",t=>{t.stopPropagation();const a=t.currentTarget;a.disabled=!0,a.classList.add(\"loading\"),async function(t,a,s,o,r){if(d)try{const i=await fetch(`${e}/auth/user/`,{headers:f(d)});if(!i.ok)return void F(\"Fehler: Benutzerdaten konnten nicht geladen werden\",\"error\");const l=await i.json(),c=(new Date).toISOString(),m={uuid:crypto.randomUUID(),created:c,updated:c,order_type:7,items:[{article:a,course_group:null,modifiers:[],uuid:crypto.randomUUID(),name:s,description:r||\"\",price:String(parseFloat(o)),amount:1,vat:\"10.00\",comment:\"\"}],table:null,total:parseFloat(o),tip:0,currency:\"EUR\",venue:n,states:[],order_state:1,date:`${t}T10:30:00Z`,payment_method:\"payroll\",customer:{first_name:l.first_name,last_name:l.last_name,email:l.email,newsletter:!1},preorder:!0,delivery_fee:0,cash_box_table_name:null,take_away:!1},u=await fetch(`${e}/user/orders/`,{method:\"POST\",headers:f(d),body:JSON.stringify(m)});if(u.ok||201===u.status)F(`Bestellt: ${s}`,\"success\"),b=null,await y();else{const e=await u.json();F(`Fehler: ${e.detail||e.non_field_errors?.[0]||\"Bestellung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Order error:\",e),F(\"Netzwerkfehler bei Bestellung\",\"error\")}}(a.dataset.date,parseInt(a.dataset.article),a.dataset.name,parseFloat(a.dataset.price),a.dataset.desc||\"\").finally(()=>{a.disabled=!1,a.classList.remove(\"loading\")})});const D=o.querySelector(\".btn-cancel\");D&&D.addEventListener(\"click\",t=>{t.stopPropagation();const n=t.currentTarget;n.disabled=!0,async function(t,n,a){if(!d)return;const s=`${t}_${n}`,o=u.get(s);if(!o||0===o.length)return;const r=o[o.length-1];try{const t=await fetch(`${e}/user/orders/${r}/cancel/`,{method:\"PATCH\",headers:f(d),body:JSON.stringify({})});t.ok?(F(`Storniert: ${a}`,\"success\"),b=null,await y()):F(`Fehler: ${(await t.json()).detail||\"Stornierung fehlgeschlagen\"}`,\"error\")}catch(e){console.error(\"Cancel error:\",e),F(\"Netzwerkfehler bei Stornierung\",\"error\")}}(n.dataset.date,parseInt(n.dataset.article),n.dataset.name).finally(()=>{n.disabled=!1})});const O=o.querySelector(\".btn-flag\");O&&O.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;E(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,t.dataset.cutoff)}),A.appendChild(o)}),a.appendChild(A),a}(t);a&&v.appendChild(a)}),t.appendChild(v),setTimeout(()=>function(e){const t=e.querySelectorAll(\".menu-card\");if(0===t.length)return;let n=0;t.forEach(e=>{n=Math.max(n,e.querySelectorAll(\".menu-item\").length)});for(let e=0;e{const s=t.querySelectorAll(\".menu-item\");s[e]&&(s[e].style.height=\"auto\",n=Math.max(n,s[e].offsetHeight),a.push(s[e]))}),a.forEach(e=>{e.style.height=`${n}px`})}}(v),0)}function j(e,t){if(!e||!t)return!1;const n=e.replace(/^v/,\"\").split(\".\").map(Number),a=t.replace(/^v/,\"\").split(\".\").map(Number);for(let e=0;e(a[e]||0))return!0;if((n[e]||0)<(a[e]||0))return!1}return!1}async function H(e){const t=e?`${s}/tags?per_page=20`:`${s}/releases?per_page=20`,n=await fetch(t,{headers:{Accept:\"application/vnd.github.v3+json\"}});if(!n.ok){if(403===n.status)throw new Error(\"API Rate Limit erreicht (403). Bitte sp\u00e4ter erneut versuchen.\");throw new Error(`GitHub API ${n.status}`)}return(await n.json()).map(t=>{const n=e?t.name:t.tag_name;return{tag:n,name:e?n:t.name||n,url:`${o}/${n}/dist/install.html`,body:t.body||\"\"}})}async function K(){const e=\"v1.6.7\",t=\"true\"===localStorage.getItem(\"kantine_dev_mode\");try{const n=await H(t);if(!n.length)return;localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:t,versions:n}));const a=n[0].tag;if(console.log(`[Kantine] Version Check: Local [${e}] vs Latest [${a}] (${t?\"dev\":\"stable\"})`),!j(a,e))return;console.log(`[Kantine] Update verf\u00fcgbar: ${a}`);const s=document.querySelector(\".header-left h1\");if(s&&!s.querySelector(\".update-icon\")){const e=document.createElement(\"a\");e.className=\"update-icon\",e.href=n[0].url,e.target=\"_blank\",e.innerHTML=\"\ud83c\udd95\",e.title=`Update: ${a} \u2014 Klick zum Installieren`,e.style.cssText=\"margin-left:8px;font-size:1em;text-decoration:none;cursor:pointer;vertical-align:middle;\",s.appendChild(e)}}catch(e){console.warn(\"[Kantine] Version check failed:\",e)}}function Q(){if(!d||!m)return void X();const e=new Date,t=e.getDay();if(0===t||6===t)return void X();const n=e.toISOString().split(\"T\")[0];let a=!1;for(const e of u.keys())if(e.startsWith(n)){a=!0;break}if(a)return void X();const s=new Date;s.setHours(10,0,0,0);const o=s-e;if(o<=0)return void X();const r=Math.floor(o/36e5),i=Math.floor(o%36e5/6e4),l=document.querySelector(\".header-center-wrapper\");if(!l)return;let c=document.getElementById(\"order-countdown\");if(c||(c=document.createElement(\"div\"),c.id=\"order-countdown\",l.insertBefore(c,l.firstChild)),c.innerHTML=`Bestellschluss: ${r}h ${i}m `,o<36e5){c.classList.add(\"urgent\");const e=`kantine_notified_${n}`;localStorage.getItem(e)||(\"granted\"===Notification.permission?new Notification(\"Kantine: Bestellschluss naht!\",{body:\"Du hast heute noch nichts bestellt. Nur noch 1 Stunde!\",icon:\"\u23f3\"}):\"default\"===Notification.permission&&Notification.requestPermission(),localStorage.setItem(e,\"true\"))}else c.classList.remove(\"urgent\")}function X(){const e=document.getElementById(\"order-countdown\");e&&e.remove()}function U(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate())),n=t.getUTCDay()||7;t.setUTCDate(t.getUTCDate()+4-n);const a=new Date(Date.UTC(t.getUTCFullYear(),0,1));return Math.ceil(((t-a)/864e5+1)/7)}function G(e){const t=new Date(e.getTime());return t.setDate(t.getDate()+3-(t.getDay()+6)%7),t.getFullYear()}function J(e){const t=document.createElement(\"div\");return t.textContent=e||\"\",t.innerHTML}setInterval(Q,6e4),setTimeout(Q,1e3);const W=[\"apfel\",\"aubergine\",\"auflauf\",\"beere\",\"blumenkohl\",\"bohne\",\"braten\",\"brokkoli\",\"brot\",\"brust\",\"br\u00f6tchen\",\"butter\",\"chili\",\"dessert\",\"dip\",\"eier\",\"eintopf\",\"eis\",\"erbse\",\"erdbeer\",\"essig\",\"filet\",\"fisch\",\"fisole\",\"fleckerl\",\"fleisch\",\"fl\u00fcgel\",\"frucht\",\"f\u00fcr\",\"gebraten\",\"gem\u00fcse\",\"gew\u00fcrz\",\"gratin\",\"grie\u00df\",\"gulasch\",\"gurke\",\"himbeer\",\"honig\",\"huhn\",\"h\u00e4hnchen\",\"jambalaya\",\"joghurt\",\"karotte\",\"kartoffel\",\"keule\",\"kirsch\",\"knacker\",\"knoblauch\",\"kn\u00f6del\",\"kompott\",\"kraut\",\"kr\u00e4uter\",\"kuchen\",\"k\u00e4se\",\"k\u00fcrbis\",\"lauch\",\"mandel\",\"milch\",\"mild\",\"mit\",\"mohn\",\"most\",\"m\u00f6hre\",\"natur\",\"nockerl\",\"nudel\",\"nuss\",\"nu\u00df\",\"obst\",\"oder\",\"olive\",\"paprika\",\"pfanne\",\"pfannkuchen\",\"pfeffer\",\"pikant\",\"pilz\",\"plunder\",\"p\u00fcree\",\"ragout\",\"rahm\",\"reis\",\"rind\",\"sahne\",\"salami\",\"salat\",\"salz\",\"sauer\",\"scharf\",\"schinken\",\"schnitte\",\"schnitzel\",\"schoko\",\"schupf\",\"schwein\",\"sellerie\",\"senf\",\"sosse\",\"so\u00dfe\",\"spargel\",\"sp\u00e4tzle\",\"speck\",\"spie\u00df\",\"spinat\",\"steak\",\"suppe\",\"s\u00fc\u00df\",\"tofu\",\"tomate\",\"topfen\",\"torte\",\"tr\u00fcffel\",\"und\",\"vanille\",\"vogerl\",\"vom\",\"wien\",\"wurst\",\"zucchini\",\"zum\",\"zur\",\"zwiebel\",\"\u00f6l\"],P=[\"almond\",\"and\",\"apple\",\"asparagus\",\"bacon\",\"baked\",\"ball\",\"bean\",\"beef\",\"berry\",\"bread\",\"breast\",\"broccoli\",\"bun\",\"butter\",\"cabbage\",\"cake\",\"caper\",\"carrot\",\"casserole\",\"cauliflower\",\"celery\",\"cheese\",\"cherry\",\"chicken\",\"chili\",\"choco\",\"chocolate\",\"cider\",\"cilantro\",\"coffee\",\"compote\",\"cream\",\"cucumber\",\"curd\",\"danish\",\"dessert\",\"dip\",\"dumpling\",\"egg\",\"eggplant\",\"filet\",\"fish\",\"for\",\"fried\",\"from\",\"fruit\",\"garlic\",\"goulash\",\"gratin\",\"ham\",\"herb\",\"honey\",\"hot\",\"ice\",\"jambalaya\",\"leek\",\"leg\",\"mash\",\"meat\",\"mexican\",\"mild\",\"milk\",\"mint\",\"mushroom\",\"mustard\",\"noodle\",\"nut\",\"oat\",\"oil\",\"olive\",\"onion\",\"or\",\"oven\",\"pan\",\"pancake\",\"pea\",\"pepper\",\"plain\",\"plate\",\"poppy\",\"pork\",\"potato\",\"pumpkin\",\"radish\",\"ragout\",\"raspberry\",\"rice\",\"roast\",\"roll\",\"salad\",\"salami\",\"salt\",\"sauce\",\"sausage\",\"shrimp\",\"skewer\",\"slice\",\"soup\",\"sour\",\"spice\",\"spicy\",\"spinach\",\"steak\",\"stew\",\"strawberr\",\"strawberry\",\"strudel\",\"sweet\",\"tart\",\"thyme\",\"to\",\"tofu\",\"tomat\",\"tomato\",\"truffle\",\"trukey\",\"turkey\",\"vanilla\",\"vegan\",\"vegetable\",\"vinegar\",\"wedge\",\"wing\",\"with\",\"wok\",\"yogurt\",\"zucchini\"];!function(){document.title=\"Kantine Weekly Menu\",document.querySelectorAll&&document.querySelectorAll('link[rel*=\"icon\"]').forEach(e=>e.remove());const e=document.createElement(\"link\");if(e.rel=\"icon\",e.type=\"image/png\",e.href=\"data:image/png;base64,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\",document.head.appendChild(e),!document.querySelector('link[href*=\"fonts.googleapis.com/css2?family=Inter\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\",document.head.appendChild(e)}if(!document.querySelector('link[href*=\"Material+Icons+Round\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/icon?family=Material+Icons+Round\",document.head.appendChild(e)}document.body.innerHTML=`\\n \\n \\n\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Initialisierung...
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Markiere Men\u00fcs automatisch, wenn sie diese Schlagw\u00f6rter enthalten.\\n
\\n
\\n \\n Hinzuf\u00fcgen \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Lade Historie...
\\n
\\n
\\n
\\n \\x3c!-- Dynamically populated --\\x3e\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Aktuell: v1.6.7 \\n
\\n
\\n \\n \\n Dev-Mode (alle Tags anzeigen) \\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n \\n update \\n Gerade aktualisiert \\n
\\n \\n
\\n
Lade Men\u00fcdaten...
\\n
\\n \\n \\n\\n \\n
`}(),function(){const n=document.getElementById(\"btn-this-week\"),a=document.getElementById(\"btn-next-week\"),s=document.getElementById(\"btn-refresh\"),o=document.getElementById(\"theme-toggle\"),r=document.getElementById(\"btn-login-open\"),i=document.getElementById(\"btn-login-close\"),l=document.getElementById(\"btn-logout\"),g=document.getElementById(\"login-form\"),k=document.getElementById(\"login-modal\"),A=document.getElementById(\"btn-highlights\"),E=document.getElementById(\"highlights-modal\"),x=document.getElementById(\"btn-highlights-close\"),C=document.getElementById(\"btn-add-tag\"),D=document.getElementById(\"tag-input\"),O=document.getElementById(\"btn-history\"),N=document.getElementById(\"history-modal\"),T=document.getElementById(\"btn-history-close\");document.querySelectorAll(\".lang-btn\").forEach(e=>{e.addEventListener(\"click\",()=>{p=e.dataset.lang,localStorage.setItem(\"kantine_lang\",p),document.querySelectorAll(\".lang-btn\").forEach(e=>e.classList.remove(\"active\")),e.classList.add(\"active\"),z()})}),A&&A.addEventListener(\"click\",()=>{E.classList.remove(\"hidden\")}),x&&x.addEventListener(\"click\",()=>{E.classList.add(\"hidden\")}),O.addEventListener(\"click\",()=>{d?(N.classList.remove(\"hidden\"),async function(){const t=document.getElementById(\"history-loading\"),n=document.getElementById(\"history-content\"),a=document.getElementById(\"history-progress-fill\"),s=document.getElementById(\"history-progress-text\");let o=[];if(b)o=b;else{const e=localStorage.getItem(\"kantine_history_cache\");if(e)try{o=JSON.parse(e),b=o}catch(e){console.warn(\"History cache parse error\",e)}}o.length>0&&w(o);if(!d)return;0===o.length&&(n.innerHTML=\"\",t.classList.remove(\"hidden\"));a.style.width=\"0%\",s.textContent=o.length>0?\"Suche nach neuen Bestellungen...\":\"Lade Bestellhistorie...\",o.length>0&&t.classList.remove(\"hidden\");let r=o.length>0?`${e}/user/orders/?venue=591&ordering=-created&limit=5`:`${e}/user/orders/?venue=591&ordering=-created&limit=50`,i=[],l=0,c=0===o.length,m=!1;try{for(;r&&!m;){const e=await fetch(r,{headers:f(d)});if(!e.ok)throw new Error(`Fetch failed: ${e.status}`);const t=await e.json();t.count&&0===l&&(l=t.count);const n=t.results||[];for(const e of n){const t=o.findIndex(t=>t.id===e.id);if(!c&&-1!==t){const n=o[t];if(n.updated===e.updated&&n.order_state===e.order_state){m=!0;break}}i.push(e)}if(!m&&c)if(l>0){const e=Math.round(i.length/l*100);a.style.width=`${e}%`,s.textContent=`Lade Bestellung ${i.length} von ${l}...`}else s.textContent=`Lade Bestellung ${i.length}...`;else m||(s.textContent=`${i.length} neue/ge\u00e4nderte Bestellungen gefunden...`);r=m?null:t.next}if(i.length>0){const e=new Map(o.map(e=>[e.id,e]));for(const t of i)e.set(t.id,t);const t=Array.from(e.values());t.sort((e,t)=>new Date(t.created)-new Date(e.created)),b=t;try{localStorage.setItem(\"kantine_history_cache\",JSON.stringify(t))}catch(e){console.warn(\"History cache write error\",e)}w(b)}}catch(e){console.error(\"Error in history sync:\",e),0===o.length?n.innerHTML='Fehler beim Laden der Historie.
':F(\"Hintergrund-Synchronisation fehlgeschlagen\",\"error\")}finally{t.classList.add(\"hidden\")}}()):k.classList.remove(\"hidden\")}),T.addEventListener(\"click\",()=>{N.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===N&&N.classList.add(\"hidden\"),e.target===E&&E.classList.add(\"hidden\")});const q=document.querySelector(\".version-tag\"),$=document.getElementById(\"version-modal\"),K=document.getElementById(\"btn-version-close\");q&&q.addEventListener(\"click\",e=>{e.preventDefault(),e.stopPropagation(),function(){const e=document.getElementById(\"version-modal\"),t=document.getElementById(\"version-list-container\"),n=document.getElementById(\"dev-mode-toggle\"),a=\"v1.6.7\";if(!e)return;e.classList.remove(\"hidden\");const s=document.getElementById(\"version-current\");s&&(s.textContent=a);const o=\"true\"===localStorage.getItem(\"kantine_dev_mode\");async function r(e){const s=n.checked;function o(e){if(!e||!e.length)return void(t.innerHTML='Keine Versionen gefunden.
');t.innerHTML='';const n=t.querySelector(\".version-list\");e.forEach(e=>{const t=e.tag===a,s=j(e.tag,a),o=document.createElement(\"li\");o.className=\"version-item\"+(t?\" current\":\"\");let r=\"\";t?r='\u2713 Installiert ':s&&(r='\u2b06 Neu! ');let i=\"\";t||(i=`Installieren `),o.innerHTML=`\\n \\n ${e.tag} \\n ${r}\\n
\\n ${i}\\n `,n.appendChild(o)})}t.innerHTML='Lade Versionen...
';try{const e=localStorage.getItem(\"kantine_version_cache\");let t=null;if(e)try{t=JSON.parse(e)}catch(e){}t&&t.devMode===s&&t.versions&&o(t.versions);const n=await H(s),a=JSON.stringify(n);a!==(t?JSON.stringify(t.versions):\"\")&&(localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:s,versions:n})),o(n))}catch(e){t.innerHTML=`Fehler: ${e.message}
`}}n.checked=o,r(!1),n.onchange=()=>{localStorage.setItem(\"kantine_dev_mode\",n.checked),localStorage.removeItem(\"kantine_version_cache\"),r(!0)}}()}),K&&K.addEventListener(\"click\",()=>{$.classList.add(\"hidden\")});const Q=document.getElementById(\"btn-clear-cache\");Q&&Q.addEventListener(\"click\",()=>{confirm(\"M\u00f6chtest du wirklich alle lokalen Daten (inkl. Login-Session, Cache und Einstellungen) l\u00f6schen? Die Seite wird danach neu geladen.\")&&(Object.keys(localStorage).forEach(e=>{e.startsWith(\"kantine_\")&&localStorage.removeItem(e)}),window.location.reload())}),window.addEventListener(\"click\",e=>{e.target===$&&$.classList.add(\"hidden\")}),C.addEventListener(\"click\",()=>{(function(e){if(e=e.trim().toLowerCase(),e&&!L.includes(e))return L.push(e),S(),!0;return!1})(D.value)&&(D.value=\"\",B())}),D.addEventListener(\"keypress\",e=>{\"Enter\"===e.key&&C.click()});const X=localStorage.getItem(\"theme\"),U=window.matchMedia(\"(prefers-color-scheme: dark)\").matches,G=o.querySelector(\".theme-icon\");\"dark\"===X||!X&&U?(document.documentElement.setAttribute(\"data-theme\",\"dark\"),G.textContent=\"dark_mode\"):(document.documentElement.setAttribute(\"data-theme\",\"light\"),G.textContent=\"light_mode\"),o.addEventListener(\"click\",()=>{const e=\"dark\"===document.documentElement.getAttribute(\"data-theme\")?\"light\":\"dark\";document.documentElement.setAttribute(\"data-theme\",e),localStorage.setItem(\"theme\",e),G.textContent=\"dark\"===e?\"dark_mode\":\"light_mode\"}),n.addEventListener(\"click\",()=>{\"this-week\"!==c&&(c=\"this-week\",n.classList.add(\"active\"),a.classList.remove(\"active\"),z())}),a.addEventListener(\"click\",()=>{a.classList.remove(\"new-week-available\"),\"next-week\"!==c&&(c=\"next-week\",a.classList.add(\"active\"),n.classList.remove(\"active\"),z())}),s.addEventListener(\"click\",()=>{d?M():k.classList.remove(\"hidden\")}),r.addEventListener(\"click\",()=>{k.classList.remove(\"hidden\"),document.getElementById(\"login-error\").classList.add(\"hidden\"),g.reset()}),i.addEventListener(\"click\",()=>{k.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===k&&k.classList.add(\"hidden\")}),g.addEventListener(\"submit\",async n=>{n.preventDefault();const a=document.getElementById(\"employee-id\").value.trim(),s=document.getElementById(\"password\").value,o=document.getElementById(\"login-error\"),r=g.querySelector('button[type=\"submit\"]'),i=r.textContent;r.disabled=!0,r.textContent=\"Wird eingeloggt...\";try{const n=`knapp-${a}@bessa.app`,r=await fetch(`${e}/auth/login/`,{method:\"POST\",headers:f(t),body:JSON.stringify({email:n,password:s})}),i=await r.json();if(r.ok){d=i.key,m=a,localStorage.setItem(\"kantine_authToken\",i.key),localStorage.setItem(\"kantine_currentUser\",a);try{const t=await fetch(`${e}/auth/user/`,{headers:f(d)});if(t.ok){const e=await t.json();e.first_name&&localStorage.setItem(\"kantine_firstName\",e.first_name),e.last_name&&localStorage.setItem(\"kantine_lastName\",e.last_name)}}catch(e){console.error(\"Failed to fetch user info:\",e)}v(),k.classList.add(\"hidden\"),y(),g.reset(),I(),M()}else o.textContent=i.non_field_errors?.[0]||i.error||\"Login fehlgeschlagen\",o.classList.remove(\"hidden\")}catch(e){console.error(\"Login error:\",e),o.textContent=\"Ein Fehler ist aufgetreten\",o.classList.remove(\"hidden\")}finally{r.disabled=!1,r.textContent=i}}),l.addEventListener(\"click\",()=>{localStorage.removeItem(\"kantine_authToken\"),localStorage.removeItem(\"kantine_currentUser\"),localStorage.removeItem(\"kantine_firstName\"),localStorage.removeItem(\"kantine_lastName\"),d=null,m=null,u=new Map,h&&(clearInterval(h),h=null,console.log(\"Polling stopped\")),v(),z()})}(),v(),function(){const e=new Date,t=e.toISOString().split(\"T\")[0];let n=!1;for(const a of[...g]){const[s]=a.split(\"_\");let o=!1;if(s=t&&(o=!0)}o&&(g.delete(a),n=!0)}n&&k()}();(function(){try{const e=localStorage.getItem(C),t=localStorage.getItem(D);if(console.log(`[Cache] localStorage: key=${!!e} (${e?e.length:0} chars), ts=${t}`),e){r=JSON.parse(e),i=U(new Date),l=(new Date).getFullYear(),console.log(`[Cache] Parsed ${r.length} weeks:`,r.map(e=>`KW${e.weekNumber}/${e.year} (${(e.days||[]).length} days)`)),z(),$(),A(),t&&q(t);try{const e=new Set;r.forEach(t=>{(t.days||[]).forEach(t=>{(t.items||[]).forEach(t=>{let n=(t.description||\"\").replace(/\\s+/g,\" \").trim();n&&n.includes(\" / \")&&e.add(n)})})});const t=Array.from(e).join(\"\\n\\n\");console.log(\"=== GEFUNDENE MEN\u00dc-TEXTE (\"+e.size+\") ===\"),console.log(t)}catch(e){}return console.log(\"Loaded menu from cache\"),!0}}catch(e){console.warn(\"Failed to load cached menu:\",e)}return!1})()?(document.getElementById(\"loading\").classList.add(\"hidden\"),!function(){const e=localStorage.getItem(D);if(!e)return console.log(\"[Cache] No timestamp found\"),!1;const t=Date.now()-new Date(e).getTime(),n=Math.round(t/6e4);if(t>36e5)return console.log(`[Cache] Stale: ${n}min old (max 60)`),!1;const a=U(new Date),s=G(new Date),o=r.some(e=>e.weekNumber===a&&e.year===s&&e.days&&e.days.length>0);return console.log(`[Cache] Age: ${n}min, looking for KW${a}/${s}, found: ${o}`),o}()?(console.log(\"Cache stale or incomplete \u2013 refreshing from API\"),M()):console.log(\"Cache fresh & complete \u2013 skipping API refresh\")):M(),d&&I(),K(),setInterval(K,36e5),console.log(\"Kantine Wrapper loaded \u2705\")}();\n"; document.head.appendChild(sc); })();
+javascript:javascript:(function(){ if(window.__KANTINE_LOADED){alert('Kantine Wrapper already loaded!');return;} var s=document.createElement('style');s.textContent=':root { /* Premium Slate/Gray-Blue Palette - Light Mode */ --bg-body: #f1f5f9; /* Slate 100 */ --bg-card: #ffffff; --text-primary: #334155; /* Slate 700 */ --text-secondary: #64748b; --accent-color: #0f172a; /* Slate 900 (High contrast) */ --border-color: #cbd5e1; /* Slate 300 */ --banner-bg: #e2e8f0; --banner-text: #1e293b; --success-color: #059669; --error-color: #dc2626; --card-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05); --header-bg: rgba(255, 255, 255, 0.9); --header-border: 1px solid rgba(203, 213, 225, 0.6); } [data-theme="dark"] { /* Premium Slate/Gray-Blue Palette - Dark Mode */ --bg-body: #1e293b; /* Deep Slate Gray (Requested) */ --bg-card: #334155; /* Slate 700 */ --text-primary: #f8fafc; /* Slate 50 */ --text-secondary: #cbd5e1; /* Slate 300 */ --accent-color: #60a5fa; /* Blue 400 */ --border-color: #475569; /* Slate 600 */ --banner-bg: #475569; --banner-text: #e2e8f0; --header-bg: rgba(30, 41, 59, 0.9); --header-border: 1px solid rgba(71, 85, 105, 0.6); --card-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.4); } * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: \'Inter\', system-ui, -apple-system, sans-serif; background-color: var(--bg-body); color: var(--text-primary); transition: background-color 0.3s ease, color 0.3s ease; line-height: 1.5; -webkit-font-smoothing: antialiased; } /* Fix scrolling bug: Reset html/body styles from host page */ /* IMPORTANT: html must NOT have overflow set, or it creates a scroll container that breaks position: sticky */ html { height: auto !important; min-height: 100% !important; overflow: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } body { height: auto !important; min-height: 100% !important; overflow-x: clip !important; /* clip prevents horizontal overflow without breaking sticky */ overflow-y: visible !important; position: static !important; margin: 0 !important; padding: 0 !important; } /* Header */ .app-header { flex-shrink: 0; z-index: 100; backdrop-filter: blur(12px); background-color: var(--header-bg); border-bottom: var(--header-border); padding: 1rem 0; } .header-content { width: 100%; /* Full width */ padding: 0 2rem; /* Comfortable padding */ display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 1rem; } .brand { display: flex; align-items: center; gap: 0.75rem; } .brand-text { display: flex; flex-direction: column; } .brand h1 { font-size: 1.25rem; font-weight: 700; letter-spacing: -0.025em; margin-bottom: 0; } .subtitle { font-size: 0.85rem; color: var(--text-secondary); font-weight: 400; margin-left: 2px; } .logo-icon { font-size: 1.5rem; color: var(--accent-color); } /* Controls */ .controls { display: flex; align-items: center; gap: 1.5rem; justify-self: end; } /* Header Week Info (centered) */ .header-week-info { text-align: center; line-height: 1.3; } .header-center-wrapper { display: flex; flex-direction: row; align-items: center; gap: 1.5rem; justify-content: center; } .header-week-title { font-size: 1.1rem; font-weight: 600; color: var(--text-primary); } .header-week-subtitle { font-size: 0.85rem; color: var(--text-secondary); } /* Language Toggle (FR-100) */ .lang-toggle { display: inline-flex; gap: 0; border-radius: 6px; overflow: hidden; border: 1px solid var(--border-color); background: var(--bg-card); } .lang-btn { padding: 3px 10px; font-size: 0.7rem; font-weight: 600; letter-spacing: 0.03em; background: transparent; color: var(--text-secondary); border: none; cursor: pointer; transition: all 0.2s; } .lang-btn:hover { color: var(--text-primary); background: rgba(100, 116, 139, 0.1); } .lang-btn.active { background: var(--accent-color); color: white; } .nav-group { display: flex; background-color: var(--bg-card); border: 1px solid var(--border-color); padding: 0.25rem; border-radius: 8px; } .nav-btn { background: none; border: none; padding: 0.5rem 1rem; font-size: 0.875rem; font-weight: 500; color: var(--text-secondary); cursor: pointer; border-radius: 6px; transition: all 0.2s; display: flex; align-items: center; gap: 0.5rem; } .nav-btn:hover { color: var(--text-primary); background-color: rgba(100, 116, 139, 0.1); } .nav-btn.active { background-color: var(--accent-color); color: white; } /* Notification state for Next Week */ .nav-btn.new-week-available { animation: goldPulse 2s infinite; border-color: #f59e0b; color: var(--accent-color); } .nav-btn.new-week-available.active { color: white; } @keyframes goldPulse { 0% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7); } 70% { box-shadow: 0 0 0 10px rgba(245, 158, 11, 0); } 100% { box-shadow: 0 0 0 0 rgba(245, 158, 11, 0); } } /* Badge for nav buttons (day count indicator) */ .nav-badge { background-color: var(--error-color); color: white; font-size: 0.75rem; font-weight: 600; padding: 0 6px; border-radius: 10px; min-width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; gap: 3px; line-height: 1; } .nav-badge .orderable { color: #fff; font-weight: 800; } .nav-badge .separator { opacity: 0.6; font-weight: 400; } .nav-badge .total { opacity: 0.8; font-weight: 400; } .nav-btn.active .nav-badge { background: rgba(255, 255, 255, 0.3); } /* Primary style for Login Button to match header */ #btn-login-open { background-color: var(--accent-color); color: white; padding: 0.5rem 1.25rem; border-radius: 8px; font-weight: 600; letter-spacing: 0.025em; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } #btn-login-open:hover { background-color: #334155; /* Slightly lighter than slate-900 */ transform: translateY(-1px); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } /* User Badge Button (Login) */ .user-badge-btn { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); border: 1px solid var(--border-color); border-radius: 20px; font-size: 0.9rem; font-weight: 500; color: var(--text-primary); cursor: pointer; transition: all 0.2s; } .user-badge-btn:hover { background: rgba(100, 116, 139, 0.1); border-color: var(--accent-color); } .user-badge-btn .material-icons-round { font-size: 1.25rem; color: var(--accent-color); } .icon-btn { background: none; border: none; color: var(--text-primary); cursor: pointer; padding: 0.5rem; border-radius: 50%; transition: background-color 0.2s; display: flex; align-items: center; justify-content: center; } .icon-btn:hover { background-color: rgba(100, 116, 139, 0.1); } /* Refresh button animation */ #btn-refresh.refreshing .material-icons-round { animation: rotate 1s linear infinite; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } /* Progress Modal */ .progress-container { margin-bottom: 1.5rem; } .progress-bar { width: 100%; height: 8px; background-color: var(--border-color); border-radius: 4px; overflow: hidden; margin-bottom: 0.75rem; } .progress-fill { height: 100%; background: linear-gradient(90deg, var(--accent-color) 0%, #60a5fa 100%); width: 0%; transition: width 0.3s ease; border-radius: 4px; } .progress-percent { text-align: center; font-size: 1.5rem; font-weight: 700; color: var(--text-primary); margin-bottom: 0.5rem; } .progress-message { text-align: center; color: var(--text-secondary); font-size: 0.9rem; font-weight: 500; } .weekly-cost { background-color: rgba(59, 130, 246, 0.1); /* Blue tint */ color: var(--accent-color); padding: 0.4rem 0.8rem; border-radius: 8px; font-weight: 600; font-size: 0.9rem; display: flex; align-items: center; gap: 0.5rem; border: 1px solid rgba(59, 130, 246, 0.2); } .weekly-cost .material-icons-round { font-size: 18px; } /* Container - flex column, full width so child scrollbar is at edge */ .container { flex: 1; width: 100%; overflow: hidden; padding: 0 0 0 0; /* Only top padding, no horizontal so child fills width */ display: flex; flex-direction: column; } /* Add horizontal padding to direct children of container to maintain layout */ .container>*:not(.menu-grid) { padding-left: 2rem; padding-right: 2rem; } /* Banner */ .banner { background-color: var(--banner-bg); color: var(--banner-text); padding: 0.75rem 1rem; border-radius: 8px; display: flex; align-items: center; gap: 0.5rem; margin-bottom: 2rem; font-size: 0.875rem; font-weight: 500; border: 1px solid var(--border-color); max-width: fit-content; } /* User Badge */ .user-badge { display: flex; align-items: center; gap: 8px; padding: 6px 12px; background: var(--bg-card); /* Changed from --surface */ border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 20px; font-size: 0.9rem; font-weight: 500; } .icon-btn-small { background: none; border: none; padding: 4px; cursor: pointer; color: var(--text-secondary); /* Changed from --text-muted */ display: flex; align-items: center; justify-content: center; border-radius: 50%; transition: all 0.2s; } .icon-btn-small:hover { color: var(--error-color); /* Changed from --danger */ background: rgba(239, 68, 68, 0.1); } /* Modal */ .modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; z-index: 1000; transition: all 0.3s; } .modal.hidden { opacity: 0; pointer-events: none; } .modal-content { background: var(--bg-card); width: 90%; max-width: 400px; border-radius: 16px; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); overflow: hidden; animation: modalSlide 0.3s ease-out; } /* History Modal specific */ .history-modal-content { max-width: 600px; max-height: 85vh; display: flex; flex-direction: column; } .history-modal-content .modal-body { overflow-y: auto; padding: 0; /* Padding is handled by inner elements */ } /* History Styles */ .history-year-group { margin-bottom: 16px; } .history-year-header { background: var(--bg-card); padding: 12px 20px; margin: 0; font-size: 1.2rem; font-weight: 700; color: var(--text-primary); border-bottom: 2px solid var(--border-color); position: sticky; top: 0; z-index: 12; } .history-month-group { border-bottom: 1px solid var(--border-color); } .history-month-header { display: flex; justify-content: space-between; align-items: center; padding: 14px 20px; margin: 0; font-size: 1.05rem; font-weight: 600; color: var(--text-primary); background: var(--bg-body); cursor: pointer; transition: background 0.2s; } .history-month-header:hover { background: var(--border-color); /* Slight hover effect */ } .history-month-summary { display: flex; align-items: center; gap: 12px; font-size: 0.95rem; color: var(--text-secondary); } .history-month-content { display: none; /* Collapsed by default */ background: var(--bg-card); } .history-month-group.open .history-month-content { display: block; /* Expanded when open class is present */ } .history-month-group.open .history-month-header .material-icons-round { transform: rotate(180deg); } .history-month-header .material-icons-round { transition: transform 0.3s; font-size: 20px; } .history-week-group { padding: 12px 20px; border-bottom: 1px dashed var(--border-color); } .history-week-group:last-child { border-bottom: none; } .history-week-header { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; font-weight: 600; color: var(--text-secondary); margin-bottom: 10px; } .history-week-summary { font-size: 0.85rem; font-weight: 500; background: rgba(100, 116, 139, 0.1); padding: 4px 10px; border-radius: 12px; } .history-items { display: flex; flex-direction: column; gap: 8px; } .history-item { display: grid; grid-template-columns: 50px 1fr auto; align-items: center; gap: 12px; padding: 10px 12px; background: var(--bg-body); border-radius: 8px; border: 1px solid var(--border-color); } .history-item-date { font-size: 0.85rem; color: var(--text-secondary); font-weight: 500; } .history-item-details { display: flex; flex-direction: column; gap: 4px; } .history-item-name { font-size: 0.95rem; font-weight: 500; color: var(--text-primary); } .history-item-price { font-weight: 600; color: var(--text-primary); } .history-item-status { font-size: 0.8rem; font-weight: 600; color: var(--text-primary); text-transform: uppercase; letter-spacing: 0.5px; } .history-item-cancelled { opacity: 0.5; filter: grayscale(1); } .history-item-price-cancelled { text-decoration: line-through; color: var(--text-secondary); } @keyframes modalSlide { from { transform: translateY(20px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px; border-bottom: 1px solid var(--border-color); } .modal-header h2 { margin: 0; font-size: 1.25rem; } .modal-body { padding: 20px; } #login-form { padding: 20px; } .form-group { margin-bottom: 20px; } .form-group label { display: block; margin-bottom: 6px; font-weight: 500; font-size: 0.9rem; } .form-group input { width: 100%; padding: 10px 12px; border: 1px solid var(--border-color); /* Changed from --border */ border-radius: 8px; background: var(--bg-body); /* Changed from --bg */ color: var(--text-primary); /* Changed from --text */ font-family: inherit; transition: border-color 0.2s; } .form-group input:focus { outline: none; border-color: var(--accent-color); /* Changed from --primary */ } .help-text { display: block; margin-top: 4px; color: var(--text-secondary); /* Changed from --text-muted */ font-size: 0.75rem; } .error-msg { margin-bottom: 16px; padding: 10px; background: rgba(239, 68, 68, 0.1); color: var(--error-color); /* Changed from --danger */ border-radius: 8px; font-size: 0.85rem; text-align: center; } .modal-actions { margin-top: 24px; } .btn-primary.wide { width: 100%; justify-content: center; } .hidden { display: none !important; } /* Menu Grid Container */ .menu-grid { display: flex; flex-direction: column; flex: 1; overflow: hidden; gap: 1rem; } .week-section { margin-bottom: 2rem; } .week-header { margin-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); padding-bottom: 1rem; text-align: center; } .week-title { font-size: 1.75rem; font-weight: 700; color: var(--text-primary); } .week-range { color: var(--text-secondary); font-size: 0.9rem; margin-top: 0.25rem; } /* Full-viewport layout: header + scrollable content + footer */ #kantine-wrapper { display: flex; flex-direction: column; height: 100vh; height: 100dvh; /* Dynamic viewport height for mobile browsers */ overflow: hidden; } .days-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0.75rem; flex: 1; overflow-y: auto; /* This is the scroll container at the window edge */ align-content: start; padding: 0 2rem 2rem 2rem; } /* Card */ .menu-card { background-color: var(--bg-card); border-radius: 12px; border: 1px solid var(--border-color); box-shadow: var(--card-shadow); overflow: clip; /* Clips scrolling content behind sticky header */ transition: box-shadow 0.2s ease; display: flex; flex-direction: column; } /* Past Day Styling - Target specific elements so ordered items can remain visible AND preserve sticky context */ /* We MUST apply filter/opacity to children, not the parent .menu-card, or else position: sticky breaks */ /* Header keeps fully opaque background to hide scrolling items, only grayscales */ .menu-card.past-day .card-header { filter: grayscale(0.8); transition: filter 0.3s; } /* Items become semi-transparent */ .menu-card.past-day .menu-item:not(.ordered) { opacity: 0.6; filter: grayscale(0.8); transition: opacity 0.3s, filter 0.3s; } .menu-card.past-day:hover .card-header { filter: grayscale(0.4); } .menu-card.past-day:hover .menu-item:not(.ordered) { opacity: 0.8; filter: grayscale(0.4); } /* Past ordered items get no special frame or shadow, but remain visually distinct by staying fully opaque (via the :not(.ordered) selector above) */ .menu-item.today-ordered { border: 2px solid #8b5cf6; box-shadow: 0 0 30px rgba(139, 92, 246, 0.6); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: pulse-glow-strong 3s infinite; } @keyframes pulse-glow-strong { 0% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } 50% { box-shadow: 0 0 40px rgba(139, 92, 246, 0.8); } 100% { box-shadow: 0 0 20px rgba(139, 92, 246, 0.4); } } .menu-card:hover { box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1); } .card-header { padding: 1rem 1.25rem; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: baseline; background-color: var(--bg-card); /* Removed border-radius: 12px 12px 0 0; .menu-card\'s overflow: clip will round the corners initially. When sticky at the top, it will be square and perfectly hide scrolling content! */ /* Sticky within .container scroll area */ position: sticky; top: 0; z-index: 90; } .card-body { padding: 1.25rem; display: grid; grid-template-rows: auto; align-content: start; } .day-name { font-size: 1.125rem; font-weight: 600; } .day-date { font-size: 0.875rem; color: var(--text-secondary); } .empty-state { color: var(--text-secondary); font-style: italic; text-align: center; padding: 1rem; } /* Menu Items */ .menu-item { margin-bottom: 1.5rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--border-color); } .menu-item:last-child { margin-bottom: 0; padding-bottom: 0; border-bottom: none; } .item-header { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.5rem; gap: 1rem; } .item-name { font-weight: 600; color: var(--text-primary); font-size: 1rem; } .item-price { font-weight: 700; color: var(--accent-color); white-space: nowrap; } .item-desc { font-size: 0.875rem; color: var(--text-secondary); line-height: 1.6; margin-bottom: 0.75rem; white-space: pre-wrap; } .badges { display: flex; gap: 0.5rem; margin-left: auto; } .item-status-row { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.75rem; } .badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; } .badge.available { background-color: rgba(16, 185, 129, 0.1); /* Emerald 500 / 10% */ color: var(--success-color); border: 1px solid rgba(16, 185, 129, 0.2); } .badge.sold-out { background-color: rgba(239, 68, 68, 0.1); /* Red 500 / 10% */ color: var(--error-color); border: 1px solid rgba(239, 68, 68, 0.2); } .badge.ordered { background-color: rgba(139, 92, 246, 0.1); /* Violet 500 / 10% */ color: #8b5cf6; border: 1px solid rgba(139, 92, 246, 0.2); gap: 4px; } .badge.ordered .material-icons-round { font-size: 1rem; } /* Loading */ .loading-state { text-align: center; padding: 4rem; color: var(--text-secondary); } .spinner { width: 40px; height: 40px; border: 3px solid var(--border-color); border-top-color: var(--accent-color); border-radius: 50%; margin: 0 auto 1rem; animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } /* Footer */ .app-footer { flex-shrink: 0; text-align: center; padding: 0.4rem 2rem; color: var(--text-secondary); font-size: 0.8rem; border-top: 1px solid var(--border-color); } /* === Order / Cancel Buttons (inline in status row) === */ .btn-order { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border: none; border-radius: 6px; background: var(--success-color); color: white; font-size: 0.75rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-order .material-icons-round { font-size: 16px; } .btn-order:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-order:disabled { opacity: 0.5; cursor: not-allowed; } .btn-order.loading { pointer-events: none; opacity: 0.6; } .btn-order-compact { padding: 2px 4px; gap: 0; } .btn-order-compact .material-icons-round { font-size: 16px; } .btn-cancel { display: inline-flex; align-items: center; justify-content: center; padding: 4px 6px; border: none; border-radius: 6px; background: var(--error-color); color: white; font-size: 0.75rem; cursor: pointer; transition: all 0.2s ease; font-family: inherit; } .btn-cancel .material-icons-round { font-size: 16px; } .btn-cancel:hover:not(:disabled) { filter: brightness(1.15); transform: translateY(-1px); } .btn-cancel:disabled { opacity: 0.5; cursor: not-allowed; } /* Past days: hide action buttons */ .past-day .item-actions { display: none; } /* Order count badge (for multi-orders) */ .order-count-badge { display: inline-flex; align-items: center; justify-content: center; background: rgba(255, 255, 255, 0.3); color: white; font-size: 0.65rem; font-weight: 700; min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; margin-left: 4px; line-height: 1; } /* === Toast Notifications === */ #toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 10000; display: flex; flex-direction: column; gap: 8px; pointer-events: none; } .toast { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 8px; font-size: 0.85rem; font-weight: 500; font-family: \'Inter\', sans-serif; color: white; backdrop-filter: blur(10px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); pointer-events: auto; transform: translateX(120%); opacity: 0; transition: transform 0.3s ease, opacity 0.3s ease; } .toast.show { transform: translateX(0); opacity: 1; } .toast .material-icons-round { font-size: 18px; } .toast-success { background: rgba(5, 150, 105, 0.95); } .toast-error { background: rgba(220, 38, 38, 0.95); } .toast-info { background: rgba(59, 130, 246, 0.95); } /* === Mobile Responsiveness === */ @media (max-width: 600px) { .header-content { flex-direction: column; gap: 1rem; padding: 0.75rem; } .week-nav { width: 100%; justify-content: center; } .nav-pills { width: 100%; justify-content: space-between; } .nav-btn { flex: 1; justify-content: center; padding: 0.5rem; font-size: 0.85rem; } .days-grid { grid-template-columns: 1fr; /* Force single column */ } .main-content { padding: 1rem; } .week-title { font-size: 1.5rem; } /* Adjust toast position for mobile */ .toast-container { bottom: 1rem; right: 1rem; left: 1rem; /* Center on mobile */ width: auto; } .menu-card { margin-bottom: 1rem; } } /* === Flagging & Notification Styles === */ .btn-flag { display: inline-flex; align-items: center; justify-content: center; background: transparent; border: 1px solid var(--text-secondary); color: var(--text-secondary); border-radius: 6px; padding: 4px; cursor: pointer; transition: all 0.2s; margin-right: 0.5rem; width: 28px; height: 28px; } .btn-flag:hover { background: rgba(234, 179, 8, 0.1); /* Yellow-500 / 10% */ color: #eab308; border-color: #eab308; } .btn-flag.active { background: rgba(234, 179, 8, 0.1); color: #eab308; border-color: #eab308; } .btn-flag .material-icons-round { font-size: 1.1rem; } /* Flagged & Sold Out (Yellow Glow) */ .menu-item.flagged-sold-out { border: 1px solid #eab308; box-shadow: 0 0 10px rgba(234, 179, 8, 0.2); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: yellow-pulse 3s infinite; } @keyframes yellow-pulse { 0% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } 50% { box-shadow: 0 0 16px rgba(234, 179, 8, 0.5); } 100% { box-shadow: 0 0 8px rgba(234, 179, 8, 0.2); } } /* Flagged & Available (Green Glow) */ .menu-item.flagged-available { border: 2px solid var(--success-color); box-shadow: 0 0 15px rgba(16, 185, 129, 0.3); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: green-pulse 3s infinite; } @keyframes green-pulse { 0% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } 50% { box-shadow: 0 0 20px rgba(16, 185, 129, 0.6); } 100% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); } } /* Day Header Badges */ .day-header-left { display: flex; align-items: center; gap: 0.75rem; } .menu-code-badge { font-size: 0.75rem; font-weight: 700; color: #8b5cf6; /* Violet 500 */ background-color: rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.3); padding: 2px 6px; border-radius: 6px; line-height: normal; display: inline-block; } /* Detailed Badge Colors */ .nav-badge.badge-violet { background-color: #8b5cf6; } .nav-badge.badge-green { background-color: var(--success-color); } .nav-badge.badge-red { background-color: var(--error-color); } .nav-badge.badge-blue { background-color: var(--accent-color); } /* Day Header Status Colors (User Request) */ .card-header.header-violet { background-color: var(--bg-card); background-image: linear-gradient(rgba(139, 92, 246, 0.15), rgba(139, 92, 246, 0.15)); border-bottom: 2px solid #8b5cf6; } .card-header.header-green { background-color: var(--bg-card); background-image: linear-gradient(rgba(16, 185, 129, 0.15), rgba(16, 185, 129, 0.15)); border-bottom: 2px solid var(--success-color); } .card-header.header-red { background-color: var(--bg-card); background-image: linear-gradient(rgba(239, 68, 68, 0.15), rgba(239, 68, 68, 0.15)); border-bottom: 2px solid var(--error-color); } .card-header.header-violet .day-name, .card-header.header-green .day-name, .card-header.header-red .day-name { font-weight: 700; color: var(--text-primary); /* Ensure text remains standard color */ } /* Update Icon */ .update-icon { display: inline-flex; align-items: center; justify-content: center; margin-left: 8px; background-color: rgba(16, 185, 129, 0.2); /* Green tint */ color: var(--success-color); border-radius: 50%; width: 24px; height: 24px; cursor: pointer; font-size: 14px; transition: all 0.2s; text-decoration: none; animation: pulse 2s infinite; } .update-icon:hover { background-color: var(--success-color); color: white; transform: scale(1.1); } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); } 100% { box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); } } /* Order Countdown */ #order-countdown { background: rgba(255, 255, 255, 0.1); padding: 0.25rem 0.75rem; border-radius: 99px; font-size: 0.85rem; display: flex; align-items: center; gap: 0.5rem; white-space: nowrap; border: 1px solid var(--border-color); } #order-countdown span { opacity: 0.7; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; } #order-countdown.urgent { background: rgba(239, 68, 68, 0.2); border-color: rgba(239, 68, 68, 0.5); color: #ef4444; animation: pulse-red 2s infinite; } @keyframes pulse-red { 0% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); } 70% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); } 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); } } /* Smart Highlights (Blue Glow - matches today-ordered/flagged pattern) */ .menu-item.highlight-glow { border: 2px solid rgba(59, 130, 246, 0.7); box-shadow: 0 0 20px rgba(59, 130, 246, 0.4); border-radius: 8px; padding: 1rem; margin: 0 -1rem 1.5rem -1rem; background: var(--bg-card); position: relative; z-index: 5; animation: blue-pulse 3s infinite; } @keyframes blue-pulse { 0% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } 50% { box-shadow: 0 0 25px rgba(59, 130, 246, 0.6); } 100% { box-shadow: 0 0 15px rgba(59, 130, 246, 0.3); } } /* Nav Badge with Count */ .nav-badge.has-highlights { background-color: var(--bg-card); /* Neutral background */ color: var(--text-primary); border: 1px solid var(--border-color); padding: 2px 6px; } .nav-badge .highlight-count { color: #3b82f6; /* Blue 500 */ font-weight: 700; margin-left: 4px; } /* Tag Management Modal */ #tags-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; min-height: 50px; } /* Tag badges styled consistently with .badge (verfügbar/ausverkauft) */ .tag-badge { display: inline-flex; align-items: center; justify-content: center; height: 24px; font-size: 0.75rem; padding: 0 10px; border-radius: 4px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; line-height: normal; white-space: nowrap; background-color: rgba(59, 130, 246, 0.1); color: #3b82f6; border: 1px solid rgba(59, 130, 246, 0.2); gap: 4px; } .tag-remove { cursor: pointer; opacity: 0.7; font-size: 1.1em; line-height: 1; transition: all 0.2s; } .tag-remove:hover { opacity: 1; color: #ef4444; } .input-group { display: flex; gap: 0.5rem; } .input-group input { flex: 1; padding: 0.75rem; background: var(--bg-body); border: 1px solid var(--border-color); color: var(--text-primary); border-radius: 8px; font-family: inherit; } /* Add tag button - styled like .btn-order with nav-btn.active color */ #btn-add-tag { display: inline-flex; align-items: center; gap: 4px; padding: 0.5rem 1rem; border: none; border-radius: 6px; background: var(--accent-color); color: white; font-size: 0.8rem; font-weight: 600; cursor: pointer; transition: all 0.2s ease; font-family: inherit; white-space: nowrap; } #btn-add-tag:hover { filter: brightness(1.15); transform: translateY(-1px); } .matched-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; /* Space between tags and title */ margin-top: -5px; /* Pull closer to header */ } .tag-badge-small { display: inline-flex; align-items: center; font-size: 0.7rem; padding: 2px 8px; border-radius: 4px; background: rgba(59, 130, 246, 0.15); color: #60a5fa; border: 1px solid rgba(59, 130, 246, 0.3); font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; } [data-theme="light"] .tag-badge-small { background: rgba(37, 99, 235, 0.1); color: #2563eb; border: 1px solid rgba(37, 99, 235, 0.2); } /* Installer Changelog */ .changelog-container ul { padding-left: 1.5rem; margin: 0.5rem 0; } .changelog-container li { margin-bottom: 0.4rem; line-height: 1.5; } .changelog-container h3 { margin-top: 1.5rem; margin-bottom: 0.5rem; font-size: 1.1em; color: var(--accent-color); } /* === Version Menu === */ .version-tag { cursor: pointer; transition: opacity 0.2s ease, text-decoration 0.2s ease; } .version-tag:hover { opacity: 1 !important; text-decoration: underline; } .version-list { list-style: none; padding: 0; margin: 0; } .version-item { display: flex; justify-content: space-between; align-items: center; padding: 10px 14px; border-radius: 8px; margin-bottom: 4px; transition: background 0.2s; } .version-item:hover { background: rgba(100, 116, 139, 0.08); } .version-item.current { background: rgba(2, 154, 168, 0.1); border: 1px solid rgba(2, 154, 168, 0.25); } [data-theme="dark"] .version-item:hover { background: rgba(255, 255, 255, 0.05); } [data-theme="dark"] .version-item.current { background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } .version-info { display: flex; align-items: center; gap: 10px; } .badge-current { font-size: 0.75rem; font-weight: 600; color: var(--success-color); padding: 2px 8px; border-radius: 4px; background: rgba(5, 150, 105, 0.1); } .badge-new { font-size: 0.75rem; font-weight: 600; color: #029aa8; padding: 2px 8px; border-radius: 4px; background: rgba(2, 154, 168, 0.1); } [data-theme="dark"] .badge-new { color: #60a5fa; background: rgba(96, 165, 250, 0.12); } .install-link { font-size: 0.8rem; font-weight: 500; padding: 4px 12px; border-radius: 6px; background: rgba(2, 154, 168, 0.1); color: #029aa8; text-decoration: none; border: 1px solid rgba(2, 154, 168, 0.25); transition: all 0.2s; white-space: nowrap; } .install-link:hover { background: rgba(2, 154, 168, 0.2); border-color: rgba(2, 154, 168, 0.4); } [data-theme="dark"] .install-link { color: #60a5fa; background: rgba(96, 165, 250, 0.12); border: 1px solid rgba(96, 165, 250, 0.25); } [data-theme="dark"] .install-link:hover { background: rgba(96, 165, 250, 0.2); border-color: rgba(96, 165, 250, 0.4); } .dev-toggle { padding: 10px 14px; border-radius: 8px; background: rgba(100, 116, 139, 0.05); border: 1px solid var(--border-color); } .dev-toggle input[type="checkbox"] { accent-color: #029aa8; width: 16px; height: 16px; } [data-theme="dark"] .dev-toggle input[type="checkbox"] { accent-color: #60a5fa; } ';document.head.appendChild(s); // Inject JS logic var sc=document.createElement('script'); sc.textContent="function showErrorModal(e,t,n,a){const s=\"error-modal\";let o=document.getElementById(s);o&&o.remove(),o=document.createElement(\"div\"),o.id=s,o.className=\"modal hidden\",o.innerHTML=`\\n \\n \\n
\\n
${t}
\\n
\\n \\n ${n}\\n open_in_new \\n \\n
\\n
\\n
\\n `,document.body.appendChild(o),document.getElementById(\"btn-error-redirect\").addEventListener(\"click\",()=>{window.location.href=a}),requestAnimationFrame(()=>{o.classList.remove(\"hidden\")})}!function(){\"use strict\";if(window.__KANTINE_LOADED)return;window.__KANTINE_LOADED=!0;const e=\"https://api.bessa.app/v1\",t=\"c3418725e95a9f90e3645cbc846b4d67c7c66131\",n=591,a=\"TauNeutrino/kantine-overview\",s=`https://api.github.com/repos/${a}`,o=`https://htmlpreview.github.io/?https://github.com/${a}/blob`;let r=[],i=U(new Date),l=(new Date).getFullYear(),c=\"this-week\",d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\"),u=new Map,g=new Set(JSON.parse(localStorage.getItem(\"kantine_flags\")||\"[]\")),h=null,p=localStorage.getItem(\"kantine_lang\")||\"de\";function f(e){return{Authorization:`Token ${e||t}`,Accept:\"application/json\",\"Content-Type\":\"application/json\",\"X-Client-Version\":\"1.7.0_prod/2026-01-26\"}}function v(){if(!d)try{const e=localStorage.getItem(\"AkitaStores\");if(e){const t=JSON.parse(e);t.auth&&t.auth.token&&(console.log(\"Found existing Bessa session!\"),d=t.auth.token,localStorage.setItem(\"kantine_authToken\",d),t.auth.user&&(m=t.auth.user.id||\"unknown\",localStorage.setItem(\"kantine_currentUser\",m),t.auth.user.firstName&&localStorage.setItem(\"kantine_firstName\",t.auth.user.firstName),t.auth.user.lastName&&localStorage.setItem(\"kantine_lastName\",t.auth.user.lastName)))}}catch(e){console.warn(\"Failed to parse AkitaStores:\",e)}d=localStorage.getItem(\"kantine_authToken\"),m=localStorage.getItem(\"kantine_currentUser\");const e=localStorage.getItem(\"kantine_firstName\"),t=document.getElementById(\"btn-login-open\"),n=document.getElementById(\"user-info\"),a=document.getElementById(\"user-id-display\");d?(t.classList.add(\"hidden\"),n.classList.remove(\"hidden\"),a.textContent=e||(m?`User ${m}`:\"Angemeldet\"),y()):(t.classList.remove(\"hidden\"),n.classList.add(\"hidden\"),a.textContent=\"\"),z()}async function y(){if(d)try{const t=await fetch(`${e}/user/orders/?venue=591&ordering=-created&limit=50`,{headers:f(d)}),n=await t.json();if(t.ok){u=new Map;const e=n.results||[];for(const t of e){if(9===t.order_state)continue;const e=t.date.split(\"T\")[0];for(const n of t.items||[]){const a=`${e}_${n.article}`;u.has(a)||u.set(a,[]),u.get(a).push(t.id)}}console.log(`Fetched ${e.length} orders, mapped active ones.`),z(),$()}}catch(e){console.error(\"Error fetching orders:\",e)}}let b=null;function w(e){const t=document.getElementById(\"history-content\");if(!e||0===e.length)return void(t.innerHTML='Keine Bestellungen gefunden.
');const n={};e.forEach(e=>{const t=new Date(e.date),a=t.getFullYear(),s=t.getMonth(),o=`${a}-${s.toString().padStart(2,\"0\")}`,r=t.toLocaleString(\"de-AT\",{month:\"long\"}),i=U(t);n[a]||(n[a]={year:a,months:{}}),n[a].months[o]||(n[a].months[o]={name:r,year:a,monthIndex:s,count:0,total:0,weeks:{}}),n[a].months[o].weeks[i]||(n[a].months[o].weeks[i]={label:`KW ${i}`,items:[],count:0,total:0});(e.items||[]).forEach(t=>{const s=parseFloat(t.price||e.total||0);n[a].months[o].weeks[i].items.push({date:e.date,name:t.name||\"Men\u00fc\",price:s,state:e.order_state}),9!==e.order_state&&(n[a].months[o].weeks[i].count++,n[a].months[o].weeks[i].total+=s,n[a].months[o].count++,n[a].months[o].total+=s)})});const a=Object.keys(n).sort((e,t)=>t-e);let s=\"\";a.forEach(e=>{const t=n[e];s+=`\\n `;Object.keys(t.months).sort((e,t)=>t.localeCompare(e)).forEach(e=>{const n=t.months[e];s+=`
\\n \\n
`;Object.keys(n.weeks).sort((e,t)=>parseInt(t)-parseInt(e)).forEach(e=>{const t=n.weeks[e];s+=`
\\n `,t.items.forEach(e=>{const t=new Date(e.date).toLocaleDateString(\"de-AT\",{weekday:\"short\",day:\"2-digit\",month:\"2-digit\"});let n=\"\";n=9===e.state?'
Storniert ':8===e.state?'
Abgeschlossen ':'
\u00dcbertragen ',s+=`\\n
\\n
${t}
\\n
\\n
${J(e.name)} \\n
${n}
\\n
\\n
\u20ac${e.price.toFixed(2)}
\\n
`}),s+=\"
\"}),s+=\"
\"}),s+=\"
\"}),t.innerHTML=s;t.querySelectorAll(\".history-month-header\").forEach(e=>{e.addEventListener(\"click\",()=>{const t=e.parentElement;t.classList.contains(\"open\")?(t.classList.remove(\"open\"),e.setAttribute(\"aria-expanded\",\"false\")):(t.classList.add(\"open\"),e.setAttribute(\"aria-expanded\",\"true\"))})})}function k(){localStorage.setItem(\"kantine_flags\",JSON.stringify([...g]))}function A(){const e=document.getElementById(\"alarm-bell\"),t=document.getElementById(\"alarm-bell-icon\");if(!e||!t)return;if(0===g.size)return e.classList.add(\"hidden\"),e.style.display=\"none\",t.style.color=\"var(--text-secondary)\",void(t.style.textShadow=\"none\");e.classList.remove(\"hidden\"),e.style.display=\"inline-flex\";let n=!1;for(const e of r)if(e.days){for(const t of e.days)if(t.items){for(const e of t.items)if(e.available&&g.has(e.id)){n=!0;break}if(n)break}if(n)break}let a=localStorage.getItem(\"kantine_last_updated\"),s=\"gerade eben\";a||(a=(new Date).toISOString(),localStorage.setItem(\"kantine_last_updated\",a));const o=new Date(a),i=Date.now()-o.getTime(),l=Math.floor(i/6e4);s=l<1?\"gerade eben\":l<60?`vor ${l} Min.`:`vor ${Math.floor(l/60)} Std.`,e.title=`Zuletzt gepr\u00fcft: ${s}`,n?(t.style.color=\"#10b981\",t.style.textShadow=\"0 0 10px rgba(16, 185, 129, 0.4)\"):(t.style.color=\"#f59e0b\",t.style.textShadow=\"0 0 10px rgba(245, 158, 11, 0.4)\")}function E(n,a,s,o){const i=`${n}_${a}`;let l=!1;g.has(i)?(g.delete(i),F(`Flag entfernt f\u00fcr ${s}`,\"success\")):(g.add(i),l=!0,F(`Benachrichtigung aktiviert f\u00fcr ${s}`,\"success\"),\"default\"===Notification.permission&&Notification.requestPermission()),k(),A(),z(),l&&async function(){if(0===g.size)return;const n=d||t,a=new Set;for(const e of g){const[t]=e.split(\"_\");a.add(t)}let s=!1;for(const t of a)try{const a=await fetch(`${e}/venues/591/menu/7/${t}/`,{headers:f(n)});if(!a.ok)continue;const o=(await a.json()).results||[];let i=[];for(const e of o)e.items&&Array.isArray(e.items)&&(i=i.concat(e.items));for(let e of r){if(!e.days)continue;let n=e.days.find(e=>e.date===t);n&&(n.items=i.map(e=>{const n=!1===e.amount_tracking,a=parseInt(e.available_amount)>0;return{id:`${t}_${e.id}`,articleId:e.id,name:e.name||\"Unknown\",description:e.description||\"\",price:parseFloat(e.price)||0,available:n||a,availableAmount:parseInt(e.available_amount)||0,amountTracking:!1!==e.amount_tracking}}),s=!0)}}catch(e){console.error(\"Error refreshing flag date\",t,e)}s&&(O(),q((new Date).toISOString()),A(),z())}()}function I(){h||d&&(h=setInterval(()=>async function(){if(0===g.size||!d)return;console.log(`Polling ${g.size} flagged items...`);for(const t of g){const[n,a]=t.split(\"_\"),s=parseInt(a);try{const t=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(d)});if(!t.ok)continue;const a=(await t.json()).results||[];let o=null;for(const e of a)if(e.items&&(o=e.items.find(e=>e.id===s||e.article===s),o))break;if(o){if(!1===o.amount_tracking||parseInt(o.available_amount)>0){const e=o.name||\"Unbekannt\";F(`${e} ist jetzt verf\u00fcgbar!`,\"success\"),\"granted\"===Notification.permission&&new Notification(\"Kantine Wrapper\",{body:`${e} ist jetzt verf\u00fcgbar!`,icon:\"\ud83c\udf7d\ufe0f\"}),M()}}}catch(e){console.error(`Poll error for ${t}:`,e),await new Promise(e=>setTimeout(e,200))}}}(),3e5),console.log(\"Polling started (every 5 min)\"))}let L=JSON.parse(localStorage.getItem(\"kantine_highlightTags\")||\"[]\");function S(){localStorage.setItem(\"kantine_highlightTags\",JSON.stringify(L)),z(),$()}function B(){const e=document.getElementById(\"tags-list\");e.innerHTML=\"\",L.forEach(t=>{const n=document.createElement(\"span\");n.className=\"tag-badge\",n.innerHTML=`${t} × `,e.appendChild(n)}),e.querySelectorAll(\".tag-remove\").forEach(e=>{e.addEventListener(\"click\",e=>{var t;t=e.target.dataset.tag,L=L.filter(e=>e!==t),S(),B()})})}function x(e){return e?(e=e.toLowerCase(),L.filter(t=>e.includes(t))):[]}const C=\"kantine_menuCache\",D=\"kantine_menuCacheTs\";function O(){try{localStorage.setItem(C,JSON.stringify(r)),localStorage.setItem(D,(new Date).toISOString())}catch(e){console.warn(\"Failed to cache menu data:\",e)}}async function M(){const n=document.getElementById(\"loading\"),a=document.getElementById(\"progress-modal\"),s=document.getElementById(\"progress-fill\"),o=document.getElementById(\"progress-percent\"),c=document.getElementById(\"progress-message\");n.classList.remove(\"hidden\");const m=d||t;try{a.classList.remove(\"hidden\"),c.textContent=\"Hole verf\u00fcgbare Daten...\",s.style.width=\"0%\",o.textContent=\"0%\";const t=await fetch(`${e}/venues/591/menu/dates/`,{headers:f(m)});if(!t.ok)throw new Error(`Failed to fetch dates: ${t.status}`);let n=(await t.json()).results||[];const d=new Date;d.setDate(d.getDate()-7);const u=d.toISOString().split(\"T\")[0];n=n.filter(e=>e.date>=u).sort((e,t)=>e.date.localeCompare(t.date)).slice(0,30);const g=n.length;c.textContent=`${g} Tage gefunden. Lade Details...`;const h=[];let p=0;for(const t of n){const n=t.date,a=Math.round((p+1)/g*100);s.style.width=`${a}%`,o.textContent=`${a}%`,c.textContent=`Lade Men\u00fc f\u00fcr ${n}...`;try{const a=await fetch(`${e}/venues/591/menu/7/${n}/`,{headers:f(m)});if(a.ok){const e=await a.json();0===p&&console.log(\"[Kantine Debug] Raw API response for\",n,\":\",JSON.stringify(e).substring(0,2e3));const s=e.results||[];let o=[];for(const e of s)e.items&&Array.isArray(e.items)&&(o=o.concat(e.items));o.length>0&&(0===p&&(console.log(\"[Kantine Debug] First item keys:\",Object.keys(o[0])),console.log(\"[Kantine Debug] First item:\",JSON.stringify(o[0]).substring(0,500))),h.push({date:n,menu_items:o,orders:t.orders||[]}))}}catch(e){console.error(`Failed to fetch details for ${n}:`,e)}p++,await new Promise(e=>setTimeout(e,100))}const y=new Map;r&&r.length>0&&r.forEach(e=>{const t=`${e.year}-${e.weekNumber}`;try{y.set(t,{year:e.year,weekNumber:e.weekNumber,days:e.days?e.days.map(e=>({...e,items:e.items?[...e.items]:[]})):[]})}catch(e){console.warn(\"Error hydrating week:\",e)}});for(const e of h){const t=new Date(e.date),n=U(t),a=G(t),s=`${a}-${n}`;y.has(s)||y.set(s,{year:a,weekNumber:n,days:[]});const o=y.get(s),r=t.toLocaleDateString(\"en-US\",{weekday:\"long\"}),i=new Date(e.date);i.setHours(10,0,0,0);const l={date:e.date,weekday:r,orderCutoff:i.toISOString(),items:e.menu_items.map(t=>{const n=!1===t.amount_tracking,a=parseInt(t.available_amount)>0;return{id:`${e.date}_${t.id}`,articleId:t.id,name:t.name||\"Unknown\",description:t.description||\"\",price:parseFloat(t.price)||0,available:n||a,availableAmount:parseInt(t.available_amount)||0,amountTracking:!1!==t.amount_tracking}})},c=o.days.findIndex(t=>t.date===e.date);c>=0?o.days[c]=l:o.days.push(l)}r=Array.from(y.values()).sort((e,t)=>e.year!==t.year?e.year-t.year:e.weekNumber-t.weekNumber),r.forEach(e=>{e.days&&e.days.sort((e,t)=>e.date.localeCompare(t.date))}),O(),q((new Date).toISOString()),i=U(new Date),l=(new Date).getFullYear(),v(),z(),$(),A(),c.textContent=\"Fertig!\",setTimeout(()=>a.classList.add(\"hidden\"),500)}catch(e){console.error(\"Error fetching menu:\",e),a.classList.add(\"hidden\"),showErrorModal(\"Keine Verbindung\",`Die Men\u00fcdaten konnten nicht geladen werden. M\u00f6glicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.${e.message} `,\"Zur Original-Seite\",\"https://web.bessa.app/knapp-kantine\")}finally{n.classList.add(\"hidden\")}}let N=null,T=null;function q(e){const t=document.getElementById(\"last-updated-subtitle\");if(e){N=e;try{const n=new Date(e),a=n.toLocaleTimeString(\"de-DE\",{hour:\"2-digit\",minute:\"2-digit\"}),s=n.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),o=function(e){const t=Date.now()-e.getTime(),n=Math.floor(t/6e4);if(n<1)return\"gerade eben\";if(1===n)return\"vor 1 min.\";if(n<60)return`vor ${n} min.`;const a=Math.floor(n/60);return 1===a?\"vor 1 Std.\":`vor ${a} Std.`}(n);t.textContent=`Aktualisiert: ${s} ${a} (${o})`}catch(e){t.textContent=\"\"}T||(T=setInterval(()=>{N&&q(N)},6e4))}}function F(e,t=\"info\"){let n=document.getElementById(\"toast-container\");n||(n=document.createElement(\"div\"),n.id=\"toast-container\",document.body.appendChild(n));const a=document.createElement(\"div\");a.className=`toast toast-${t}`;const s=\"success\"===t?\"check_circle\":\"error\"===t?\"error\":\"info\";a.innerHTML=`${s} ${e} `,n.appendChild(a),requestAnimationFrame(()=>a.classList.add(\"show\")),setTimeout(()=>{a.classList.remove(\"show\"),setTimeout(()=>a.remove(),300)},3e3)}function $(){const e=document.getElementById(\"btn-next-week\");let t=i+1,n=l;t>52&&(t=1,n++);const a=r.find(e=>e.weekNumber===t&&e.year===n);let s=0,o=0,c=0,d=0;a&&a.days&&a.days.forEach(e=>{if(e.items&&e.items.length>0){s++;const t=e.items.some(e=>e.available);t&&o++;let n=!1;e.items.forEach(t=>{const a=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${a}`;u.has(s)&&u.get(s).length>0&&(n=!0)}),n&&c++,t&&!n&&d++}});let m=e.querySelector(\".nav-badge\");if(s>0){m||(m=document.createElement(\"span\"),m.className=\"nav-badge\",e.appendChild(m)),m.title=`${c} bestellt / ${o} bestellbar / ${s} gesamt`,m.innerHTML=`${c} / ${o} / ${s} `,m.classList.remove(\"badge-violet\",\"badge-green\",\"badge-red\",\"badge-blue\"),c>0&&0===d?m.classList.add(\"badge-violet\"):d>0?m.classList.add(\"badge-green\"):0===o?m.classList.add(\"badge-red\"):m.classList.add(\"badge-blue\");let r=0;if(a&&a.days&&a.days.forEach(e=>{e.items.forEach(e=>{const t=x(e.name),n=x(e.description);(t.length>0||n.length>0)&&r++})}),r>0&&(m.innerHTML+=`(${r}) `,m.title+=` \u2022 ${r} Highlights gefunden`,m.classList.add(\"has-highlights\")),0===c){e.classList.add(\"new-week-available\");const a=`kantine_notified_nextweek_${n}_${t}`;localStorage.getItem(a)||(localStorage.setItem(a,\"true\"),F(\"Neue Men\u00fcdaten f\u00fcr n\u00e4chste Woche verf\u00fcgbar!\",\"info\"))}else e.classList.remove(\"new-week-available\")}else m&&m.remove()}function z(){const t=document.getElementById(\"menu-container\");if(!t)return;t.innerHTML=\"\";let a=i,s=l;\"next-week\"===c&&(a++,a>52&&(a=1,s++));const o=r.flatMap(e=>e.days||[]).filter(e=>{const t=new Date(e.date);return U(t)===a&&G(t)===s});if(0===o.length)return t.innerHTML=`\\n \\n
Keine Men\u00fcdaten f\u00fcr KW ${a} (${s}) verf\u00fcgbar.
\\n
Versuchen Sie eine andere Woche oder schauen Sie sp\u00e4ter vorbei. \\n
`,void document.getElementById(\"weekly-cost-display\").classList.add(\"hidden\");!function(e){let t=0;e&&e.length>0&&e.forEach(e=>{e.items&&e.items.forEach(n=>{const a=n.articleId||parseInt(n.id.split(\"_\")[1]),s=`${e.date}_${a}`,o=u.get(s)||[];o.length>0&&(t+=n.price*o.length)})});const n=document.getElementById(\"weekly-cost-display\");t>0?(n.innerHTML=`shopping_bag Gesamt: ${t.toFixed(2).replace(\".\",\",\")} \u20ac `,n.classList.remove(\"hidden\")):n.classList.add(\"hidden\")}(o);const m=document.getElementById(\"header-week-info\"),h=\"this-week\"===c?\"Diese Woche\":\"N\u00e4chste Woche\";m.innerHTML=`\\n \\n `;const v=document.createElement(\"div\");v.className=\"days-grid\",o.sort((e,t)=>e.date.localeCompare(t.date));o.filter(e=>{const t=new Date(e.date).getDay();return 0!==t&&6!==t}).forEach(t=>{const a=function(t){if(!t.items||0===t.items.length)return null;const a=document.createElement(\"div\");a.className=\"menu-card\";const s=new Date,o=new Date(t.date);let r=!1;if(t.orderCutoff)r=s>=new Date(t.orderCutoff);else{const e=new Date;e.setHours(0,0,0,0);const n=new Date(t.date);n.setHours(0,0,0,0),r=n{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`,s=(u.get(a)||[]).length;if(s>0){const t=e.name.match(/([M][1-9][Ff]?)/);if(t){let e=t[1];s>1&&(e+=\"+\"),i.push(e)}}});const l=document.createElement(\"div\");l.className=\"card-header\";const c=o.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),m=i.map(e=>``).join(\"\");let h=\"\";const v=t.items&&t.items.some(e=>{const n=e.articleId||parseInt(e.id.split(\"_\")[1]),a=`${t.date}_${n}`;return u.has(a)&&u.get(a).length>0}),w=t.items&&t.items.some(e=>e.available);h=v?\"header-violet\":w&&!r?\"header-green\":\"header-red\";h&&l.classList.add(h);l.innerHTML=`\\n \\n ${c} `,a.appendChild(l);var k;const A=document.createElement(\"div\");A.className=\"card-body\";const I=(new Date).toISOString().split(\"T\")[0],L=t.date===I,S=[...t.items].sort((e,n)=>{if(L){const a=e.articleId||parseInt(e.id.split(\"_\")[1]),s=n.articleId||parseInt(n.id.split(\"_\")[1]),o=u.has(`${t.date}_${a}`),r=u.has(`${t.date}_${s}`);if(o&&!r)return-1;if(!o&&r)return 1}return e.name.localeCompare(n.name)});return S.forEach(a=>{const o=document.createElement(\"div\");o.className=\"menu-item\";const i=a.articleId||parseInt(a.id.split(\"_\")[1]),l=`${t.date}_${i}`,c=(u.get(l)||[]).length;let m=\"\";m=a.available?a.amountTracking?`Verf\u00fcgbar (${a.availableAmount}) `:'Verf\u00fcgbar ':'Ausverkauft ';let h=\"\";if(c>0){h=`check_circle Bestellt${c>1?`${c} `:\"\"} `,o.classList.add(\"ordered\"),new Date(t.date).toDateString()===s.toDateString()&&o.classList.add(\"today-ordered\")}const v=`${t.date}_${i}`,w=g.has(v);w&&o.classList.add(a.available?\"flagged-available\":\"flagged-sold-out\");const k=[...new Set([...x(a.name),...x(a.description)])];k.length>0&&o.classList.add(\"highlight-glow\");let I=\"\",L=\"\",S=\"\";if(d&&!r){const e=w?\"notifications_active\":\"notifications_none\",n=w?\"btn-flag active\":\"btn-flag\",s=w?\"Benachrichtigung deaktivieren\":\"Benachrichtigen wenn verf\u00fcgbar\";if(a.available&&!w||(S=`${e} `),a.available&&(I=c>0?`add `:`add_shopping_cart Bestellen `),c>0){const e=1===c?\"close\":\"remove\",n=1===c?\"Bestellung stornieren\":\"Eine Bestellung stornieren\";L=`${e} `}}let B=\"\";if(k.length>0){B=`${k.map(e=>`star ${J(e)} `).join(\"\")}
`}o.innerHTML=`\\n \\n \\n ${h}\\n ${L}\\n ${I}\\n ${S}\\n
${m}
\\n
\\n ${B}\\n ${J(function(e){if(\"all\"===p)return e||\"\";const t=function(e){if(!e)return{de:\"\",en:\"\",raw:\"\"};let t=e.replace(/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?=\\S)/g,\"($1)\\n\u2022 \");t.startsWith(\"\u2022 \")||(t=\"\u2022 \"+t);function n(e){let t=0,n=0;return e.forEach(e=>{const a=e.toLowerCase().replace(/[^a-z\u00e4\u00f6\u00fc\u00df]/g,\"\");if(a){let s=0,o=0;W.includes(a)?s=a.length:W.forEach(e=>{a.includes(e)&&e.length>s&&(s=e.length)}),P.includes(a)?o=a.length:P.forEach(e=>{a.includes(e)&&e.length>o&&(o=e.length)}),s>0&&(t+=s/a.length),o>0&&(n+=o/a.length),/^[A-Z\u00c4\u00d6\u00dc]/.test(e)&&(t+=.5)}}),{de:t,en:n}}function a(e){const t=e.trim().split(/\\s+/);if(t.length<2)return{enPart:e,nextDe:\"\"};let a=-1,s=-9999;for(let e=1;el.en&&m>s&&(s=m,a=e)}return-1!==a?{enPart:t.slice(0,a).join(\" \"),nextDe:t.slice(a).join(\" \")}:{enPart:e,nextDe:\"\"}}const s=e.split(/\\s*\\/\\s*(?![A-Z,]+\\))/);if(s.length>4)return{de:t,en:\"\",raw:t};const o=[],r=[];o.push(s[0].trim());const i=/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*/;for(let e=1;e0&&(o[o.length-1]=o[o.length-1]+\"(\"+s+\")\"),i&&o.push(i)}else{const e=a(t);r.push(e.enPart),e.nextDe&&o.push(e.nextDe)}}1===s.length&&0===r.length&&r.push(o[0]);if(o.length>r.length)for(let e=r.length;e0&&!l.startsWith(\"\u2022 \")&&(l=\"\u2022 \"+l);let c=r.join(\"\\n\u2022 \");r.length>0&&!c.startsWith(\"\u2022 \")&&(c=\"\u2022 \"+c);return{de:l,en:c,raw:t}}(e);return\"en\"===p?t.en||t.raw:t.de||t.raw}(a.description))}
`;const C=o.querySelector(\".btn-order\");C&&C.addEventListener(\"click\",t=>{t.stopPropagation();const a=t.currentTarget;a.disabled=!0,a.classList.add(\"loading\"),async function(t,a,s,o,r){if(d)try{const i=await fetch(`${e}/auth/user/`,{headers:f(d)});if(!i.ok)return void F(\"Fehler: Benutzerdaten konnten nicht geladen werden\",\"error\");const l=await i.json(),c=(new Date).toISOString(),m={uuid:crypto.randomUUID(),created:c,updated:c,order_type:7,items:[{article:a,course_group:null,modifiers:[],uuid:crypto.randomUUID(),name:s,description:r||\"\",price:String(parseFloat(o)),amount:1,vat:\"10.00\",comment:\"\"}],table:null,total:parseFloat(o),tip:0,currency:\"EUR\",venue:n,states:[],order_state:1,date:`${t}T10:30:00Z`,payment_method:\"payroll\",customer:{first_name:l.first_name,last_name:l.last_name,email:l.email,newsletter:!1},preorder:!0,delivery_fee:0,cash_box_table_name:null,take_away:!1},u=await fetch(`${e}/user/orders/`,{method:\"POST\",headers:f(d),body:JSON.stringify(m)});if(u.ok||201===u.status)F(`Bestellt: ${s}`,\"success\"),b=null,await y();else{const e=await u.json();F(`Fehler: ${e.detail||e.non_field_errors?.[0]||\"Bestellung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Order error:\",e),F(\"Netzwerkfehler bei Bestellung\",\"error\")}}(a.dataset.date,parseInt(a.dataset.article),a.dataset.name,parseFloat(a.dataset.price),a.dataset.desc||\"\").finally(()=>{a.disabled=!1,a.classList.remove(\"loading\")})});const D=o.querySelector(\".btn-cancel\");D&&D.addEventListener(\"click\",t=>{t.stopPropagation();const n=t.currentTarget;n.disabled=!0,async function(t,n,a){if(!d)return;const s=`${t}_${n}`,o=u.get(s);if(!o||0===o.length)return;const r=o[o.length-1];try{const t=await fetch(`${e}/user/orders/${r}/cancel/`,{method:\"PATCH\",headers:f(d),body:JSON.stringify({})});t.ok?(F(`Storniert: ${a}`,\"success\"),b=null,await y()):F(`Fehler: ${(await t.json()).detail||\"Stornierung fehlgeschlagen\"}`,\"error\")}catch(e){console.error(\"Cancel error:\",e),F(\"Netzwerkfehler bei Stornierung\",\"error\")}}(n.dataset.date,parseInt(n.dataset.article),n.dataset.name).finally(()=>{n.disabled=!1})});const O=o.querySelector(\".btn-flag\");O&&O.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;E(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,t.dataset.cutoff)}),A.appendChild(o)}),a.appendChild(A),a}(t);a&&v.appendChild(a)}),t.appendChild(v),setTimeout(()=>function(e){const t=e.querySelectorAll(\".menu-card\");if(0===t.length)return;let n=0;t.forEach(e=>{n=Math.max(n,e.querySelectorAll(\".menu-item\").length)});for(let e=0;e{const s=t.querySelectorAll(\".menu-item\");s[e]&&(s[e].style.height=\"auto\",n=Math.max(n,s[e].offsetHeight),a.push(s[e]))}),a.forEach(e=>{e.style.height=`${n}px`})}}(v),0)}function j(e,t){if(!e||!t)return!1;const n=e.replace(/^v/,\"\").split(\".\").map(Number),a=t.replace(/^v/,\"\").split(\".\").map(Number);for(let e=0;e(a[e]||0))return!0;if((n[e]||0)<(a[e]||0))return!1}return!1}async function H(e){const t=e?`${s}/tags?per_page=20`:`${s}/releases?per_page=20`,n=await fetch(t,{headers:{Accept:\"application/vnd.github.v3+json\"}});if(!n.ok){if(403===n.status)throw new Error(\"API Rate Limit erreicht (403). Bitte sp\u00e4ter erneut versuchen.\");throw new Error(`GitHub API ${n.status}`)}return(await n.json()).map(t=>{const n=e?t.name:t.tag_name;return{tag:n,name:e?n:t.name||n,url:`${o}/${n}/dist/install.html`,body:t.body||\"\"}})}async function K(){const e=\"v1.6.8\",t=\"true\"===localStorage.getItem(\"kantine_dev_mode\");try{const n=await H(t);if(!n.length)return;localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:t,versions:n}));const a=n[0].tag;if(console.log(`[Kantine] Version Check: Local [${e}] vs Latest [${a}] (${t?\"dev\":\"stable\"})`),!j(a,e))return;console.log(`[Kantine] Update verf\u00fcgbar: ${a}`);const s=document.querySelector(\".header-left h1\");if(s&&!s.querySelector(\".update-icon\")){const e=document.createElement(\"a\");e.className=\"update-icon\",e.href=n[0].url,e.target=\"_blank\",e.innerHTML=\"\ud83c\udd95\",e.title=`Update: ${a} \u2014 Klick zum Installieren`,e.style.cssText=\"margin-left:8px;font-size:1em;text-decoration:none;cursor:pointer;vertical-align:middle;\",s.appendChild(e)}}catch(e){console.warn(\"[Kantine] Version check failed:\",e)}}function Q(){if(!d||!m)return void X();const e=new Date,t=e.getDay();if(0===t||6===t)return void X();const n=e.toISOString().split(\"T\")[0];let a=!1;for(const e of u.keys())if(e.startsWith(n)){a=!0;break}if(a)return void X();const s=new Date;s.setHours(10,0,0,0);const o=s-e;if(o<=0)return void X();const r=Math.floor(o/36e5),i=Math.floor(o%36e5/6e4),l=document.querySelector(\".header-center-wrapper\");if(!l)return;let c=document.getElementById(\"order-countdown\");if(c||(c=document.createElement(\"div\"),c.id=\"order-countdown\",l.insertBefore(c,l.firstChild)),c.innerHTML=`Bestellschluss: ${r}h ${i}m `,o<36e5){c.classList.add(\"urgent\");const e=`kantine_notified_${n}`;localStorage.getItem(e)||(\"granted\"===Notification.permission?new Notification(\"Kantine: Bestellschluss naht!\",{body:\"Du hast heute noch nichts bestellt. Nur noch 1 Stunde!\",icon:\"\u23f3\"}):\"default\"===Notification.permission&&Notification.requestPermission(),localStorage.setItem(e,\"true\"))}else c.classList.remove(\"urgent\")}function X(){const e=document.getElementById(\"order-countdown\");e&&e.remove()}function U(e){const t=new Date(Date.UTC(e.getFullYear(),e.getMonth(),e.getDate())),n=t.getUTCDay()||7;t.setUTCDate(t.getUTCDate()+4-n);const a=new Date(Date.UTC(t.getUTCFullYear(),0,1));return Math.ceil(((t-a)/864e5+1)/7)}function G(e){const t=new Date(e.getTime());return t.setDate(t.getDate()+3-(t.getDay()+6)%7),t.getFullYear()}function J(e){const t=document.createElement(\"div\");return t.textContent=e||\"\",t.innerHTML}setInterval(Q,6e4),setTimeout(Q,1e3);const W=[\"apfel\",\"aubergine\",\"auflauf\",\"beere\",\"blumenkohl\",\"bohne\",\"braten\",\"brokkoli\",\"brot\",\"brust\",\"br\u00f6tchen\",\"butter\",\"chili\",\"dessert\",\"dip\",\"eier\",\"eintopf\",\"eis\",\"erbse\",\"erdbeer\",\"essig\",\"filet\",\"fisch\",\"fisole\",\"fleckerl\",\"fleisch\",\"fl\u00fcgel\",\"frucht\",\"f\u00fcr\",\"gebraten\",\"gem\u00fcse\",\"gew\u00fcrz\",\"gratin\",\"grie\u00df\",\"gulasch\",\"gurke\",\"himbeer\",\"honig\",\"huhn\",\"h\u00e4hnchen\",\"jambalaya\",\"joghurt\",\"karotte\",\"kartoffel\",\"keule\",\"kirsch\",\"knacker\",\"knoblauch\",\"kn\u00f6del\",\"kompott\",\"kraut\",\"kr\u00e4uter\",\"kuchen\",\"k\u00e4se\",\"k\u00fcrbis\",\"lauch\",\"mandel\",\"milch\",\"mild\",\"mit\",\"mohn\",\"most\",\"m\u00f6hre\",\"natur\",\"nockerl\",\"nudel\",\"nuss\",\"nu\u00df\",\"obst\",\"oder\",\"olive\",\"paprika\",\"pfanne\",\"pfannkuchen\",\"pfeffer\",\"pikant\",\"pilz\",\"plunder\",\"p\u00fcree\",\"ragout\",\"rahm\",\"reis\",\"rind\",\"sahne\",\"salami\",\"salat\",\"salz\",\"sauer\",\"scharf\",\"schinken\",\"schnitte\",\"schnitzel\",\"schoko\",\"schupf\",\"schwein\",\"sellerie\",\"senf\",\"sosse\",\"so\u00dfe\",\"spargel\",\"sp\u00e4tzle\",\"speck\",\"spie\u00df\",\"spinat\",\"steak\",\"suppe\",\"s\u00fc\u00df\",\"tofu\",\"tomate\",\"topfen\",\"torte\",\"tr\u00fcffel\",\"und\",\"vanille\",\"vogerl\",\"vom\",\"wien\",\"wurst\",\"zucchini\",\"zum\",\"zur\",\"zwiebel\",\"\u00f6l\"],P=[\"almond\",\"and\",\"apple\",\"asparagus\",\"bacon\",\"baked\",\"ball\",\"bean\",\"beef\",\"berry\",\"bread\",\"breast\",\"broccoli\",\"bun\",\"butter\",\"cabbage\",\"cake\",\"caper\",\"carrot\",\"casserole\",\"cauliflower\",\"celery\",\"cheese\",\"cherry\",\"chicken\",\"chili\",\"choco\",\"chocolate\",\"cider\",\"cilantro\",\"coffee\",\"compote\",\"cream\",\"cucumber\",\"curd\",\"danish\",\"dessert\",\"dip\",\"dumpling\",\"egg\",\"eggplant\",\"filet\",\"fish\",\"for\",\"fried\",\"from\",\"fruit\",\"garlic\",\"goulash\",\"gratin\",\"ham\",\"herb\",\"honey\",\"hot\",\"ice\",\"jambalaya\",\"leek\",\"leg\",\"mash\",\"meat\",\"mexican\",\"mild\",\"milk\",\"mint\",\"mushroom\",\"mustard\",\"noodle\",\"nut\",\"oat\",\"oil\",\"olive\",\"onion\",\"or\",\"oven\",\"pan\",\"pancake\",\"pea\",\"pepper\",\"plain\",\"plate\",\"poppy\",\"pork\",\"potato\",\"pumpkin\",\"radish\",\"ragout\",\"raspberry\",\"rice\",\"roast\",\"roll\",\"salad\",\"salami\",\"salt\",\"sauce\",\"sausage\",\"shrimp\",\"skewer\",\"slice\",\"soup\",\"sour\",\"spice\",\"spicy\",\"spinach\",\"steak\",\"stew\",\"strawberr\",\"strawberry\",\"strudel\",\"sweet\",\"tart\",\"thyme\",\"to\",\"tofu\",\"tomat\",\"tomato\",\"truffle\",\"trukey\",\"turkey\",\"vanilla\",\"vegan\",\"vegetable\",\"vinegar\",\"wedge\",\"wing\",\"with\",\"wok\",\"yogurt\",\"zucchini\"];!function(){document.title=\"Kantine Weekly Menu\",document.querySelectorAll&&document.querySelectorAll('link[rel*=\"icon\"]').forEach(e=>e.remove());const e=document.createElement(\"link\");if(e.rel=\"icon\",e.type=\"image/png\",e.href=\"data:image/png;base64,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\",document.head.appendChild(e),!document.querySelector('link[href*=\"fonts.googleapis.com/css2?family=Inter\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap\",document.head.appendChild(e)}if(!document.querySelector('link[href*=\"Material+Icons+Round\"]')){const e=document.createElement(\"link\");e.rel=\"stylesheet\",e.href=\"https://fonts.googleapis.com/icon?family=Material+Icons+Round\",document.head.appendChild(e)}document.body.innerHTML=`\\n \\n \\n\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Initialisierung...
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Markiere Men\u00fcs automatisch, wenn sie diese Schlagw\u00f6rter enthalten.\\n
\\n
\\n \\n Hinzuf\u00fcgen \\n
\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n
Lade Historie...
\\n
\\n
\\n
\\n \\x3c!-- Dynamically populated --\\x3e\\n
\\n
\\n
\\n
\\n\\n
\\n
\\n \\n
\\n
\\n Aktuell: v1.6.8 \\n
\\n
\\n \\n \\n Dev-Mode (alle Tags anzeigen) \\n \\n
\\n
\\n
\\n
\\n
\\n
\\n\\n
\\n \\n update \\n Gerade aktualisiert \\n
\\n \\n
\\n
Lade Men\u00fcdaten...
\\n
\\n \\n \\n\\n \\n
`}(),function(){const n=document.getElementById(\"btn-this-week\"),a=document.getElementById(\"btn-next-week\"),s=document.getElementById(\"btn-refresh\"),o=document.getElementById(\"theme-toggle\"),r=document.getElementById(\"btn-login-open\"),i=document.getElementById(\"btn-login-close\"),l=document.getElementById(\"btn-logout\"),g=document.getElementById(\"login-form\"),k=document.getElementById(\"login-modal\"),A=document.getElementById(\"btn-highlights\"),E=document.getElementById(\"highlights-modal\"),x=document.getElementById(\"btn-highlights-close\"),C=document.getElementById(\"btn-add-tag\"),D=document.getElementById(\"tag-input\"),O=document.getElementById(\"btn-history\"),N=document.getElementById(\"history-modal\"),T=document.getElementById(\"btn-history-close\");document.querySelectorAll(\".lang-btn\").forEach(e=>{e.addEventListener(\"click\",()=>{p=e.dataset.lang,localStorage.setItem(\"kantine_lang\",p),document.querySelectorAll(\".lang-btn\").forEach(e=>e.classList.remove(\"active\")),e.classList.add(\"active\"),z()})}),A&&A.addEventListener(\"click\",()=>{E.classList.remove(\"hidden\")}),x&&x.addEventListener(\"click\",()=>{E.classList.add(\"hidden\")}),O.addEventListener(\"click\",()=>{d?(N.classList.remove(\"hidden\"),async function(){const t=document.getElementById(\"history-loading\"),n=document.getElementById(\"history-content\"),a=document.getElementById(\"history-progress-fill\"),s=document.getElementById(\"history-progress-text\");let o=[];if(b)o=b;else{const e=localStorage.getItem(\"kantine_history_cache\");if(e)try{o=JSON.parse(e),b=o}catch(e){console.warn(\"History cache parse error\",e)}}o.length>0&&w(o);if(!d)return;0===o.length&&(n.innerHTML=\"\",t.classList.remove(\"hidden\"));a.style.width=\"0%\",s.textContent=o.length>0?\"Suche nach neuen Bestellungen...\":\"Lade Bestellhistorie...\",o.length>0&&t.classList.remove(\"hidden\");let r=o.length>0?`${e}/user/orders/?venue=591&ordering=-created&limit=5`:`${e}/user/orders/?venue=591&ordering=-created&limit=50`,i=[],l=0,c=0===o.length,m=!1;try{for(;r&&!m;){const e=await fetch(r,{headers:f(d)});if(!e.ok)throw new Error(`Fetch failed: ${e.status}`);const t=await e.json();t.count&&0===l&&(l=t.count);const n=t.results||[];for(const e of n){const t=o.findIndex(t=>t.id===e.id);if(!c&&-1!==t){const n=o[t];if(n.updated===e.updated&&n.order_state===e.order_state){m=!0;break}}i.push(e)}if(!m&&c)if(l>0){const e=Math.round(i.length/l*100);a.style.width=`${e}%`,s.textContent=`Lade Bestellung ${i.length} von ${l}...`}else s.textContent=`Lade Bestellung ${i.length}...`;else m||(s.textContent=`${i.length} neue/ge\u00e4nderte Bestellungen gefunden...`);r=m?null:t.next}if(i.length>0){const e=new Map(o.map(e=>[e.id,e]));for(const t of i)e.set(t.id,t);const t=Array.from(e.values());t.sort((e,t)=>new Date(t.created)-new Date(e.created)),b=t;try{localStorage.setItem(\"kantine_history_cache\",JSON.stringify(t))}catch(e){console.warn(\"History cache write error\",e)}w(b)}}catch(e){console.error(\"Error in history sync:\",e),0===o.length?n.innerHTML='Fehler beim Laden der Historie.
':F(\"Hintergrund-Synchronisation fehlgeschlagen\",\"error\")}finally{t.classList.add(\"hidden\")}}()):k.classList.remove(\"hidden\")}),T.addEventListener(\"click\",()=>{N.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===N&&N.classList.add(\"hidden\"),e.target===E&&E.classList.add(\"hidden\")});const q=document.querySelector(\".version-tag\"),$=document.getElementById(\"version-modal\"),K=document.getElementById(\"btn-version-close\");q&&q.addEventListener(\"click\",e=>{e.preventDefault(),e.stopPropagation(),function(){const e=document.getElementById(\"version-modal\"),t=document.getElementById(\"version-list-container\"),n=document.getElementById(\"dev-mode-toggle\"),a=\"v1.6.8\";if(!e)return;e.classList.remove(\"hidden\");const s=document.getElementById(\"version-current\");s&&(s.textContent=a);const o=\"true\"===localStorage.getItem(\"kantine_dev_mode\");async function r(e){const s=n.checked;function o(e){if(!e||!e.length)return void(t.innerHTML='Keine Versionen gefunden.
');t.innerHTML='';const n=t.querySelector(\".version-list\");e.forEach(e=>{const t=e.tag===a,s=j(e.tag,a),o=document.createElement(\"li\");o.className=\"version-item\"+(t?\" current\":\"\");let r=\"\";t?r='\u2713 Installiert ':s&&(r='\u2b06 Neu! ');let i=\"\";t||(i=`Installieren `),o.innerHTML=`\\n \\n ${e.tag} \\n ${r}\\n
\\n ${i}\\n `,n.appendChild(o)})}t.innerHTML='Lade Versionen...
';try{const e=localStorage.getItem(\"kantine_version_cache\");let t=null;if(e)try{t=JSON.parse(e)}catch(e){}t&&t.devMode===s&&t.versions&&o(t.versions);const n=await H(s),a=JSON.stringify(n);a!==(t?JSON.stringify(t.versions):\"\")&&(localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:s,versions:n})),o(n))}catch(e){t.innerHTML=`Fehler: ${e.message}
`}}n.checked=o,r(!1),n.onchange=()=>{localStorage.setItem(\"kantine_dev_mode\",n.checked),localStorage.removeItem(\"kantine_version_cache\"),r(!0)}}()}),K&&K.addEventListener(\"click\",()=>{$.classList.add(\"hidden\")});const Q=document.getElementById(\"btn-clear-cache\");Q&&Q.addEventListener(\"click\",()=>{confirm(\"M\u00f6chtest du wirklich alle lokalen Daten (inkl. Login-Session, Cache und Einstellungen) l\u00f6schen? Die Seite wird danach neu geladen.\")&&(Object.keys(localStorage).forEach(e=>{e.startsWith(\"kantine_\")&&localStorage.removeItem(e)}),window.location.reload())}),window.addEventListener(\"click\",e=>{e.target===$&&$.classList.add(\"hidden\")}),C.addEventListener(\"click\",()=>{(function(e){if(e=e.trim().toLowerCase(),e&&!L.includes(e))return L.push(e),S(),!0;return!1})(D.value)&&(D.value=\"\",B())}),D.addEventListener(\"keypress\",e=>{\"Enter\"===e.key&&C.click()});const X=localStorage.getItem(\"theme\"),U=window.matchMedia(\"(prefers-color-scheme: dark)\").matches,G=o.querySelector(\".theme-icon\");\"dark\"===X||!X&&U?(document.documentElement.setAttribute(\"data-theme\",\"dark\"),G.textContent=\"dark_mode\"):(document.documentElement.setAttribute(\"data-theme\",\"light\"),G.textContent=\"light_mode\"),o.addEventListener(\"click\",()=>{const e=\"dark\"===document.documentElement.getAttribute(\"data-theme\")?\"light\":\"dark\";document.documentElement.setAttribute(\"data-theme\",e),localStorage.setItem(\"theme\",e),G.textContent=\"dark\"===e?\"dark_mode\":\"light_mode\"}),n.addEventListener(\"click\",()=>{\"this-week\"!==c&&(c=\"this-week\",n.classList.add(\"active\"),a.classList.remove(\"active\"),z())}),a.addEventListener(\"click\",()=>{a.classList.remove(\"new-week-available\"),\"next-week\"!==c&&(c=\"next-week\",a.classList.add(\"active\"),n.classList.remove(\"active\"),z())}),s.addEventListener(\"click\",()=>{d?M():k.classList.remove(\"hidden\")}),r.addEventListener(\"click\",()=>{k.classList.remove(\"hidden\"),document.getElementById(\"login-error\").classList.add(\"hidden\"),g.reset()}),i.addEventListener(\"click\",()=>{k.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===k&&k.classList.add(\"hidden\")}),g.addEventListener(\"submit\",async n=>{n.preventDefault();const a=document.getElementById(\"employee-id\").value.trim(),s=document.getElementById(\"password\").value,o=document.getElementById(\"login-error\"),r=g.querySelector('button[type=\"submit\"]'),i=r.textContent;r.disabled=!0,r.textContent=\"Wird eingeloggt...\";try{const n=`knapp-${a}@bessa.app`,r=await fetch(`${e}/auth/login/`,{method:\"POST\",headers:f(t),body:JSON.stringify({email:n,password:s})}),i=await r.json();if(r.ok){d=i.key,m=a,localStorage.setItem(\"kantine_authToken\",i.key),localStorage.setItem(\"kantine_currentUser\",a);try{const t=await fetch(`${e}/auth/user/`,{headers:f(d)});if(t.ok){const e=await t.json();e.first_name&&localStorage.setItem(\"kantine_firstName\",e.first_name),e.last_name&&localStorage.setItem(\"kantine_lastName\",e.last_name)}}catch(e){console.error(\"Failed to fetch user info:\",e)}v(),k.classList.add(\"hidden\"),y(),g.reset(),I(),M()}else o.textContent=i.non_field_errors?.[0]||i.error||\"Login fehlgeschlagen\",o.classList.remove(\"hidden\")}catch(e){console.error(\"Login error:\",e),o.textContent=\"Ein Fehler ist aufgetreten\",o.classList.remove(\"hidden\")}finally{r.disabled=!1,r.textContent=i}}),l.addEventListener(\"click\",()=>{localStorage.removeItem(\"kantine_authToken\"),localStorage.removeItem(\"kantine_currentUser\"),localStorage.removeItem(\"kantine_firstName\"),localStorage.removeItem(\"kantine_lastName\"),d=null,m=null,u=new Map,h&&(clearInterval(h),h=null,console.log(\"Polling stopped\")),v(),z()})}(),v(),function(){const e=new Date,t=e.toISOString().split(\"T\")[0];let n=!1;for(const a of[...g]){const[s]=a.split(\"_\");let o=!1;if(s=t&&(o=!0)}o&&(g.delete(a),n=!0)}n&&k()}();(function(){try{const e=localStorage.getItem(C),t=localStorage.getItem(D);if(console.log(`[Cache] localStorage: key=${!!e} (${e?e.length:0} chars), ts=${t}`),e){r=JSON.parse(e),i=U(new Date),l=(new Date).getFullYear(),console.log(`[Cache] Parsed ${r.length} weeks:`,r.map(e=>`KW${e.weekNumber}/${e.year} (${(e.days||[]).length} days)`)),z(),$(),A(),t&&q(t);try{const e=new Set;r.forEach(t=>{(t.days||[]).forEach(t=>{(t.items||[]).forEach(t=>{let n=(t.description||\"\").replace(/\\s+/g,\" \").trim();n&&n.includes(\" / \")&&e.add(n)})})});const t=Array.from(e).join(\"\\n\\n\");console.log(\"=== GEFUNDENE MEN\u00dc-TEXTE (\"+e.size+\") ===\"),console.log(t)}catch(e){}return console.log(\"Loaded menu from cache\"),!0}}catch(e){console.warn(\"Failed to load cached menu:\",e)}return!1})()?(document.getElementById(\"loading\").classList.add(\"hidden\"),!function(){const e=localStorage.getItem(D);if(!e)return console.log(\"[Cache] No timestamp found\"),!1;const t=Date.now()-new Date(e).getTime(),n=Math.round(t/6e4);if(t>36e5)return console.log(`[Cache] Stale: ${n}min old (max 60)`),!1;const a=U(new Date),s=G(new Date),o=r.some(e=>e.weekNumber===a&&e.year===s&&e.days&&e.days.length>0);return console.log(`[Cache] Age: ${n}min, looking for KW${a}/${s}, found: ${o}`),o}()?(console.log(\"Cache stale or incomplete \u2013 refreshing from API\"),M()):console.log(\"Cache fresh & complete \u2013 skipping API refresh\")):M(),d&&I(),K(),setInterval(K,36e5),console.log(\"Kantine Wrapper loaded \u2705\")}();\n"; document.head.appendChild(sc); })();
diff --git a/dist/install.html b/dist/install.html
index dbb5566..a835fb6 100755
--- a/dist/install.html
+++ b/dist/install.html
@@ -2,7 +2,7 @@
- Kantine Wrapper Installer (v1.6.7)
+ Kantine Wrapper Installer (v1.6.8)