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="(()=>{\"use strict\";var e={367(e,t,n){n.d(t,{Aq:()=>m,BM:()=>E,Et:()=>b,Gb:()=>d,H:()=>v,KG:()=>S,N4:()=>h,P0:()=>N,PQ:()=>f,VL:()=>D,Y1:()=>A,g8:()=>y,i_:()=>c,m9:()=>x,oL:()=>k,wH:()=>g});var a=n(901),s=n(413),o=n(521),i=n(672),r=n(842);let l=null;function c(){if(!a.gX)try{const e=localStorage.getItem(\"AkitaStores\");if(e){const t=JSON.parse(e);t.auth&&t.auth.token&&(console.log(\"Found existing Bessa session!\"),(0,a.O5)(t.auth.token),localStorage.setItem(\"kantine_authToken\",t.auth.token),t.auth.user&&((0,a.lt)(t.auth.user.id||\"unknown\"),localStorage.setItem(\"kantine_currentUser\",t.auth.user.id||\"unknown\"),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)}(0,a.O5)(localStorage.getItem(\"kantine_authToken\")),(0,a.lt)(localStorage.getItem(\"kantine_currentUser\"));const e=localStorage.getItem(\"kantine_firstName\"),t=document.getElementById(\"btn-login-open\"),n=document.getElementById(\"user-info\"),s=document.getElementById(\"user-id-display\");a.gX?(t.classList.add(\"hidden\"),n.classList.remove(\"hidden\"),s.textContent=e||(a.Ny?`User ${a.Ny}`:\"Angemeldet\"),d()):(t.classList.remove(\"hidden\"),n.classList.add(\"hidden\"),s.textContent=\"\"),(0,r.OR)()}async function d(){if(a.gX)try{const e=await fetch(`${o.tE}/user/orders/?venue=${o.eW}&ordering=-created&limit=50`,{headers:(0,i.H)(a.gX)}),t=await e.json();if(e.ok){const e=new Map,n=t.results||[];for(const t of n){if(9===t.order_state)continue;const n=t.date.split(\"T\")[0];for(const a of t.items||[]){const s=`${n}_${a.article}`;e.has(s)||e.set(s,[]),e.get(s).push(t.id)}}(0,a.di)(e),console.log(`Fetched ${n.length} orders, mapped active ones.`),(0,r.OR)(),(0,r.gJ)()}}catch(e){console.error(\"Error fetching orders:\",e)}}async function m(){const e=document.getElementById(\"history-loading\"),t=document.getElementById(\"history-content\"),n=document.getElementById(\"history-progress-fill\"),s=document.getElementById(\"history-progress-text\");let r=[];if(l)r=l;else{const e=localStorage.getItem(\"kantine_history_cache\");if(e)try{r=JSON.parse(e),l=r}catch(e){console.warn(\"History cache parse error\",e)}}if(r.length>0&&u(r),!a.gX)return;0===r.length&&(t.innerHTML=\"\",e.classList.remove(\"hidden\")),n.style.width=\"0%\",s.textContent=r.length>0?\"Suche nach neuen Bestellungen...\":\"Lade Bestellhistorie...\",r.length>0&&e.classList.remove(\"hidden\");let c=r.length>0?`${o.tE}/user/orders/?venue=${o.eW}&ordering=-created&limit=5`:`${o.tE}/user/orders/?venue=${o.eW}&ordering=-created&limit=50`,d=[],m=0,g=0===r.length,h=!1;try{for(;c&&!h;){const e=await fetch(c,{headers:(0,i.H)(a.gX)});if(!e.ok)throw new Error(`Fetch failed: ${e.status}`);const t=await e.json();t.count&&0===m&&(m=t.count);const o=t.results||[];for(const e of o){const t=r.findIndex(t=>t.id===e.id);if(!g&&-1!==t){const n=r[t];if(n.updated===e.updated&&n.order_state===e.order_state){h=!0;break}}d.push(e)}if(!h&&g)if(m>0){const e=Math.round(d.length/m*100);n.style.width=`${e}%`,s.textContent=`Lade Bestellung ${d.length} von ${m}...`}else s.textContent=`Lade Bestellung ${d.length}...`;else h||(s.textContent=`${d.length} neue/ge\u00e4nderte Bestellungen gefunden...`);c=h?null:t.next}if(d.length>0){const e=new Map(r.map(e=>[e.id,e]));for(const t of d)e.set(t.id,t);const t=Array.from(e.values());t.sort((e,t)=>new Date(t.created)-new Date(e.created)),l=t;try{localStorage.setItem(\"kantine_history_cache\",JSON.stringify(t))}catch(e){console.warn(\"History cache write error\",e)}u(l)}}catch(e){console.error(\"Error in history sync:\",e),0===r.length?t.innerHTML='<p style=\"color:var(--error-color);text-align:center;\">Fehler beim Laden der Historie.</p>':N(\"Hintergrund-Synchronisation fehlgeschlagen\",\"error\")}finally{e.classList.add(\"hidden\")}}function u(e){const t=document.getElementById(\"history-content\");if(!e||0===e.length)return void(t.innerHTML='<p style=\"text-align:center;color:var(--text-secondary);padding:20px;\">Keine Bestellungen gefunden.</p>');const n={};e.forEach(e=>{const t=new Date(e.date),a=t.getFullYear(),o=t.getMonth(),i=`${a}-${o.toString().padStart(2,\"0\")}`,r=t.toLocaleString(\"de-AT\",{month:\"long\"}),l=(0,s.sn)(t);n[a]||(n[a]={year:a,months:{}}),n[a].months[i]||(n[a].months[i]={name:r,year:a,monthIndex:o,count:0,total:0,weeks:{}}),n[a].months[i].weeks[l]||(n[a].months[i].weeks[l]={label:`KW ${l}`,items:[],count:0,total:0});(e.items||[]).forEach(t=>{const s=parseFloat(t.price||e.total||0);n[a].months[i].weeks[l].items.push({date:e.date,name:t.name||\"Men\u00fc\",price:s,state:e.order_state}),9!==e.order_state&&(n[a].months[i].weeks[l].count++,n[a].months[i].weeks[l].total+=s,n[a].months[i].count++,n[a].months[i].total+=s)})});const a=Object.keys(n).sort((e,t)=>t-e);let o=\"\";a.forEach(e=>{const t=n[e];o+=`<div class=\"history-year-group\">\\n <h2 class=\"history-year-header\">${t.year}</h2>`;Object.keys(t.months).sort((e,t)=>t.localeCompare(e)).forEach(e=>{const n=t.months[e];o+=`<div class=\"history-month-group\">\\n <div class=\"history-month-header\" tabindex=\"0\" role=\"button\" aria-expanded=\"false\" title=\"Klicken, um die Bestellungen f\u00fcr diesen Monat ein-/auszublenden\">\\n <div style=\"display:flex; flex-direction:column; gap:4px;\">\\n <span>${n.name}</span>\\n <div class=\"history-month-summary\">\\n <span>${n.count} Bestellungen &bull; <strong>\u20ac${n.total.toFixed(2)}</strong></span>\\n </div>\\n </div>\\n <span class=\"material-icons-round\">expand_more</span>\\n </div>\\n <div class=\"history-month-content\">`;Object.keys(n.weeks).sort((e,t)=>parseInt(t)-parseInt(e)).forEach(e=>{const t=n.weeks[e];o+=`<div class=\"history-week-group\">\\n <div class=\"history-week-header\">\\n <strong>${t.label}</strong>\\n <span>${t.count} Bestellungen &bull; <strong>\u20ac${t.total.toFixed(2)}</strong></span>\\n </div>`,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?'<span class=\"history-item-status\">Storniert</span>':8===e.state?'<span class=\"history-item-status\">Abgeschlossen</span>':'<span class=\"history-item-status\">\u00dcbertragen</span>',o+=`\\n <div class=\"history-item ${9===e.state?\"history-item-cancelled\":\"\"}\">\\n <div style=\"font-size: 0.85rem; color: var(--text-secondary);\">${t}</div>\\n <div class=\"history-item-details\">\\n <span class=\"history-item-name\">${(0,s.ZD)(e.name)}</span>\\n <div>${n}</div>\\n </div>\\n <div class=\"history-item-price ${9===e.state?\"history-item-price-cancelled\":\"\"}\">\u20ac${e.price.toFixed(2)}</div>\\n </div>`}),o+=\"</div>\"}),o+=\"</div></div>\"}),o+=\"</div>\"}),t.innerHTML=o;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\"))})})}async function g(e,t,n,s,r){if(a.gX)try{const c=await fetch(`${o.tE}/auth/user/`,{headers:(0,i.H)(a.gX)});if(!c.ok)return void N(\"Fehler: Benutzerdaten konnten nicht geladen werden\",\"error\");const m=await c.json(),u=(new Date).toISOString(),g={uuid:crypto.randomUUID(),created:u,updated:u,order_type:7,items:[{article:t,course_group:null,modifiers:[],uuid:crypto.randomUUID(),name:n,description:r||\"\",price:String(parseFloat(s)),amount:1,vat:\"10.00\",comment:\"\"}],table:null,total:parseFloat(s),tip:0,currency:\"EUR\",venue:o.eW,states:[],order_state:1,date:`${e}T10:30:00Z`,payment_method:\"payroll\",customer:{first_name:m.first_name,last_name:m.last_name,email:m.email,newsletter:!1},preorder:!0,delivery_fee:0,cash_box_table_name:null,take_away:!1},h=await fetch(`${o.tE}/user/orders/`,{method:\"POST\",headers:(0,i.H)(a.gX),body:JSON.stringify(g)});if(h.ok||201===h.status)N(`Bestellt: ${n}`,\"success\"),l=null,await d();else{const e=await h.json();N(`Fehler: ${e.detail||e.non_field_errors?.[0]||\"Bestellung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Order error:\",e),N(\"Netzwerkfehler bei Bestellung\",\"error\")}}async function h(e,t,n){if(!a.gX)return;const s=`${e}_${t}`,r=a.L.get(s);if(!r||0===r.length)return;const c=r[r.length-1];try{const e=await fetch(`${o.tE}/user/orders/${c}/cancel/`,{method:\"PATCH\",headers:(0,i.H)(a.gX),body:JSON.stringify({})});if(e.ok)N(`Storniert: ${n}`,\"success\"),l=null,await d();else{N(`Fehler: ${(await e.json()).detail||\"Stornierung fehlgeschlagen\"}`,\"error\")}}catch(e){console.error(\"Cancel error:\",e),N(\"Netzwerkfehler bei Stornierung\",\"error\")}}function p(){localStorage.setItem(\"kantine_flags\",JSON.stringify([...a.BY]))}function f(e,t,n,s){const l=`${e}_${t}`;let c=!1;a.BY.has(l)?(a.BY.delete(l),N(`Flag entfernt f\u00fcr ${n}`,\"success\")):(a.BY.add(l),c=!0,N(`Benachrichtigung aktiviert f\u00fcr ${n}`,\"success\"),\"default\"===Notification.permission&&Notification.requestPermission()),p(),(0,r.Mb)(),(0,r.OR)(),c&&async function(){if(0===a.BY.size)return;const e=a.gX||o.f9,t=new Set;for(const e of a.BY){const[n]=e.split(\"_\");t.add(n)}let n=!1;for(const s of t)try{const t=await fetch(`${o.tE}/venues/${o.eW}/menu/${o.YU}/${s}/`,{headers:(0,i.H)(e)});if(!t.ok)continue;const r=(await t.json()).results||[];let l=[];for(const e of r)e.items&&Array.isArray(e.items)&&(l=l.concat(e.items));for(let e of a.p_){if(!e.days)continue;let t=e.days.find(e=>e.date===s);t&&(t.items=l.map(e=>{const t=!1===e.amount_tracking,n=parseInt(e.available_amount)>0;return{id:`${s}_${e.id}`,articleId:e.id,name:e.name||\"Unknown\",description:e.description||\"\",price:parseFloat(e.price)||0,available:t||n,availableAmount:parseInt(e.available_amount)||0,amountTracking:!1!==e.amount_tracking}}),n=!0)}}catch(e){console.error(\"Error refreshing flag date\",s,e)}n&&(B(),M((new Date).toISOString()),(0,r.Mb)(),(0,r.OR)())}()}function v(){const e=new Date,t=e.toISOString().split(\"T\")[0];let n=!1;for(const s of[...a.BY]){const[o]=s.split(\"_\");let i=!1;if(o<t)i=!0;else if(o===t){const t=new Date(o);t.setHours(10,0,0,0),e>=t&&(i=!0)}i&&(a.BY.delete(s),n=!0)}n&&p()}function y(){a.K8||a.gX&&((0,a.cc)(setInterval(()=>async function(){if(0===a.BY.size||!a.gX)return;console.log(`Polling ${a.BY.size} flagged items...`);for(const e of a.BY){const[t,n]=e.split(\"_\"),s=parseInt(n);try{const e=await fetch(`${o.tE}/venues/${o.eW}/menu/${o.YU}/${t}/`,{headers:(0,i.H)(a.gX)});if(!e.ok)continue;const n=(await e.json()).results||[];let r=null;for(const e of n)if(e.items&&(r=e.items.find(e=>e.id===s||e.article===s),r))break;if(r){if(!1===r.amount_tracking||parseInt(r.available_amount)>0){const e=r.name||\"Unbekannt\";N(`${e} ist jetzt verf\u00fcgbar!`,\"success\"),\"granted\"===Notification.permission&&new Notification(\"Kantine Wrapper\",{body:`${e} ist jetzt verf\u00fcgbar!`,icon:\"\ud83c\udf7d\ufe0f\"}),x()}}}catch(t){console.error(`Poll error for ${e}:`,t),await new Promise(e=>setTimeout(e,200))}}localStorage.setItem(\"kantine_last_checked\",(new Date).toISOString()),(0,r.Mb)()}(),o.fv)),console.log(\"Polling started (every 5 min)\"))}function b(){a.K8&&(clearInterval(a.K8),(0,a.cc)(null),console.log(\"Polling stopped\"))}function w(){localStorage.setItem(\"kantine_highlightTags\",JSON.stringify(a.yz)),(0,r.OR)(),(0,r.gJ)()}function k(e){if((e=e.trim().toLowerCase())&&!a.yz.includes(e)){const t=[...a.yz,e];return(0,a.iw)(t),w(),!0}return!1}function A(){const e=document.getElementById(\"tags-list\");e.innerHTML=\"\",a.yz.forEach(t=>{const n=document.createElement(\"span\");n.className=\"tag-badge\",n.innerHTML=`${t} <span class=\"tag-remove\" data-tag=\"${t}\" title=\"Schlagwort entfernen\">&times;</span>`,e.appendChild(n)}),e.querySelectorAll(\".tag-remove\").forEach(e=>{e.addEventListener(\"click\",e=>{!function(e){const t=a.yz.filter(t=>t!==e);(0,a.iw)(t),w()}(e.target.dataset.tag),A()})})}function E(e){return e?(e=e.toLowerCase(),a.yz.filter(t=>e.includes(t))):[]}const L=\"kantine_menuCache\",I=\"kantine_menuCacheTs\";function B(){try{localStorage.setItem(L,JSON.stringify(a.p_)),localStorage.setItem(I,(new Date).toISOString())}catch(e){console.warn(\"Failed to cache menu data:\",e)}}function S(){try{const e=localStorage.getItem(L),t=localStorage.getItem(I);if(console.log(`[Cache] localStorage: key=${!!e} (${e?e.length:0} chars), ts=${t}`),e){(0,a.tn)(JSON.parse(e)),(0,a.Xt)((0,s.sn)(new Date)),(0,a.pK)((new Date).getFullYear()),console.log(`[Cache] Parsed ${a.p_.length} weeks:`,a.p_.map(e=>`KW${e.weekNumber}/${e.year} (${(e.days||[]).length} days)`)),(0,r.OR)(),(0,r.gJ)(),(0,r.Mb)(),t&&M(t);try{const e=new Set;a.p_.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}function D(){const e=localStorage.getItem(I);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 o=(0,s.sn)(new Date),i=(0,s.Ao)(new Date),r=a.p_.some(e=>e.weekNumber===o&&e.year===i&&e.days&&e.days.length>0);return console.log(`[Cache] Age: ${n}min, looking for KW${o}/${i}, found: ${r}`),r}async function x(){const e=document.getElementById(\"loading\"),t=document.getElementById(\"progress-modal\"),l=document.getElementById(\"progress-fill\"),d=document.getElementById(\"progress-percent\"),m=document.getElementById(\"progress-message\");e.classList.remove(\"hidden\");const u=a.gX||o.f9;try{t.classList.remove(\"hidden\"),m.textContent=\"Hole verf\u00fcgbare Daten...\",l.style.width=\"0%\",d.textContent=\"0%\";const e=await fetch(`${o.tE}/venues/${o.eW}/menu/dates/`,{headers:(0,i.H)(u)});if(!e.ok)throw new Error(`Failed to fetch dates: ${e.status}`);let n=(await e.json()).results||[];const g=new Date;g.setDate(g.getDate()-7);const h=g.toISOString().split(\"T\")[0];n=n.filter(e=>e.date>=h).sort((e,t)=>e.date.localeCompare(t.date)).slice(0,30);const p=n.length;m.textContent=`${p} Tage gefunden. Lade Details...`;const f=[];let v=0;for(const e of n){const t=e.date,n=Math.round((v+1)/p*100);l.style.width=`${n}%`,d.textContent=`${n}%`,m.textContent=`Lade Men\u00fc f\u00fcr ${t}...`;try{const n=await fetch(`${o.tE}/venues/${o.eW}/menu/${o.YU}/${t}/`,{headers:(0,i.H)(u)});if(n.ok){const a=await n.json();0===v&&console.log(\"[Kantine Debug] Raw API response for\",t,\":\",JSON.stringify(a).substring(0,2e3));const s=a.results||[];let o=[];for(const e of s)e.items&&Array.isArray(e.items)&&(o=o.concat(e.items));o.length>0&&(0===v&&(console.log(\"[Kantine Debug] First item keys:\",Object.keys(o[0])),console.log(\"[Kantine Debug] First item:\",JSON.stringify(o[0]).substring(0,500))),f.push({date:t,menu_items:o,orders:e.orders||[]}))}}catch(e){console.error(`Failed to fetch details for ${t}:`,e)}v++,await new Promise(e=>setTimeout(e,100))}const y=new Map;a.p_&&a.p_.length>0&&a.p_.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 f){const t=new Date(e.date),n=(0,s.sn)(t),a=(0,s.Ao)(t),o=`${a}-${n}`;y.has(o)||y.set(o,{year:a,weekNumber:n,days:[]});const i=y.get(o),r=t.toLocaleDateString(\"en-US\",{weekday:\"long\"}),l=new Date(e.date);l.setHours(10,0,0,0);const c={date:e.date,weekday:r,orderCutoff:l.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}})},d=i.days.findIndex(t=>t.date===e.date);d>=0?i.days[d]=c:i.days.push(c)}const b=Array.from(y.values()).sort((e,t)=>e.year!==t.year?e.year-t.year:e.weekNumber-t.weekNumber);b.forEach(e=>{e.days&&e.days.sort((e,t)=>e.date.localeCompare(t.date))}),(0,a.tn)(b),B(),M((new Date).toISOString()),(0,a.Xt)((0,s.sn)(new Date)),(0,a.pK)((new Date).getFullYear()),c(),(0,r.OR)(),(0,r.gJ)(),(0,r.Mb)(),m.textContent=\"Fertig!\",setTimeout(()=>t.classList.add(\"hidden\"),500)}catch(e){console.error(\"Error fetching menu:\",e),t.classList.add(\"hidden\"),Promise.resolve().then(n.bind(n,842)).then(t=>{t.showErrorModal(\"Keine Verbindung\",`Die Men\u00fcdaten konnten nicht geladen werden. M\u00f6glicherweise besteht keine Verbindung zur API oder zur Bessa-Webseite.<br><br><small style=\"color:var(--text-secondary)\">${e.message}</small>`,\"Zur Original-Seite\",\"https://web.bessa.app/knapp-kantine\")})}finally{e.classList.add(\"hidden\")}}let O=null,C=null;function M(e){const t=document.getElementById(\"last-updated-subtitle\");if(e){O=e,localStorage.setItem(\"kantine_last_updated\",e),localStorage.setItem(\"kantine_last_checked\",e);try{const n=new Date(e),a=n.toLocaleTimeString(\"de-DE\",{hour:\"2-digit\",minute:\"2-digit\"}),o=n.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),i=(0,s.gs)(n);t.textContent=`Aktualisiert: ${o} ${a} (${i})`}catch(e){t.textContent=\"\"}C||(C=setInterval(()=>{O&&(M(O),(0,r.Mb)())},6e4))}}function N(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=`<span class=\"material-icons-round\">${s}</span><span>${e}</span>`,n.appendChild(a),requestAnimationFrame(()=>a.classList.add(\"show\")),setTimeout(()=>{a.classList.remove(\"show\"),setTimeout(()=>a.remove(),300)},3e3)}},672(e,t,n){n.d(t,{H:()=>s,O:()=>o});var a=n(521);function s(e){return{Authorization:`Token ${e||a.f9}`,Accept:\"application/json\",\"Content-Type\":\"application/json\",\"X-Client-Version\":a.fZ}}function o(){return{Accept:\"application/vnd.github.v3+json\"}}},521(e,t,n){n.d(t,{YU:()=>r,d_:()=>m,eW:()=>i,f9:()=>s,fZ:()=>o,fv:()=>l,pe:()=>d,tE:()=>a});const a=\"https://api.bessa.app/v1\",s=\"c3418725e95a9f90e3645cbc846b4d67c7c66131\",o=\"v1.6.11\",i=591,r=7,l=3e5,c=\"TauNeutrino/kantine-overview\",d=`https://api.github.com/repos/${c}`,m=`https://htmlpreview.github.io/?https://github.com/${c}/blob`},901(e,t,n){n.d(t,{BT:()=>o,BY:()=>m,K8:()=>u,Kl:()=>g,L:()=>d,Ny:()=>c,O5:()=>b,UD:()=>E,Xt:()=>f,cc:()=>A,di:()=>k,gX:()=>l,iw:()=>L,lt:()=>w,pK:()=>v,p_:()=>s,qo:()=>y,sw:()=>r,tn:()=>p,vW:()=>i,yz:()=>h});var a=n(413);let s=[],o=(0,a.sn)(new Date),i=(new Date).getFullYear(),r=\"this-week\",l=localStorage.getItem(\"kantine_authToken\"),c=localStorage.getItem(\"kantine_currentUser\"),d=new Map,m=new Set(JSON.parse(localStorage.getItem(\"kantine_flags\")||\"[]\")),u=null,g=localStorage.getItem(\"kantine_lang\")||\"de\",h=JSON.parse(localStorage.getItem(\"kantine_highlightTags\")||\"[]\");function p(e){s=e}function f(e){o=e}function v(e){i=e}function y(e){r=e}function b(e){l=e}function w(e){c=e}function k(e){d=e}function A(e){u=e}function E(e){g=e}function L(e){h=e}},842(e,t,n){n.d(t,{Gk:()=>u,Mb:()=>f,OR:()=>c,Ux:()=>m,gJ:()=>l,showErrorModal:()=>p});var a=n(901),s=n(413),o=n(521),i=n(672),r=n(367);function l(){const e=document.getElementById(\"btn-next-week\");let t=a.BT+1,n=a.vW;t>52&&(t=1,n++);const s=a.p_.find(e=>e.weekNumber===t&&e.year===n);let o=0,i=0,l=0,c=0;s&&s.days&&s.days.forEach(e=>{if(e.items&&e.items.length>0){o++;const t=e.items.some(e=>e.available);t&&i++;let n=!1;e.items.forEach(t=>{const s=t.articleId||parseInt(t.id.split(\"_\")[1]),o=`${e.date}_${s}`;a.L.has(o)&&a.L.get(o).length>0&&(n=!0)}),n&&l++,t&&!n&&c++}});let d=e.querySelector(\".nav-badge\");if(o>0){d||(d=document.createElement(\"span\"),d.className=\"nav-badge\",e.appendChild(d)),d.title=`${l} bestellt / ${i} bestellbar / ${o} gesamt`,d.innerHTML=`<span class=\"ordered\">${l}</span><span class=\"separator\">/</span><span class=\"orderable\">${i}</span><span class=\"separator\">/</span><span class=\"total\">${o}</span>`,d.classList.remove(\"badge-violet\",\"badge-green\",\"badge-red\",\"badge-blue\"),l>0&&0===c?d.classList.add(\"badge-violet\"):c>0?d.classList.add(\"badge-green\"):0===i?d.classList.add(\"badge-red\"):d.classList.add(\"badge-blue\");let a=0;if(s&&s.days&&s.days.forEach(e=>{e.items.forEach(e=>{const t=(0,r.BM)(e.name),n=(0,r.BM)(e.description);(t.length>0||n.length>0)&&a++})}),a>0&&(d.innerHTML+=`<span class=\"highlight-count\" title=\"${a} Highlight Men\u00fcs\">(${a})</span>`,d.title+=` \u2022 ${a} Highlights gefunden`,d.classList.add(\"has-highlights\")),0===l){e.classList.add(\"new-week-available\");const a=`kantine_notified_nextweek_${n}_${t}`;localStorage.getItem(a)||(localStorage.setItem(a,\"true\"),(0,r.P0)(\"Neue Men\u00fcdaten f\u00fcr n\u00e4chste Woche verf\u00fcgbar!\",\"info\"))}else e.classList.remove(\"new-week-available\")}else d&&d.remove()}function c(){const e=document.getElementById(\"menu-container\");if(!e)return;e.innerHTML=\"\";let t=a.BT,n=a.vW;\"next-week\"===a.sw&&(t++,t>52&&(t=1,n++));const o=a.p_.flatMap(e=>e.days||[]).filter(e=>{const a=new Date(e.date);return(0,s.sn)(a)===t&&(0,s.Ao)(a)===n});if(0===o.length)return e.innerHTML=`\\n <div class=\"empty-state\">\\n <p>Keine Men\u00fcdaten f\u00fcr KW ${t} (${n}) verf\u00fcgbar.</p>\\n <small>Versuchen Sie eine andere Woche oder schauen Sie sp\u00e4ter vorbei.</small>\\n </div>`,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 s=n.articleId||parseInt(n.id.split(\"_\")[1]),o=`${e.date}_${s}`,i=a.L.get(o)||[];i.length>0&&(t+=n.price*i.length)})});const n=document.getElementById(\"weekly-cost-display\");t>0?(n.innerHTML=`<span class=\"material-icons-round\">shopping_bag</span> <span>Gesamt: ${t.toFixed(2).replace(\".\",\",\")} \u20ac</span>`,n.classList.remove(\"hidden\")):n.classList.add(\"hidden\")}(o);const i=document.getElementById(\"header-week-info\"),l=\"this-week\"===a.sw?\"Diese Woche\":\"N\u00e4chste Woche\";i.innerHTML=`\\n <div class=\"header-week-title\">${l}</div>\\n <div class=\"header-week-subtitle\">Week ${t} \u2022 ${n}</div>`;const c=document.createElement(\"div\");c.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(e=>{const t=function(e){if(!e.items||0===e.items.length)return null;const t=document.createElement(\"div\");t.className=\"menu-card\";const n=new Date,o=new Date(e.date);let i=!1;if(e.orderCutoff)i=n>=new Date(e.orderCutoff);else{const t=new Date;t.setHours(0,0,0,0);const n=new Date(e.date);n.setHours(0,0,0,0),i=n<t}i&&t.classList.add(\"past-day\");const l=[];e.items&&e.items.forEach(t=>{const n=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${n}`,o=(a.L.get(s)||[]).length;if(o>0){const e=t.name.match(/([M][1-9][Ff]?)/);if(e){let t=e[1];o>1&&(t+=\"+\"),l.push(t)}}});const c=document.createElement(\"div\");c.className=\"card-header\";const d=o.toLocaleDateString(\"de-DE\",{day:\"2-digit\",month:\"2-digit\"}),m=l.map(e=>`<span class=\"menu-code-badge\">${e}</span>`).join(\"\");let u=\"\";const g=e.items&&e.items.some(t=>{const n=t.articleId||parseInt(t.id.split(\"_\")[1]),s=`${e.date}_${n}`;return a.L.has(s)&&a.L.get(s).length>0}),h=e.items&&e.items.some(e=>e.available);u=g?\"header-violet\":h&&!i?\"header-green\":\"header-red\";u&&c.classList.add(u);c.innerHTML=`\\n <div class=\"day-header-left\">\\n <span class=\"day-name\">${(0,s.FS)(e.weekday)}</span>\\n <div class=\"day-badges\">${m}</div>\\n </div>\\n <span class=\"day-date\">${d}</span>`,t.appendChild(c);const p=document.createElement(\"div\");p.className=\"card-body\";const f=(new Date).toISOString().split(\"T\")[0],v=e.date===f,y=[...e.items].sort((t,n)=>{if(v){const s=t.articleId||parseInt(t.id.split(\"_\")[1]),o=n.articleId||parseInt(n.id.split(\"_\")[1]),i=a.L.has(`${e.date}_${s}`),r=a.L.has(`${e.date}_${o}`);if(i&&!r)return-1;if(!i&&r)return 1}return t.name.localeCompare(n.name)});return y.forEach(t=>{const o=document.createElement(\"div\");o.className=\"menu-item\";const l=t.articleId||parseInt(t.id.split(\"_\")[1]),c=`${e.date}_${l}`,d=(a.L.get(c)||[]).length;let m=\"\";m=t.available?t.amountTracking?`<span class=\"badge available\">Verf\u00fcgbar (${t.availableAmount})</span>`:'<span class=\"badge available\">Verf\u00fcgbar</span>':'<span class=\"badge sold-out\">Ausverkauft</span>';let u=\"\";if(d>0){u=`<span class=\"badge ordered\"><span class=\"material-icons-round\">check_circle</span> Bestellt${d>1?`<span class=\"order-count-badge\">${d}</span>`:\"\"}</span>`,o.classList.add(\"ordered\"),new Date(e.date).toDateString()===n.toDateString()&&o.classList.add(\"today-ordered\")}const g=`${e.date}_${l}`,h=a.BY.has(g);h&&o.classList.add(t.available?\"flagged-available\":\"flagged-sold-out\");const f=[...new Set([...(0,r.BM)(t.name),...(0,r.BM)(t.description)])];f.length>0&&o.classList.add(\"highlight-glow\");let v=\"\",y=\"\",b=\"\";if(a.gX&&!i){const n=h?\"notifications_active\":\"notifications_none\",a=h?\"btn-flag active\":\"btn-flag\",o=h?\"Benachrichtigung deaktivieren\":\"Benachrichtigen wenn verf\u00fcgbar\";if(t.available&&!h||(b=`<button class=\"${a}\" data-date=\"${e.date}\" data-article=\"${l}\" data-name=\"${(0,s.ZD)(t.name)}\" data-cutoff=\"${e.orderCutoff}\" title=\"${o}\"><span class=\"material-icons-round\">${n}</span></button>`),t.available&&(v=d>0?`<button class=\"btn-order btn-order-compact\" data-date=\"${e.date}\" data-article=\"${l}\" data-name=\"${(0,s.ZD)(t.name)}\" data-price=\"${t.price}\" data-desc=\"${(0,s.ZD)(t.description||\"\")}\" title=\"${(0,s.ZD)(t.name)} nochmal bestellen\"><span class=\"material-icons-round\">add</span></button>`:`<button class=\"btn-order\" data-date=\"${e.date}\" data-article=\"${l}\" data-name=\"${(0,s.ZD)(t.name)}\" data-price=\"${t.price}\" data-desc=\"${(0,s.ZD)(t.description||\"\")}\" title=\"${(0,s.ZD)(t.name)} bestellen\"><span class=\"material-icons-round\">add_shopping_cart</span> Bestellen</button>`),d>0){const n=1===d?\"close\":\"remove\",a=1===d?\"Bestellung stornieren\":\"Eine Bestellung stornieren\";y=`<button class=\"btn-cancel\" data-date=\"${e.date}\" data-article=\"${l}\" data-name=\"${(0,s.ZD)(t.name)}\" title=\"${a}\"><span class=\"material-icons-round\">${n}</span></button>`}}let w=\"\";if(f.length>0){w=`<div class=\"matched-tags\">${f.map(e=>`<span class=\"tag-badge-small\"><span class=\"material-icons-round\" style=\"font-size:10px;margin-right:2px\">star</span>${(0,s.ZD)(e)}</span>`).join(\"\")}</div>`}o.innerHTML=`\\n <div class=\"item-header\">\\n <span class=\"item-name\">${(0,s.ZD)(t.name)}</span>\\n <span class=\"item-price\">${t.price.toFixed(2)} \u20ac</span>\\n </div>\\n <div class=\"item-status-row\">\\n ${u}\\n ${y}\\n ${v}\\n ${b}\\n <div class=\"badges\">${m}</div>\\n </div>\\n ${w}\\n <p class=\"item-desc\">${(0,s.ZD)((0,s.PC)(t.description))}</p>`;const k=o.querySelector(\".btn-order\");k&&k.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;t.disabled=!0,t.classList.add(\"loading\"),(0,r.wH)(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,parseFloat(t.dataset.price),t.dataset.desc||\"\").finally(()=>{t.disabled=!1,t.classList.remove(\"loading\")})});const A=o.querySelector(\".btn-cancel\");A&&A.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;t.disabled=!0,(0,r.N4)(t.dataset.date,parseInt(t.dataset.article),t.dataset.name).finally(()=>{t.disabled=!1})});const E=o.querySelector(\".btn-flag\");E&&E.addEventListener(\"click\",e=>{e.stopPropagation();const t=e.currentTarget;(0,r.PQ)(t.dataset.date,parseInt(t.dataset.article),t.dataset.name,t.dataset.cutoff)}),p.appendChild(o)}),t.appendChild(p),t}(e);t&&c.appendChild(t)}),e.appendChild(c),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<n;e++){let n=0;const a=[];t.forEach(t=>{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`})}}(c),0)}async function d(e){const t=e?`${o.pe}/tags?per_page=20`:`${o.pe}/releases?per_page=20`,n=await fetch(t,{headers:(0,i.O)()});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.d_}/${n}/dist/install.html`,body:t.body||\"\"}})}async function m(){const e=\"v1.6.11\",t=\"true\"===localStorage.getItem(\"kantine_dev_mode\");try{const n=await d(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\"})`),!(0,s.U4)(a,e))return;console.log(`[Kantine] Update verf\u00fcgbar: ${a}`);const o=document.querySelector(\".header-left h1\");if(o&&!o.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;\",o.appendChild(e)}}catch(e){console.warn(\"[Kantine] Version check failed:\",e)}}function u(){const e=document.getElementById(\"version-modal\"),t=document.getElementById(\"version-list-container\"),n=document.getElementById(\"dev-mode-toggle\"),a=\"v1.6.11\";if(!e)return;e.classList.remove(\"hidden\");const o=document.getElementById(\"version-current\");o&&(o.textContent=a);const i=\"true\"===localStorage.getItem(\"kantine_dev_mode\");async function r(e){const o=n.checked;function i(e){if(!e||!e.length)return void(t.innerHTML='<p style=\"color:var(--text-secondary);\">Keine Versionen gefunden.</p>');t.innerHTML='<ul class=\"version-list\"></ul>';const n=t.querySelector(\".version-list\");e.forEach(e=>{const t=e.tag===a,o=(0,s.U4)(e.tag,a),i=document.createElement(\"li\");i.className=\"version-item\"+(t?\" current\":\"\");let r=\"\";t?r='<span class=\"badge-current\">\u2713 Installiert</span>':o&&(r='<span class=\"badge-new\">\u2b06 Neu!</span>');let l=\"\";t||(l=`<a href=\"${e.url}\" target=\"_blank\" class=\"install-link\" title=\"${e.tag} installieren\">Installieren</a>`),i.innerHTML=`\\n <div class=\"version-info\">\\n <strong>${e.tag}</strong>\\n ${r}\\n </div>\\n ${l}\\n `,n.appendChild(i)})}t.innerHTML='<p style=\"color:var(--text-secondary);\">Lade Versionen...</p>';try{const e=localStorage.getItem(\"kantine_version_cache\");let t=null;if(e)try{t=JSON.parse(e)}catch(e){}t&&t.devMode===o&&t.versions&&i(t.versions);const n=await d(o),a=JSON.stringify(n);a!==(t?JSON.stringify(t.versions):\"\")&&(localStorage.setItem(\"kantine_version_cache\",JSON.stringify({timestamp:Date.now(),devMode:o,versions:n})),i(n))}catch(e){t.innerHTML=`<p style=\"color:#e94560;\">Fehler: ${e.message}</p>`}}n.checked=i,r(),n.onchange=()=>{localStorage.setItem(\"kantine_dev_mode\",n.checked),localStorage.removeItem(\"kantine_version_cache\"),r()}}function g(){if(!a.gX||!a.Ny)return void h();const e=new Date,t=e.getDay();if(0===t||6===t)return void h();const n=e.toISOString().split(\"T\")[0];let s=!1;for(const e of a.L.keys())if(e.startsWith(n)){s=!0;break}if(s)return void h();const o=new Date;o.setHours(10,0,0,0);const i=o-e;if(i<=0)return void h();const r=Math.floor(i/36e5),l=Math.floor(i%36e5/6e4),c=document.querySelector(\".header-center-wrapper\");if(!c)return;let d=document.getElementById(\"order-countdown\");if(d||(d=document.createElement(\"div\"),d.id=\"order-countdown\",c.insertBefore(d,c.firstChild)),d.innerHTML=`<span>Bestellschluss:</span> <strong>${r}h ${l}m</strong>`,i<36e5){d.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 d.classList.remove(\"urgent\")}function h(){const e=document.getElementById(\"order-countdown\");e&&e.remove()}function p(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 <div class=\"modal-content\">\\n <div class=\"modal-header\">\\n <h2 style=\"color: var(--error-color); display: flex; align-items: center; gap: 10px;\">\\n <span class=\"material-icons-round\">signal_wifi_off</span>\\n ${e}\\n </h2>\\n </div>\\n <div style=\"padding: 20px;\">\\n <p style=\"margin-bottom: 15px; color: var(--text-primary);\">${t}</p>\\n <div style=\"margin-top: 20px; display: flex; justify-content: center;\">\\n <button id=\"btn-error-redirect\" style=\"\\n background-color: var(--accent-color); \\n color: white; \\n padding: 12px 24px; \\n border-radius: 8px; \\n border: none; \\n font-weight: 600; \\n cursor: pointer;\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n width: 100%;\\n justify-content: center;\\n transition: transform 0.1s;\\n \">\\n ${n}\\n <span class=\"material-icons-round\">open_in_new</span>\\n </button>\\n </div>\\n </div>\\n </div>\\n `,document.body.appendChild(o),document.getElementById(\"btn-error-redirect\").addEventListener(\"click\",()=>{window.location.href=a}),requestAnimationFrame(()=>{o.classList.remove(\"hidden\")})}function f(){const e=document.getElementById(\"alarm-bell\"),t=document.getElementById(\"alarm-bell-icon\");if(!e||!t)return;if(0===a.BY.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 a.p_)if(e.days){for(const t of e.days)if(t.items){for(const e of t.items)if(e.available&&a.BY.has(e.id)){n=!0;break}if(n)break}if(n)break}let o=localStorage.getItem(\"kantine_last_checked\"),i=\"gerade eben\";o||(o=(new Date).toISOString(),localStorage.setItem(\"kantine_last_checked\",o));const r=new Date(o);i=(0,s.gs)(r),e.title=`Zuletzt gepr\u00fcft: ${i}`,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)\")}setInterval(g,6e4),setTimeout(g,1e3)},413(e,t,n){n.d(t,{Ao:()=>o,FS:()=>i,PC:()=>u,U4:()=>l,ZD:()=>r,gs:()=>c,sn:()=>s});var a=n(901);function s(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 o(e){const t=new Date(e.getTime());return t.setDate(t.getDate()+3-(t.getDay()+6)%7),t.getFullYear()}function i(e){return{Monday:\"Montag\",Tuesday:\"Dienstag\",Wednesday:\"Mittwoch\",Thursday:\"Donnerstag\",Friday:\"Freitag\",Saturday:\"Samstag\",Sunday:\"Sonntag\"}[e]||e}function r(e){const t=document.createElement(\"div\");return t.textContent=e||\"\",t.innerHTML}function l(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<Math.max(n.length,a.length);e++){if((n[e]||0)>(a[e]||0))return!0;if((n[e]||0)<(a[e]||0))return!1}return!1}function c(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.`}const d=[\"apfel\",\"achtung\",\"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\"],m=[\"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 u(e){if(\"all\"===a.Kl)return e||\"\";const t=function(e){if(!e)return{de:\"\",en:\"\",raw:\"\"};let t=e.replace(/(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?=\\S)(?!\\s*\\/)/g,\"($1)\\n\u2022 \");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;d.includes(a)?s=a.length:d.forEach(e=>{a.includes(e)&&e.length>s&&(s=e.length)}),m.includes(a)?o=a.length:m.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;e<t.length;e++){const o=t.slice(0,e),i=t.slice(e),r=n(o),l=n(i),c=i[0];let d=0;/^[A-Z\u00c4\u00d6\u00dc]/.test(c)&&(d=1);const m=r.en-r.de+(l.de-l.en)+d,u=r.en>r.de||r.en>0,g=l.de+d>l.en;u&&g&&m>s&&(s=m,a=e)}return-1!==a?{enPart:t.slice(0,a).join(\" \"),nextDe:t.slice(a).join(\" \")}:{enPart:e,nextDe:\"\"}}t.startsWith(\"\u2022 \")||(t=\"\u2022 \"+t);const s=/(.*?)(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*(?!\\s*[/])/g;let o;const i=[];let r=0;for(;null!==(o=s.exec(e));)o.index>r&&i.push(e.substring(r,o.index).trim()),i.push(o[0].trim()),r=s.lastIndex;r<e.length&&i.push(e.substring(r).trim()),0===i.length&&\"\"!==e.trim()&&i.push(e.trim());const l=[],c=[];for(let e of i){let t=e.match(/(.*?)(?:\\(|(?:\\/|\\s|^))([A-Z,]+)\\)\\s*$/),n=e,s=\"\",o=\"\";t&&(n=t[1].trim(),o=t[2],s=` (${o})`);const i=n.split(/\\s*\\/\\s*(?![A-Z,]+$)/);if(i.length>=2){const e=i[0].trim();let t=i.slice(1).join(\" / \").trim();const n=a(t);if(n.nextDe){l.push(e+s),c.push(n.enPart+s);const t=n.nextDe+s;l.push(t),c.push(t)}else{const n=t+s,a=e.includes(s.trim())?e:e+s;l.push(a),c.push(n)}}else{const e=a(n);e.nextDe?(c.push(e.enPart+s),l.push(e.nextDe+s)):(l.push(n+s),c.push(n+s))}}let u=l.join(\"\\n\u2022 \");l.length>0&&!u.startsWith(\"\u2022 \")&&(u=\"\u2022 \"+u);let g=c.join(\"\\n\u2022 \");return c.length>0&&!g.startsWith(\"\u2022 \")&&(g=\"\u2022 \"+g),{de:u,en:g,raw:t}}(e);return\"en\"===a.Kl?t.en||t.raw:t.de||t.raw}}},t={};function n(a){var s=t[a];if(void 0!==s)return s.exports;var o=t[a]={exports:{}};return e[a](o,o.exports,n),o.exports}n.d=(e,t)=>{for(var a in t)n.o(t,a)&&!n.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:t[a]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t);var a=n(901);var s=n(367),o=n(842),i=n(521),r=n(672);if(window.__KANTINE_LOADED)console.log(\"Kantine Wrapper already loaded.\");else{window.__KANTINE_LOADED=!0,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, \",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)}const t=`\\n <div id=\"kantine-wrapper\">\\n <header class=\"app-header\">\\n <div class=\"header-content\">\\n <div class=\"brand\">\\n <img src=\"data:image/png;base64, \" alt=\"Logo\" class=\"logo-img\" style=\"height: 2em; width: 2em; object-fit: contain;\">\\n <div class=\"header-left\">\\n <h1>Kantinen \u00dcbersicht <small class=\"version-tag\" style=\"font-size: 0.6em; opacity: 0.7; font-weight: 400; cursor: pointer;\" title=\"Klick f\u00fcr Versionsmen\u00fc\">v1.6.11</small></h1>\\n <div id=\"last-updated-subtitle\" class=\"subtitle\"></div>\\n </div>\\n <div class=\"nav-group\" style=\"margin-left: 1rem;\">\\n <button id=\"btn-this-week\" class=\"nav-btn active\" title=\"Men\u00fc dieser Woche anzeigen\">Diese Woche</button>\\n <button id=\"btn-next-week\" class=\"nav-btn\" title=\"Men\u00fc n\u00e4chster Woche anzeigen\">N\u00e4chste Woche</button>\\n </div>\\n <button id=\"alarm-bell\" class=\"icon-btn hidden\" aria-label=\"Benachrichtigungen\" title=\"Keine beobachteten Men\u00fcs\" style=\"margin-left: -0.5rem;\">\\n <span class=\"material-icons-round\" id=\"alarm-bell-icon\" style=\"color:var(--text-secondary); transition: color 0.3s;\">notifications</span>\\n </button>\\n </div>\\n <div class=\"header-center-wrapper\">\\n <div id=\"lang-toggle\" class=\"lang-toggle\" title=\"Sprache der Men\u00fcbeschreibung\">\\n <button class=\"lang-btn${\"de\"===a.Kl?\" active\":\"\"}\" data-lang=\"de\">DE</button>\\n <button class=\"lang-btn${\"en\"===a.Kl?\" active\":\"\"}\" data-lang=\"en\">EN</button>\\n <button class=\"lang-btn${\"all\"===a.Kl?\" active\":\"\"}\" data-lang=\"all\">ALL</button>\\n </div>\\n <div id=\"header-week-info\" class=\"header-week-info\"></div>\\n <div id=\"weekly-cost-display\" class=\"weekly-cost hidden\"></div>\\n </div>\\n <div class=\"controls\">\\n <button id=\"btn-refresh\" class=\"icon-btn\" aria-label=\"Men\u00fcdaten aktualisieren\" title=\"Men\u00fcdaten neu laden\">\\n <span class=\"material-icons-round\">refresh</span>\\n </button>\\n <button id=\"btn-history\" class=\"icon-btn\" aria-label=\"Bestellhistorie\" title=\"Bestellhistorie\">\\n <span class=\"material-icons-round\">receipt_long</span>\\n </button>\\n <button id=\"btn-highlights\" class=\"icon-btn\" aria-label=\"Pers\u00f6nliche Highlights verwalten\" title=\"Pers\u00f6nliche Highlights verwalten\">\\n <span class=\"material-icons-round\">label</span>\\n </button>\\n <button id=\"theme-toggle\" class=\"icon-btn\" aria-label=\"Toggle Theme\" title=\"Erscheinungsbild (Hell/Dunkel) wechseln\">\\n <span class=\"material-icons-round theme-icon\">light_mode</span>\\n </button>\\n <button id=\"btn-login-open\" class=\"user-badge-btn icon-btn-small\" title=\"Mit Bessa.app Account anmelden\">\\n <span class=\"material-icons-round\">login</span>\\n <span>Anmelden</span>\\n </button>\\n <div id=\"user-info\" class=\"user-badge hidden\">\\n <span class=\"material-icons-round\">person</span>\\n <span id=\"user-id-display\"></span>\\n <button id=\"btn-logout\" class=\"icon-btn-small\" aria-label=\"Logout\" title=\"Von Bessa.app abmelden\">\\n <span class=\"material-icons-round\">logout</span>\\n </button>\\n </div>\\n </div>\\n </div>\\n </header>\\n\\n <div id=\"login-modal\" class=\"modal hidden\">\\n <div class=\"modal-content\">\\n <div class=\"modal-header\">\\n <h2>Login</h2>\\n <button id=\"btn-login-close\" class=\"icon-btn\" aria-label=\"Close\" title=\"Schlie\u00dfen\">\\n <span class=\"material-icons-round\">close</span>\\n </button>\\n </div>\\n <form id=\"login-form\">\\n <div class=\"form-group\">\\n <label for=\"employee-id\">Mitarbeiternummer</label>\\n <input type=\"text\" id=\"employee-id\" name=\"employee-id\" placeholder=\"z.B. 2041\" required>\\n <small class=\"help-text\">Deine offizielle Knapp Mitarbeiternummer.</small>\\n </div>\\n <div class=\"form-group\">\\n <label for=\"password\">Passwort</label>\\n <input type=\"password\" id=\"password\" name=\"password\" placeholder=\"Bessa Passwort\" required>\\n <small class=\"help-text\">Das Passwort f\u00fcr deinen Bessa Account.</small>\\n </div>\\n <div id=\"login-error\" class=\"error-msg hidden\"></div>\\n <div class=\"modal-actions\">\\n <button type=\"submit\" class=\"btn-primary wide\">Einloggen</button>\\n </div>\\n </form>\\n </div>\\n </div>\\n\\n <div id=\"progress-modal\" class=\"modal hidden\">\\n <div class=\"modal-content\">\\n <div class=\"modal-header\">\\n <h2>Men\u00fcdaten aktualisieren</h2>\\n </div>\\n <div class=\"modal-body\" style=\"padding: 20px;\">\\n <div class=\"progress-container\">\\n <div class=\"progress-bar\">\\n <div id=\"progress-fill\" class=\"progress-fill\"></div>\\n </div>\\n <div id=\"progress-percent\" class=\"progress-percent\">0%</div>\\n </div>\\n <p id=\"progress-message\" class=\"progress-message\">Initialisierung...</p>\\n </div>\\n </div>\\n </div>\\n\\n <div id=\"highlights-modal\" class=\"modal hidden\">\\n <div class=\"modal-content\">\\n <div class=\"modal-header\">\\n <h2>Meine Highlights</h2>\\n <button id=\"btn-highlights-close\" class=\"icon-btn\" aria-label=\"Close\" title=\"Schlie\u00dfen\">\\n <span class=\"material-icons-round\">close</span>\\n </button>\\n </div>\\n <div class=\"modal-body\">\\n <p style=\"margin-bottom: 1rem; color: var(--text-secondary);\">\\n Markiere Men\u00fcs automatisch, wenn sie diese Schlagw\u00f6rter enthalten.\\n </p>\\n <div class=\"input-group\">\\n <input type=\"text\" id=\"tag-input\" placeholder=\"z.B. Schnitzel, Vegetarisch...\" title=\"Neues Schlagwort zum Hervorheben eingeben\">\\n <button id=\"btn-add-tag\" class=\"btn-primary\" title=\"Schlagwort zur Liste hinzuf\u00fcgen\">Hinzuf\u00fcgen</button>\\n </div>\\n <div id=\"tags-list\"></div>\\n </div>\\n </div>\\n </div>\\n\\n <div id=\"history-modal\" class=\"modal hidden\">\\n <div class=\"modal-content history-modal-content\">\\n <div class=\"modal-header\">\\n <h2>Bestellhistorie</h2>\\n <button id=\"btn-history-close\" class=\"icon-btn\" aria-label=\"Close\" title=\"Schlie\u00dfen\">\\n <span class=\"material-icons-round\">close</span>\\n </button>\\n </div>\\n <div class=\"modal-body\">\\n <div id=\"history-loading\" class=\"hidden\">\\n <p id=\"history-progress-text\" style=\"text-align: center; margin-bottom: 1rem; color: var(--text-secondary);\">Lade Historie...</p>\\n <div class=\"progress-container\">\\n <div class=\"progress-bar\">\\n <div id=\"history-progress-fill\" class=\"progress-fill\"></div>\\n </div>\\n </div>\\n </div>\\n <div id=\"history-content\">\\n </div>\\n </div>\\n </div>\\n </div>\\n\\n <div id=\"version-modal\" class=\"modal hidden\">\\n <div class=\"modal-content\">\\n <div class=\"modal-header\">\\n <h2>\ud83d\udce6 Versionen</h2>\\n <button id=\"btn-version-close\" class=\"icon-btn\" aria-label=\"Close\" title=\"Schlie\u00dfen\">\\n <span class=\"material-icons-round\">close</span>\\n </button>\\n </div>\\n <div class=\"modal-body\">\\n <div style=\"margin-bottom: 1rem;\">\\n <strong>Aktuell:</strong> <span id=\"version-current\">v1.6.11</span>\\n </div>\\n <div class=\"dev-toggle\">\\n <label style=\"display:flex;align-items:center;gap:8px;cursor:pointer;\">\\n <input type=\"checkbox\" id=\"dev-mode-toggle\">\\n <span>Dev-Mode (alle Tags anzeigen)</span>\\n </label>\\n </div>\\n <div id=\"version-list-container\" style=\"margin-top:1rem; max-height: 250px; overflow-y: auto;\">\\n <p style=\"color:var(--text-secondary);\">Lade Versionen...</p>\\n </div>\\n <div style=\"margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--border-color); display: flex; flex-direction: column; gap: 0.75rem; font-size: 0.9em;\">\\n <a href=\"https://github.com/TauNeutrino/kantine-overview/issues\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color: var(--primary-color); text-decoration: none; display: flex; align-items: center; gap: 0.5rem;\" title=\"Melde einen Fehler auf GitHub\">\\n <span class=\"material-icons-round\" style=\"font-size: 1.2em;\">bug_report</span> Fehler melden\\n </a>\\n <a href=\"https://github.com/TauNeutrino/kantine-overview/discussions/categories/ideas\" target=\"_blank\" rel=\"noopener noreferrer\" style=\"color: var(--primary-color); text-decoration: none; display: flex; align-items: center; gap: 0.5rem;\" title=\"Schlage ein neues Feature auf GitHub vor\">\\n <span class=\"material-icons-round\" style=\"font-size: 1.2em;\">lightbulb</span> Feature vorschlagen\\n </a>\\n <button id=\"btn-clear-cache\" style=\"background: none; border: none; padding: 0; color: var(--error-color); text-decoration: none; display: flex; align-items: center; gap: 0.5rem; cursor: pointer; text-align: left; font-size: inherit; font-family: inherit;\" title=\"L\u00f6scht alle lokalen Daten & erzwingt einen Neuladen\">\\n <span class=\"material-icons-round\" style=\"font-size: 1.2em;\">delete_forever</span> Lokalen Cache leeren\\n </button>\\n </div>\\n </div>\\n </div>\\n </div>\\n\\n <main class=\"container\">\\n <div id=\"last-updated-banner\" class=\"banner hidden\">\\n <span class=\"material-icons-round\">update</span>\\n <span id=\"last-updated-text\">Gerade aktualisiert</span>\\n </div>\\n <div id=\"loading\" class=\"loading-state\">\\n <div class=\"spinner\"></div>\\n <p>Lade Men\u00fcdaten...</p>\\n </div>\\n <div id=\"menu-container\" class=\"menu-grid\"></div>\\n </main>\\n\\n <footer class=\"app-footer\">\\n <p>Jetzt Bessa Einfach! &bull; Knapp-Kantine Wrapper &bull; <span id=\"current-year\">${(new Date).getFullYear()}</span> by Kaufi \ud83d\ude03\ud83d\udc4d mit Hilfe von KI \ud83e\udd16</p>\\n </footer>\\n </div>`;document.body.innerHTML=t}(),function(){const e=document.getElementById(\"btn-this-week\"),t=document.getElementById(\"btn-next-week\"),n=document.getElementById(\"btn-refresh\"),l=document.getElementById(\"theme-toggle\"),c=document.getElementById(\"btn-login-open\"),d=document.getElementById(\"btn-login-close\"),m=document.getElementById(\"btn-logout\"),u=document.getElementById(\"login-form\"),g=document.getElementById(\"login-modal\"),h=document.getElementById(\"btn-highlights\"),p=document.getElementById(\"highlights-modal\"),f=document.getElementById(\"btn-highlights-close\"),v=document.getElementById(\"btn-add-tag\"),y=document.getElementById(\"tag-input\"),b=document.getElementById(\"btn-history\"),w=document.getElementById(\"history-modal\"),k=document.getElementById(\"btn-history-close\");document.querySelectorAll(\".lang-btn\").forEach(e=>{e.addEventListener(\"click\",()=>{(0,a.UD)(e.dataset.lang),localStorage.setItem(\"kantine_lang\",e.dataset.lang),document.querySelectorAll(\".lang-btn\").forEach(e=>e.classList.remove(\"active\")),e.classList.add(\"active\"),(0,o.OR)()})}),h&&h.addEventListener(\"click\",()=>{p.classList.remove(\"hidden\")}),f&&f.addEventListener(\"click\",()=>{p.classList.add(\"hidden\")}),b.addEventListener(\"click\",()=>{a.gX?(w.classList.remove(\"hidden\"),(0,s.Aq)()):g.classList.remove(\"hidden\")}),k.addEventListener(\"click\",()=>{w.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===w&&w.classList.add(\"hidden\"),e.target===p&&p.classList.add(\"hidden\")});const A=document.querySelector(\".version-tag\"),E=document.getElementById(\"version-modal\"),L=document.getElementById(\"btn-version-close\");A&&A.addEventListener(\"click\",e=>{e.preventDefault(),e.stopPropagation(),(0,o.Gk)()}),L&&L.addEventListener(\"click\",()=>{E.classList.add(\"hidden\")});const I=document.getElementById(\"btn-clear-cache\");I&&I.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===E&&E.classList.add(\"hidden\")}),v.addEventListener(\"click\",()=>{const e=y.value;(0,s.oL)(e)&&(y.value=\"\",(0,s.Y1)())}),y.addEventListener(\"keypress\",e=>{\"Enter\"===e.key&&v.click()});const B=localStorage.getItem(\"theme\"),S=window.matchMedia(\"(prefers-color-scheme: dark)\").matches,D=l.querySelector(\".theme-icon\");\"dark\"===B||!B&&S?(document.documentElement.setAttribute(\"data-theme\",\"dark\"),D.textContent=\"dark_mode\"):(document.documentElement.setAttribute(\"data-theme\",\"light\"),D.textContent=\"light_mode\"),l.addEventListener(\"click\",()=>{const e=\"dark\"===document.documentElement.getAttribute(\"data-theme\")?\"light\":\"dark\";document.documentElement.setAttribute(\"data-theme\",e),localStorage.setItem(\"theme\",e),D.textContent=\"dark\"===e?\"dark_mode\":\"light_mode\"}),e.addEventListener(\"click\",()=>{\"this-week\"!==a.sw&&((0,a.qo)(\"this-week\"),e.classList.add(\"active\"),t.classList.remove(\"active\"),(0,o.OR)())}),t.addEventListener(\"click\",()=>{t.classList.remove(\"new-week-available\"),\"next-week\"!==a.sw&&((0,a.qo)(\"next-week\"),t.classList.add(\"active\"),e.classList.remove(\"active\"),(0,o.OR)())}),n.addEventListener(\"click\",()=>{a.gX?(0,s.m9)():g.classList.remove(\"hidden\")}),c.addEventListener(\"click\",()=>{g.classList.remove(\"hidden\"),document.getElementById(\"login-error\").classList.add(\"hidden\"),u.reset()}),d.addEventListener(\"click\",()=>{g.classList.add(\"hidden\")}),window.addEventListener(\"click\",e=>{e.target===g&&g.classList.add(\"hidden\")}),u.addEventListener(\"submit\",async e=>{e.preventDefault();const t=document.getElementById(\"employee-id\").value.trim(),n=document.getElementById(\"password\").value,o=document.getElementById(\"login-error\"),l=u.querySelector('button[type=\"submit\"]'),c=l.textContent;l.disabled=!0,l.textContent=\"Wird eingeloggt...\";try{const e=`knapp-${t}@bessa.app`,l=await fetch(`${i.tE}/auth/login/`,{method:\"POST\",headers:(0,r.H)(i.f9),body:JSON.stringify({email:e,password:n})}),c=await l.json();if(l.ok){(0,a.O5)(c.key),(0,a.lt)(t),localStorage.setItem(\"kantine_authToken\",c.key),localStorage.setItem(\"kantine_currentUser\",t);try{const e=await fetch(`${i.tE}/auth/user/`,{headers:(0,r.H)(c.key)});if(e.ok){const t=await e.json();t.first_name&&localStorage.setItem(\"kantine_firstName\",t.first_name),t.last_name&&localStorage.setItem(\"kantine_lastName\",t.last_name)}}catch(e){console.error(\"Failed to fetch user info:\",e)}(0,s.i_)(),g.classList.add(\"hidden\"),(0,s.Gb)(),u.reset(),(0,s.g8)(),(0,s.m9)()}else o.textContent=c.non_field_errors?.[0]||c.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{l.disabled=!1,l.textContent=c}}),m.addEventListener(\"click\",()=>{localStorage.removeItem(\"kantine_authToken\"),localStorage.removeItem(\"kantine_currentUser\"),localStorage.removeItem(\"kantine_firstName\"),localStorage.removeItem(\"kantine_lastName\"),(0,a.O5)(null),(0,a.lt)(null),(0,a.di)(new Map),(0,s.Et)(),(0,s.i_)(),(0,o.OR)()})}(),(0,s.i_)(),(0,s.H)();(0,s.KG)()?(document.getElementById(\"loading\").classList.add(\"hidden\"),(0,s.VL)()?console.log(\"Cache fresh & complete \u2013 skipping API refresh\"):(console.log(\"Cache stale or incomplete \u2013 refreshing from API\"),(0,s.m9)())):(0,s.m9)(),a.gX&&(0,s.g8)(),(0,o.Ux)(),setInterval(o.Ux,36e5),console.log(\"Kantine Wrapper loaded \u2705\")}})();\n"; document.head.appendChild(sc); })();
