diff --git a/assets/css/main.css b/assets/css/main.css
new file mode 100644
index 0000000..6343b61
--- /dev/null
+++ b/assets/css/main.css
@@ -0,0 +1,61 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+@layer base {
+ :root {
+ --primary-color: theme('colors.primary.DEFAULT');
+ --accent-color: theme('colors.accent.DEFAULT');
+ --text-color: theme('colors.gray.800');
+ --background-color: theme('colors.white');
+ --card-background: theme('colors.white');
+ --header-background: theme('colors.white');
+ }
+
+ .dark {
+ --primary-color: theme('colors.primary.400');
+ --accent-color: theme('colors.accent.400');
+ --text-color: theme('colors.gray.200');
+ --background-color: theme('colors.gray.900');
+ --card-background: theme('colors.gray.800');
+ --header-background: theme('colors.gray.900');
+ }
+}
+
+@keyframes slideInLeft {
+ from {
+ transform: translateX(-100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+@keyframes slideInRight {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+.slide-in-left {
+ animation: slideInLeft 1s ease-out forwards;
+}
+
+.slide-in-right {
+ animation: slideInRight 1s ease-out forwards;
+}
+
+.scrollbar-hide::-webkit-scrollbar {
+ display: none;
+}
+.scrollbar-hide {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+}
\ No newline at end of file
diff --git a/assets/js/menu.js b/assets/js/menu.js
new file mode 100644
index 0000000..1d902a4
--- /dev/null
+++ b/assets/js/menu.js
@@ -0,0 +1,44 @@
+document.addEventListener('DOMContentLoaded', function() {
+ // Menu category switching
+ const tabButtons = document.querySelectorAll('[data-tab]');
+ const menuContents = document.querySelectorAll('.menu-content');
+
+ tabButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ const targetId = `${button.dataset.tab}-content`;
+
+ // Update button styles
+ tabButtons.forEach(btn => {
+ const isActive = btn === button;
+ btn.classList.toggle('bg-pizza-red', isActive);
+ btn.classList.toggle('text-white', isActive);
+ btn.classList.toggle('bg-gray-200', !isActive);
+ btn.classList.toggle('dark:bg-pizza-darker', !isActive);
+ btn.classList.toggle('text-gray-700', !isActive);
+ btn.classList.toggle('dark:text-white', !isActive);
+ });
+
+ // Show/hide content
+ menuContents.forEach(content => {
+ content.classList.toggle('hidden', content.id !== targetId);
+ });
+ });
+ });
+
+ // Pizza price group toggles
+ const priceGroupHeaders = document.querySelectorAll('.price-group-header');
+ priceGroupHeaders.forEach(header => {
+ header.addEventListener('click', () => {
+ const content = header.nextElementSibling;
+ const arrow = header.querySelector('svg');
+
+ // Toggle content visibility
+ content.classList.toggle('hidden');
+
+ // Rotate arrow
+ arrow.style.transform = content.classList.contains('hidden')
+ ? 'rotate(0deg)'
+ : 'rotate(180deg)';
+ });
+ });
+});
\ No newline at end of file
diff --git a/assets/js/opening-status.js b/assets/js/opening-status.js
new file mode 100644
index 0000000..6856188
--- /dev/null
+++ b/assets/js/opening-status.js
@@ -0,0 +1,95 @@
+function updateTimeAndStatus() {
+ const now = new Date();
+ const timeString = now.toLocaleTimeString('de-DE', {
+ hour: '2-digit',
+ minute: '2-digit',
+ hour12: false
+ });
+
+ // Update time display
+ const timeDisplay = document.getElementById('current-time');
+ if (timeDisplay) {
+ timeDisplay.textContent = timeString;
+ }
+
+ fetch('/api/check-open-status')
+ .then(response => response.json())
+ .then(status => {
+ const statusBar = document.getElementById('status-bar');
+ const statusText = document.getElementById('status-text');
+ const deliveryText = document.querySelector('.delivery-text');
+
+ if (statusBar && statusText) {
+ statusBar.className = status.isOpen
+ ? 'bg-status-green transition-colors duration-300'
+ : 'bg-status-red transition-colors duration-300';
+
+ const textOpen = statusText.dataset.textOpen;
+ const textClosed = statusText.dataset.textClosed;
+ statusText.textContent = status.isOpen ? textOpen : textClosed;
+ }
+
+ // Debug information
+ const debugInfo = document.getElementById('debug-info');
+ if (debugInfo && !status.isOpen) {
+ const nextOpen = document.getElementById('next-open');
+ const currentDay = document.getElementById('current-day');
+
+ if (currentDay) {
+ currentDay.textContent = now.toLocaleDateString('de-DE', { weekday: 'long' });
+ }
+
+ if (nextOpen) {
+ const hoursRows = document.querySelectorAll('.hours-row');
+ let nextOpenTime = null;
+ let foundToday = false;
+
+ // First check today's remaining times
+ hoursRows.forEach(row => {
+ if (row.dataset.day === status.currentDay) {
+ const openTime = row.dataset.open;
+ if (openTime > timeString) {
+ nextOpenTime = `Today at ${openTime}`;
+ foundToday = true;
+ }
+ }
+ });
+
+ // If no times found today, find next day's opening
+ if (!foundToday) {
+ hoursRows.forEach(row => {
+ const dayIndex = parseInt(row.dataset.dayIndex || 0);
+ const currentDayIndex = now.getDay();
+
+ if (dayIndex > currentDayIndex || (dayIndex === 0 && currentDayIndex !== 0)) {
+ const openTime = row.dataset.open;
+ const dayName = row.dataset.dayName;
+ if (!nextOpenTime) {
+ nextOpenTime = `${dayName} at ${openTime}`;
+ }
+ }
+ });
+ }
+
+ nextOpen.textContent = nextOpenTime || 'Check opening hours';
+ }
+ }
+
+ // Update other elements
+ if (deliveryText) {
+ deliveryText.className = status.isOpen
+ ? 'delivery-text text-status-green'
+ : 'delivery-text text-status-red';
+ }
+
+ document.querySelectorAll('.hours-row').forEach(row => {
+ const isCurrentDay = row.dataset.day === status.currentDay;
+ row.classList.toggle('border-2', isCurrentDay && status.isOpen);
+ row.classList.toggle('border-status-green', isCurrentDay && status.isOpen);
+ });
+ });
+}
+
+// Update immediately and then every minute
+updateTimeAndStatus();
+setInterval(updateTimeAndStatus, 60000);
\ No newline at end of file
diff --git a/layouts/404.html b/layouts/404.html
new file mode 100644
index 0000000..29c103e
--- /dev/null
+++ b/layouts/404.html
@@ -0,0 +1,60 @@
+{{ define "main" }}
+
+
+
+ 4
+
+
+
+
+
+
+
+
+
+
+
+
+ 4
+
+
+
+
+ {{ i18n "404_oops" | default "Oops! Looks like this slice is missing!" }}
+
+
+
+ {{ i18n "404_text" | default "The page you're looking for has been eaten or never existed." }}
+
+
+
+
+
+
+
+
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html
new file mode 100644
index 0000000..4e213eb
--- /dev/null
+++ b/layouts/_default/baseof.html
@@ -0,0 +1,26 @@
+
+
+
+
+
+ {{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ .Title }} - {{ .Site.Title }}{{ end }}
+
+
+
+ {{ partial "header.html" . }}
+
+ {{ block "main" . }}{{ end }}
+
+ {{ partial "footer.html" . }}
+
+
+
+
+
+ {{ with resources.Get "js/opening-status.js" }}
+ {{ with . | resources.Minify }}
+
+ {{ end }}
+ {{ end }}
+
+
diff --git a/layouts/_default/check-open-status.json b/layouts/_default/check-open-status.json
new file mode 100644
index 0000000..7f56fc6
--- /dev/null
+++ b/layouts/_default/check-open-status.json
@@ -0,0 +1,5 @@
+{
+ "isOpen": {{ $status := partial "check-open-status.html" . }}{{ $status.isOpen }},
+ "currentDay": "{{ now.Format "Monday" }}",
+ "currentTime": "{{ now.Format "15:04" }}"
+}
\ No newline at end of file
diff --git a/layouts/_default/list.html b/layouts/_default/list.html
new file mode 100644
index 0000000..58b1765
--- /dev/null
+++ b/layouts/_default/list.html
@@ -0,0 +1,12 @@
+{{ define "main" }}
+{{ .Title }}
+
+ {{ range .Pages }}
+
+
+ {{ .Date.Format "January 2, 2006" }}
+ {{ .Summary }}
+
+ {{ end }}
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/_default/single.html b/layouts/_default/single.html
new file mode 100644
index 0000000..da6bab1
--- /dev/null
+++ b/layouts/_default/single.html
@@ -0,0 +1,9 @@
+{{ define "main" }}
+
+ {{ .Title }}
+ {{ .Date.Format "January 2, 2006" }}
+
+ {{ .Content }}
+
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/_default/single.json b/layouts/_default/single.json
new file mode 100644
index 0000000..2807823
--- /dev/null
+++ b/layouts/_default/single.json
@@ -0,0 +1,5 @@
+{
+ "layout": "{{ .Layout }}",
+ "title": "{{ .Title }}",
+ "type": "{{ .Type }}"
+}
\ No newline at end of file
diff --git a/layouts/about/about.html b/layouts/about/about.html
new file mode 100644
index 0000000..83fdd12
--- /dev/null
+++ b/layouts/about/about.html
@@ -0,0 +1,105 @@
+{{ define "main" }}
+
+
+
+
+
+
+
{{ .Site.Data.about.hero.title }}
+
{{ .Site.Data.about.hero.description }}
+
+
+
+
+
+
+
+
+
+
+
{{ .Site.Data.about.story.title }}
+
+
+ {{ .Site.Data.about.story.content }}
+
+
+
+ {{ range .Site.Data.about.story.features }}
+
+
+
+
+ {{ . }}
+
+ {{ end }}
+
+
+
+
+
+
+
+
+
+
+
{{ .Site.Data.about.team.title }}
+
+ {{ .Site.Data.about.team.description }}
+
+
+
+ {{ range .Site.Data.about.team.members }}
+
+
+
+
+
+
{{ .name }}
+
{{ .role }}
+
+ {{ .description }}
+
+
+
+ {{ end }}
+
+
+
+
+
+
+
+
{{ .Site.Data.about.contact.title }}
+
+
+
+
+
+
+ {{ .Site.Data.about.contact.address }}
+
+
+
+
+
+ {{ .Site.Params.contact.phone }}
+
+
+
+
+
+
+
+
+
+
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/en/about/about.html b/layouts/en/about/about.html
new file mode 100644
index 0000000..6c188b7
--- /dev/null
+++ b/layouts/en/about/about.html
@@ -0,0 +1,105 @@
+{{ define "main" }}
+
+
+
+
+
+
+
{{ .Site.Data.en.about.hero.title }}
+
{{ .Site.Data.en.about.hero.description }}
+
+
+
+
+
+
+
+
+
+
+
{{ .Site.Data.en.about.story.title }}
+
+
+ {{ .Site.Data.en.about.story.content }}
+
+
+
+ {{ range .Site.Data.en.about.story.features }}
+
+
+
+
+ {{ . }}
+
+ {{ end }}
+
+
+
+
+
+
+
+
+
+
+
{{ .Site.Data.en.about.team.title }}
+
+ {{ .Site.Data.en.about.team.description }}
+
+
+
+ {{ range .Site.Data.en.about.team.members }}
+
+
+
+
+
+
{{ .name }}
+
{{ .role }}
+
+ {{ .description }}
+
+
+
+ {{ end }}
+
+
+
+
+
+
+
+
{{ .Site.Data.en.about.contact.title }}
+
+
+
+
+
+
+ {{ .Site.Data.en.about.contact.address }}
+
+
+
+
+
+ {{ .Site.Params.contact.phone }}
+
+
+
+
+
+
+
+
+
+
+
+{{ end }}
diff --git a/layouts/en/index.html b/layouts/en/index.html
new file mode 100644
index 0000000..5a37790
--- /dev/null
+++ b/layouts/en/index.html
@@ -0,0 +1,25 @@
+{{ define "main" }}
+
+
+
+
+
+
+ {{ partial "opening-hours.html" . }}
+
+
+
+
+
+
+
+
+
+ {{ partial "menu-card.html" . }}
+
+
+
+
+{{ $menu := resources.Get "js/menu.js" | resources.Minify | resources.Fingerprint }}
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/index.html b/layouts/index.html
new file mode 100644
index 0000000..777102e
--- /dev/null
+++ b/layouts/index.html
@@ -0,0 +1,26 @@
+{{ define "main" }}
+
+
+
+
+
+
+ {{ partial "opening-hours.html" . }}
+
+
+
+
+
+
+
+
+
+ {{ partial "menu-card.html" . }}
+
+
+
+
+
+{{ $menu := resources.Get "js/menu.js" | resources.Minify | resources.Fingerprint }}
+
+{{ end }}
\ No newline at end of file
diff --git a/layouts/partials/check-open-status.html b/layouts/partials/check-open-status.html
new file mode 100644
index 0000000..eba2922
--- /dev/null
+++ b/layouts/partials/check-open-status.html
@@ -0,0 +1,32 @@
+{{ $currentTime := now.Format "15:04" }}
+{{ $currentDay := now.Format "Monday" }}
+{{ $isOpen := false }}
+{{ $holidayInfo := dict }}
+{{ $isHoliday := false }}
+
+
+{{ range .Site.Data.hours.holidays }}
+ {{ $holidayDate := time .date }}
+ {{ if eq (now.Format "2006-01-02") ($holidayDate.Format "2006-01-02") }}
+ {{ $isHoliday = true }}
+ {{ $holidayInfo = . }}
+ {{ if not .closed }}
+ {{ if and (ge $currentTime .open) (le $currentTime .close) }}
+ {{ $isOpen = true }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+{{ end }}
+
+
+{{ if not $isHoliday }}
+ {{ range .Site.Data.hours.regular_hours }}
+ {{ if in .days $currentDay }}
+ {{ if and (ge $currentTime .open) (le $currentTime .close) }}
+ {{ $isOpen = true }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+{{ end }}
+
+{{ return dict "isOpen" $isOpen "isHoliday" $isHoliday "holidayInfo" $holidayInfo "currentDay" $currentDay "currentTime" $currentTime }}
\ No newline at end of file
diff --git a/layouts/partials/components/language-switcher.html b/layouts/partials/components/language-switcher.html
new file mode 100644
index 0000000..942a98e
--- /dev/null
+++ b/layouts/partials/components/language-switcher.html
@@ -0,0 +1,13 @@
+
+ {{ if eq .Site.Language.Lang "en" }}
+
+
+ DE
+
+ {{ else }}
+
+
+ EN
+
+ {{ end }}
+
\ No newline at end of file
diff --git a/layouts/partials/components/theme-switcher.html b/layouts/partials/components/theme-switcher.html
new file mode 100644
index 0000000..309cbd2
--- /dev/null
+++ b/layouts/partials/components/theme-switcher.html
@@ -0,0 +1,70 @@
+
+{{ $class := .Class }}
+{{ if site.Params.theme_switcher }}
+
+
+
+ theme switcher
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{{ end }}
diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html
new file mode 100644
index 0000000..5cb67e7
--- /dev/null
+++ b/layouts/partials/footer.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+ © {{ now.Format "2006" }} {{ .Site.Title }}
+
+
+
+
\ No newline at end of file
diff --git a/layouts/partials/head.html b/layouts/partials/head.html
new file mode 100644
index 0000000..a86f3ce
--- /dev/null
+++ b/layouts/partials/head.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/layouts/partials/header.html b/layouts/partials/header.html
new file mode 100644
index 0000000..44a3687
--- /dev/null
+++ b/layouts/partials/header.html
@@ -0,0 +1,161 @@
+
+
+ {{ $status := partial "check-open-status.html" . }}
+
+
+
+
+ {{ if $status.isOpen }}
+ {{ i18n "open" }}
+ {{ else }}
+ {{ i18n "closed" }}
+ {{ end }}
+
+
+ ({{ now.Format "15:04" }} {{ i18n "time_suffix" }})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/layouts/partials/logo.html b/layouts/partials/logo.html
new file mode 100644
index 0000000..e4d1848
--- /dev/null
+++ b/layouts/partials/logo.html
@@ -0,0 +1,5 @@
+{{ if .Site.Params.logo }}
+
+{{ else }}
+ {{ .Site.Title }}
+{{ end }}
\ No newline at end of file
diff --git a/layouts/partials/menu-card.html b/layouts/partials/menu-card.html
new file mode 100644
index 0000000..8551152
--- /dev/null
+++ b/layouts/partials/menu-card.html
@@ -0,0 +1,180 @@
+
+
\ No newline at end of file
diff --git a/layouts/partials/opening-hours.html b/layouts/partials/opening-hours.html
new file mode 100644
index 0000000..c66ebea
--- /dev/null
+++ b/layouts/partials/opening-hours.html
@@ -0,0 +1,83 @@
+{{ $now := now }}
+{{ $currentDay := $now.Format "Monday" }}
+{{ $currentTime := $now.Format "15:04" }}
+
+
+
{{ i18n "opening_hours" }}
+
+
+
+ {{ range .Site.Data.hours.regular_hours }}
+ {{ $isOpen := and (in .days $currentDay) (ge $currentTime .open) (le $currentTime .close) }}
+
+
+
+ {{ $numDays := len .days }}
+ {{ if eq $numDays 1 }}
+ {{ index .days 0 }}
+ {{ else if eq $numDays 2 }}
+ {{ i18n (index .days 0) }} & {{ i18n (index .days 1) }}
+ {{ else }}
+ {{ $lastIndex := sub $numDays 1 }}
+ {{ range $i, $day := .days }}
+ {{ if eq $i 0 }}
+ {{ i18n $day }}
+ {{ else if eq $i $lastIndex }}
+ - {{ i18n $day }}
+ {{ end }}
+ {{ end }}
+ {{ end }}
+
+
+
+ {{ .open }} - {{ .close }}
+
+
+ {{ i18n "delivery_until" }} {{ .close }}
+
+
+
+
+
+ {{ if $isOpen }}
+
+ {{ end }}
+
+ {{ end }}
+
+
+
+ {{ range .Site.Data.hours.holidays }}
+ {{ $holidayDate := time .date }}
+ {{ if eq ($now.Format "2006-01-02") ($holidayDate.Format "2006-01-02") }}
+
+
+ {{ .name }}:
+ {{ if .closed }}
+
{{ i18n "closed" }}
+ {{ else }}
+
{{ .open }} - {{ .close }} Uhr
+
+ {{ i18n "delivery_until" }} {{ .delivery_until }} Uhr
+
+ {{ end }}
+
+
+ {{ end }}
+ {{ end }}
+
+
\ No newline at end of file
diff --git a/layouts/partials/price-table.html b/layouts/partials/price-table.html
new file mode 100644
index 0000000..15c7932
--- /dev/null
+++ b/layouts/partials/price-table.html
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/static/css/style.css b/static/css/style.css
new file mode 100644
index 0000000..fb4edbe
--- /dev/null
+++ b/static/css/style.css
@@ -0,0 +1,1760 @@
+*, ::before, ::after {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+ --tw-contain-size: ;
+ --tw-contain-layout: ;
+ --tw-contain-paint: ;
+ --tw-contain-style: ;
+}
+
+::backdrop {
+ --tw-border-spacing-x: 0;
+ --tw-border-spacing-y: 0;
+ --tw-translate-x: 0;
+ --tw-translate-y: 0;
+ --tw-rotate: 0;
+ --tw-skew-x: 0;
+ --tw-skew-y: 0;
+ --tw-scale-x: 1;
+ --tw-scale-y: 1;
+ --tw-pan-x: ;
+ --tw-pan-y: ;
+ --tw-pinch-zoom: ;
+ --tw-scroll-snap-strictness: proximity;
+ --tw-gradient-from-position: ;
+ --tw-gradient-via-position: ;
+ --tw-gradient-to-position: ;
+ --tw-ordinal: ;
+ --tw-slashed-zero: ;
+ --tw-numeric-figure: ;
+ --tw-numeric-spacing: ;
+ --tw-numeric-fraction: ;
+ --tw-ring-inset: ;
+ --tw-ring-offset-width: 0px;
+ --tw-ring-offset-color: #fff;
+ --tw-ring-color: rgb(59 130 246 / 0.5);
+ --tw-ring-offset-shadow: 0 0 #0000;
+ --tw-ring-shadow: 0 0 #0000;
+ --tw-shadow: 0 0 #0000;
+ --tw-shadow-colored: 0 0 #0000;
+ --tw-blur: ;
+ --tw-brightness: ;
+ --tw-contrast: ;
+ --tw-grayscale: ;
+ --tw-hue-rotate: ;
+ --tw-invert: ;
+ --tw-saturate: ;
+ --tw-sepia: ;
+ --tw-drop-shadow: ;
+ --tw-backdrop-blur: ;
+ --tw-backdrop-brightness: ;
+ --tw-backdrop-contrast: ;
+ --tw-backdrop-grayscale: ;
+ --tw-backdrop-hue-rotate: ;
+ --tw-backdrop-invert: ;
+ --tw-backdrop-opacity: ;
+ --tw-backdrop-saturate: ;
+ --tw-backdrop-sepia: ;
+ --tw-contain-size: ;
+ --tw-contain-layout: ;
+ --tw-contain-paint: ;
+ --tw-contain-style: ;
+}
+
+/*
+! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com
+*/
+
+/*
+1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
+2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
+*/
+
+*,
+::before,
+::after {
+ box-sizing: border-box;
+ /* 1 */
+ border-width: 0;
+ /* 2 */
+ border-style: solid;
+ /* 2 */
+ border-color: #e5e7eb;
+ /* 2 */
+}
+
+::before,
+::after {
+ --tw-content: '';
+}
+
+/*
+1. Use a consistent sensible line-height in all browsers.
+2. Prevent adjustments of font size after orientation changes in iOS.
+3. Use a more readable tab size.
+4. Use the user's configured `sans` font-family by default.
+5. Use the user's configured `sans` font-feature-settings by default.
+6. Use the user's configured `sans` font-variation-settings by default.
+7. Disable tap highlights on iOS
+*/
+
+html,
+:host {
+ line-height: 1.5;
+ /* 1 */
+ -webkit-text-size-adjust: 100%;
+ /* 2 */
+ -moz-tab-size: 4;
+ /* 3 */
+ -o-tab-size: 4;
+ tab-size: 4;
+ /* 3 */
+ font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
+ /* 4 */
+ font-feature-settings: normal;
+ /* 5 */
+ font-variation-settings: normal;
+ /* 6 */
+ -webkit-tap-highlight-color: transparent;
+ /* 7 */
+}
+
+/*
+1. Remove the margin in all browsers.
+2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
+*/
+
+body {
+ margin: 0;
+ /* 1 */
+ line-height: inherit;
+ /* 2 */
+}
+
+/*
+1. Add the correct height in Firefox.
+2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
+3. Ensure horizontal rules are visible by default.
+*/
+
+hr {
+ height: 0;
+ /* 1 */
+ color: inherit;
+ /* 2 */
+ border-top-width: 1px;
+ /* 3 */
+}
+
+/*
+Add the correct text decoration in Chrome, Edge, and Safari.
+*/
+
+abbr:where([title]) {
+ -webkit-text-decoration: underline dotted;
+ text-decoration: underline dotted;
+}
+
+/*
+Remove the default font size and weight for headings.
+*/
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+ font-size: inherit;
+ font-weight: inherit;
+}
+
+/*
+Reset links to optimize for opt-in styling instead of opt-out.
+*/
+
+a {
+ color: inherit;
+ text-decoration: inherit;
+}
+
+/*
+Add the correct font weight in Edge and Safari.
+*/
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/*
+1. Use the user's configured `mono` font-family by default.
+2. Use the user's configured `mono` font-feature-settings by default.
+3. Use the user's configured `mono` font-variation-settings by default.
+4. Correct the odd `em` font sizing in all browsers.
+*/
+
+code,
+kbd,
+samp,
+pre {
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ /* 1 */
+ font-feature-settings: normal;
+ /* 2 */
+ font-variation-settings: normal;
+ /* 3 */
+ font-size: 1em;
+ /* 4 */
+}
+
+/*
+Add the correct font size in all browsers.
+*/
+
+small {
+ font-size: 80%;
+}
+
+/*
+Prevent `sub` and `sup` elements from affecting the line height in all browsers.
+*/
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/*
+1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
+2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
+3. Remove gaps between table borders by default.
+*/
+
+table {
+ text-indent: 0;
+ /* 1 */
+ border-color: inherit;
+ /* 2 */
+ border-collapse: collapse;
+ /* 3 */
+}
+
+/*
+1. Change the font styles in all browsers.
+2. Remove the margin in Firefox and Safari.
+3. Remove default padding in all browsers.
+*/
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit;
+ /* 1 */
+ font-feature-settings: inherit;
+ /* 1 */
+ font-variation-settings: inherit;
+ /* 1 */
+ font-size: 100%;
+ /* 1 */
+ font-weight: inherit;
+ /* 1 */
+ line-height: inherit;
+ /* 1 */
+ letter-spacing: inherit;
+ /* 1 */
+ color: inherit;
+ /* 1 */
+ margin: 0;
+ /* 2 */
+ padding: 0;
+ /* 3 */
+}
+
+/*
+Remove the inheritance of text transform in Edge and Firefox.
+*/
+
+button,
+select {
+ text-transform: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Remove default button styles.
+*/
+
+button,
+input:where([type='button']),
+input:where([type='reset']),
+input:where([type='submit']) {
+ -webkit-appearance: button;
+ /* 1 */
+ background-color: transparent;
+ /* 2 */
+ background-image: none;
+ /* 2 */
+}
+
+/*
+Use the modern Firefox focus style for all focusable elements.
+*/
+
+:-moz-focusring {
+ outline: auto;
+}
+
+/*
+Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
+*/
+
+:-moz-ui-invalid {
+ box-shadow: none;
+}
+
+/*
+Add the correct vertical alignment in Chrome and Firefox.
+*/
+
+progress {
+ vertical-align: baseline;
+}
+
+/*
+Correct the cursor style of increment and decrement buttons in Safari.
+*/
+
+::-webkit-inner-spin-button,
+::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/*
+1. Correct the odd appearance in Chrome and Safari.
+2. Correct the outline style in Safari.
+*/
+
+[type='search'] {
+ -webkit-appearance: textfield;
+ /* 1 */
+ outline-offset: -2px;
+ /* 2 */
+}
+
+/*
+Remove the inner padding in Chrome and Safari on macOS.
+*/
+
+::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/*
+1. Correct the inability to style clickable types in iOS and Safari.
+2. Change font properties to `inherit` in Safari.
+*/
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button;
+ /* 1 */
+ font: inherit;
+ /* 2 */
+}
+
+/*
+Add the correct display in Chrome and Safari.
+*/
+
+summary {
+ display: list-item;
+}
+
+/*
+Removes the default spacing and border for appropriate elements.
+*/
+
+blockquote,
+dl,
+dd,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+hr,
+figure,
+p,
+pre {
+ margin: 0;
+}
+
+fieldset {
+ margin: 0;
+ padding: 0;
+}
+
+legend {
+ padding: 0;
+}
+
+ol,
+ul,
+menu {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+
+/*
+Reset default styling for dialogs.
+*/
+
+dialog {
+ padding: 0;
+}
+
+/*
+Prevent resizing textareas horizontally by default.
+*/
+
+textarea {
+ resize: vertical;
+}
+
+/*
+1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
+2. Set the default placeholder color to the user's configured gray 400 color.
+*/
+
+input::-moz-placeholder, textarea::-moz-placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+input::placeholder,
+textarea::placeholder {
+ opacity: 1;
+ /* 1 */
+ color: #9ca3af;
+ /* 2 */
+}
+
+/*
+Set the default cursor for buttons.
+*/
+
+button,
+[role="button"] {
+ cursor: pointer;
+}
+
+/*
+Make sure disabled buttons don't get the pointer cursor.
+*/
+
+:disabled {
+ cursor: default;
+}
+
+/*
+1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
+2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
+ This can trigger a poorly considered lint error in some tools but is included by design.
+*/
+
+img,
+svg,
+video,
+canvas,
+audio,
+iframe,
+embed,
+object {
+ display: block;
+ /* 1 */
+ vertical-align: middle;
+ /* 2 */
+}
+
+/*
+Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
+*/
+
+img,
+video {
+ max-width: 100%;
+ height: auto;
+}
+
+/* Make elements with the HTML hidden attribute stay hidden by default */
+
+[hidden]:where(:not([hidden="until-found"])) {
+ display: none;
+}
+
+.container {
+ width: 100%;
+}
+
+@media (min-width: 640px) {
+ .container {
+ max-width: 640px;
+ }
+}
+
+@media (min-width: 768px) {
+ .container {
+ max-width: 768px;
+ }
+}
+
+@media (min-width: 1024px) {
+ .container {
+ max-width: 1024px;
+ }
+}
+
+@media (min-width: 1280px) {
+ .container {
+ max-width: 1280px;
+ }
+}
+
+@media (min-width: 1536px) {
+ .container {
+ max-width: 1536px;
+ }
+}
+
+.sr-only {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border-width: 0;
+}
+
+.visible {
+ visibility: visible;
+}
+
+.fixed {
+ position: fixed;
+}
+
+.absolute {
+ position: absolute;
+}
+
+.relative {
+ position: relative;
+}
+
+.inset-0 {
+ inset: 0px;
+}
+
+.bottom-4 {
+ bottom: 1rem;
+}
+
+.left-0 {
+ left: 0px;
+}
+
+.left-1\/2 {
+ left: 50%;
+}
+
+.right-0 {
+ right: 0px;
+}
+
+.right-4 {
+ right: 1rem;
+}
+
+.top-0 {
+ top: 0px;
+}
+
+.top-1\/2 {
+ top: 50%;
+}
+
+.z-10 {
+ z-index: 10;
+}
+
+.z-50 {
+ z-index: 50;
+}
+
+.mx-0 {
+ margin-left: 0px;
+ margin-right: 0px;
+}
+
+.mx-1 {
+ margin-left: 0.25rem;
+ margin-right: 0.25rem;
+}
+
+.mx-auto {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.mb-12 {
+ margin-bottom: 3rem;
+}
+
+.mb-16 {
+ margin-bottom: 4rem;
+}
+
+.mb-2 {
+ margin-bottom: 0.5rem;
+}
+
+.mb-4 {
+ margin-bottom: 1rem;
+}
+
+.mb-6 {
+ margin-bottom: 1.5rem;
+}
+
+.mb-8 {
+ margin-bottom: 2rem;
+}
+
+.ml-2 {
+ margin-left: 0.5rem;
+}
+
+.mr-2 {
+ margin-right: 0.5rem;
+}
+
+.mt-12 {
+ margin-top: 3rem;
+}
+
+.mt-2 {
+ margin-top: 0.5rem;
+}
+
+.mt-3 {
+ margin-top: 0.75rem;
+}
+
+.mt-4 {
+ margin-top: 1rem;
+}
+
+.mt-6 {
+ margin-top: 1.5rem;
+}
+
+.mt-8 {
+ margin-top: 2rem;
+}
+
+.mt-auto {
+ margin-top: auto;
+}
+
+.block {
+ display: block;
+}
+
+.inline-block {
+ display: inline-block;
+}
+
+.flex {
+ display: flex;
+}
+
+.inline-flex {
+ display: inline-flex;
+}
+
+.grid {
+ display: grid;
+}
+
+.hidden {
+ display: none;
+}
+
+.aspect-square {
+ aspect-ratio: 1 / 1;
+}
+
+.h-12 {
+ height: 3rem;
+}
+
+.h-16 {
+ height: 4rem;
+}
+
+.h-24 {
+ height: 6rem;
+}
+
+.h-3 {
+ height: 0.75rem;
+}
+
+.h-32 {
+ height: 8rem;
+}
+
+.h-5 {
+ height: 1.25rem;
+}
+
+.h-6 {
+ height: 1.5rem;
+}
+
+.h-64 {
+ height: 16rem;
+}
+
+.h-8 {
+ height: 2rem;
+}
+
+.h-80 {
+ height: 20rem;
+}
+
+.h-\[40vh\] {
+ height: 40vh;
+}
+
+.h-full {
+ height: 100%;
+}
+
+.min-h-screen {
+ min-height: 100vh;
+}
+
+.w-24 {
+ width: 6rem;
+}
+
+.w-3 {
+ width: 0.75rem;
+}
+
+.w-32 {
+ width: 8rem;
+}
+
+.w-5 {
+ width: 1.25rem;
+}
+
+.w-6 {
+ width: 1.5rem;
+}
+
+.w-auto {
+ width: auto;
+}
+
+.w-full {
+ width: 100%;
+}
+
+.max-w-2xl {
+ max-width: 42rem;
+}
+
+.max-w-4xl {
+ max-width: 56rem;
+}
+
+.flex-shrink-0 {
+ flex-shrink: 0;
+}
+
+.origin-center {
+ transform-origin: center;
+}
+
+.-translate-x-1\/2 {
+ --tw-translate-x: -50%;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.-translate-y-1\/2 {
+ --tw-translate-y: -50%;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.transform {
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+@keyframes bounce {
+ 0%, 100% {
+ transform: translateY(-25%);
+ animation-timing-function: cubic-bezier(0.8,0,1,1);
+ }
+
+ 50% {
+ transform: none;
+ animation-timing-function: cubic-bezier(0,0,0.2,1);
+ }
+}
+
+.animate-bounce-subtle {
+ animation: bounce 2s infinite;
+}
+
+@keyframes driveBy {
+ 0% {
+ transform: translateX(-200%);
+ }
+
+ 100% {
+ transform: translateX(200%);
+ }
+}
+
+.animate-drive-by {
+ animation: driveBy 10s linear infinite;
+}
+
+@keyframes pulse {
+ 50% {
+ opacity: .5;
+ }
+}
+
+.animate-pulse {
+ animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.animate-spin-slow {
+ animation: spin 8s linear infinite;
+}
+
+.cursor-pointer {
+ cursor: pointer;
+}
+
+.resize {
+ resize: both;
+}
+
+.list-inside {
+ list-style-position: inside;
+}
+
+.list-disc {
+ list-style-type: disc;
+}
+
+.grid-cols-1 {
+ grid-template-columns: repeat(1, minmax(0, 1fr));
+}
+
+.grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+}
+
+.flex-col {
+ flex-direction: column;
+}
+
+.flex-wrap {
+ flex-wrap: wrap;
+}
+
+.items-center {
+ align-items: center;
+}
+
+.justify-center {
+ justify-content: center;
+}
+
+.justify-between {
+ justify-content: space-between;
+}
+
+.justify-around {
+ justify-content: space-around;
+}
+
+.gap-2 {
+ gap: 0.5rem;
+}
+
+.gap-4 {
+ gap: 1rem;
+}
+
+.gap-6 {
+ gap: 1.5rem;
+}
+
+.gap-8 {
+ gap: 2rem;
+}
+
+.space-x-3 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-x-reverse: 0;
+ margin-right: calc(0.75rem * var(--tw-space-x-reverse));
+ margin-left: calc(0.75rem * calc(1 - var(--tw-space-x-reverse)));
+}
+
+.space-x-4 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-x-reverse: 0;
+ margin-right: calc(1rem * var(--tw-space-x-reverse));
+ margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse)));
+}
+
+.space-x-8 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-x-reverse: 0;
+ margin-right: calc(2rem * var(--tw-space-x-reverse));
+ margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
+}
+
+.space-y-1 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
+}
+
+.space-y-16 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(4rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(4rem * var(--tw-space-y-reverse));
+}
+
+.space-y-2 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));
+}
+
+.space-y-3 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(0.75rem * var(--tw-space-y-reverse));
+}
+
+.space-y-4 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(1rem * var(--tw-space-y-reverse));
+}
+
+.space-y-6 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
+}
+
+.space-y-8 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(2rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(2rem * var(--tw-space-y-reverse));
+}
+
+.overflow-hidden {
+ overflow: hidden;
+}
+
+.overflow-x-auto {
+ overflow-x: auto;
+}
+
+.scroll-smooth {
+ scroll-behavior: smooth;
+}
+
+.whitespace-nowrap {
+ white-space: nowrap;
+}
+
+.rounded-full {
+ border-radius: 9999px;
+}
+
+.rounded-lg {
+ border-radius: 0.5rem;
+}
+
+.rounded-xl {
+ border-radius: 0.75rem;
+}
+
+.border {
+ border-width: 1px;
+}
+
+.border-2 {
+ border-width: 2px;
+}
+
+.border-b {
+ border-bottom-width: 1px;
+}
+
+.border-t {
+ border-top-width: 1px;
+}
+
+.border-gray-100 {
+ --tw-border-opacity: 1;
+ border-color: rgb(243 244 246 / var(--tw-border-opacity, 1));
+}
+
+.border-gray-200 {
+ --tw-border-opacity: 1;
+ border-color: rgb(229 231 235 / var(--tw-border-opacity, 1));
+}
+
+.border-pizza-red\/20 {
+ border-color: rgb(255 56 80 / 0.2);
+}
+
+.border-status-green {
+ --tw-border-opacity: 1;
+ border-color: rgb(16 185 129 / var(--tw-border-opacity, 1));
+}
+
+.bg-black\/50 {
+ background-color: rgb(0 0 0 / 0.5);
+}
+
+.bg-gray-100 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
+}
+
+.bg-gray-200 {
+ --tw-bg-opacity: 1;
+ background-color: rgb(229 231 235 / var(--tw-bg-opacity, 1));
+}
+
+.bg-pizza-red {
+ --tw-bg-opacity: 1;
+ background-color: rgb(255 56 80 / var(--tw-bg-opacity, 1));
+}
+
+.bg-pizza-red\/10 {
+ background-color: rgb(255 56 80 / 0.1);
+}
+
+.bg-status-green {
+ --tw-bg-opacity: 1;
+ background-color: rgb(16 185 129 / var(--tw-bg-opacity, 1));
+}
+
+.bg-status-red {
+ --tw-bg-opacity: 1;
+ background-color: rgb(239 68 68 / var(--tw-bg-opacity, 1));
+}
+
+.bg-white {
+ --tw-bg-opacity: 1;
+ background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
+}
+
+.bg-white\/5 {
+ background-color: rgb(255 255 255 / 0.05);
+}
+
+.bg-white\/90 {
+ background-color: rgb(255 255 255 / 0.9);
+}
+
+.bg-white\/95 {
+ background-color: rgb(255 255 255 / 0.95);
+}
+
+.bg-\[url\(\'\/images\/pizza-hero\.jpg\'\)\] {
+ background-image: url('/images/pizza-hero.jpg');
+}
+
+.bg-cover {
+ background-size: cover;
+}
+
+.bg-center {
+ background-position: center;
+}
+
+.object-cover {
+ -o-object-fit: cover;
+ object-fit: cover;
+}
+
+.p-2 {
+ padding: 0.5rem;
+}
+
+.p-4 {
+ padding: 1rem;
+}
+
+.p-6 {
+ padding: 1.5rem;
+}
+
+.p-8 {
+ padding: 2rem;
+}
+
+.px-2 {
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+}
+
+.px-3 {
+ padding-left: 0.75rem;
+ padding-right: 0.75rem;
+}
+
+.px-4 {
+ padding-left: 1rem;
+ padding-right: 1rem;
+}
+
+.px-6 {
+ padding-left: 1.5rem;
+ padding-right: 1.5rem;
+}
+
+.px-8 {
+ padding-left: 2rem;
+ padding-right: 2rem;
+}
+
+.py-1\.5 {
+ padding-top: 0.375rem;
+ padding-bottom: 0.375rem;
+}
+
+.py-12 {
+ padding-top: 3rem;
+ padding-bottom: 3rem;
+}
+
+.py-2 {
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
+}
+
+.py-2\.5 {
+ padding-top: 0.625rem;
+ padding-bottom: 0.625rem;
+}
+
+.py-3 {
+ padding-top: 0.75rem;
+ padding-bottom: 0.75rem;
+}
+
+.py-8 {
+ padding-top: 2rem;
+ padding-bottom: 2rem;
+}
+
+.pb-2 {
+ padding-bottom: 0.5rem;
+}
+
+.pb-3 {
+ padding-bottom: 0.75rem;
+}
+
+.pt-2 {
+ padding-top: 0.5rem;
+}
+
+.pt-24 {
+ padding-top: 6rem;
+}
+
+.pt-3 {
+ padding-top: 0.75rem;
+}
+
+.pt-4 {
+ padding-top: 1rem;
+}
+
+.pt-6 {
+ padding-top: 1.5rem;
+}
+
+.pt-8 {
+ padding-top: 2rem;
+}
+
+.text-center {
+ text-align: center;
+}
+
+.text-right {
+ text-align: right;
+}
+
+.text-2xl {
+ font-size: 1.5rem;
+ line-height: 2rem;
+}
+
+.text-3xl {
+ font-size: 1.875rem;
+ line-height: 2.25rem;
+}
+
+.text-5xl {
+ font-size: 3rem;
+ line-height: 1;
+}
+
+.text-9xl {
+ font-size: 8rem;
+ line-height: 1;
+}
+
+.text-base {
+ font-size: 1rem;
+ line-height: 1.5rem;
+}
+
+.text-lg {
+ font-size: 1.125rem;
+ line-height: 1.75rem;
+}
+
+.text-sm {
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+}
+
+.text-xl {
+ font-size: 1.25rem;
+ line-height: 1.75rem;
+}
+
+.text-xs {
+ font-size: 0.75rem;
+ line-height: 1rem;
+}
+
+.font-bold {
+ font-weight: 700;
+}
+
+.font-medium {
+ font-weight: 500;
+}
+
+.font-semibold {
+ font-weight: 600;
+}
+
+.tracking-widest {
+ letter-spacing: 0.1em;
+}
+
+.text-emerald-400 {
+ --tw-text-opacity: 1;
+ color: rgb(52 211 153 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-400 {
+ --tw-text-opacity: 1;
+ color: rgb(156 163 175 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-500 {
+ --tw-text-opacity: 1;
+ color: rgb(107 114 128 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-600 {
+ --tw-text-opacity: 1;
+ color: rgb(75 85 99 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-700 {
+ --tw-text-opacity: 1;
+ color: rgb(55 65 81 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-800 {
+ --tw-text-opacity: 1;
+ color: rgb(31 41 55 / var(--tw-text-opacity, 1));
+}
+
+.text-gray-900 {
+ --tw-text-opacity: 1;
+ color: rgb(17 24 39 / var(--tw-text-opacity, 1));
+}
+
+.text-pizza-red {
+ --tw-text-opacity: 1;
+ color: rgb(255 56 80 / var(--tw-text-opacity, 1));
+}
+
+.text-status-green {
+ --tw-text-opacity: 1;
+ color: rgb(16 185 129 / var(--tw-text-opacity, 1));
+}
+
+.text-status-red {
+ --tw-text-opacity: 1;
+ color: rgb(239 68 68 / var(--tw-text-opacity, 1));
+}
+
+.text-white {
+ --tw-text-opacity: 1;
+ color: rgb(255 255 255 / var(--tw-text-opacity, 1));
+}
+
+.opacity-0 {
+ opacity: 0;
+}
+
+.opacity-100 {
+ opacity: 1;
+}
+
+.shadow-lg {
+ --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
+ --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+}
+
+.shadow-md {
+ --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
+ --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
+ box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
+}
+
+.backdrop-blur-sm {
+ --tw-backdrop-blur: blur(4px);
+ -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+ backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
+}
+
+.transition-all {
+ transition-property: all;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-duration: 150ms;
+}
+
+.transition-colors {
+ transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-duration: 150ms;
+}
+
+.transition-transform {
+ transition-property: transform;
+ transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+ transition-duration: 150ms;
+}
+
+.duration-200 {
+ transition-duration: 200ms;
+}
+
+.duration-300 {
+ transition-duration: 300ms;
+}
+
+.duration-500 {
+ transition-duration: 500ms;
+}
+
+.duration-700 {
+ transition-duration: 700ms;
+}
+
+@keyframes slideInLeft {
+ from {
+ transform: translateX(-100%);
+ opacity: 0;
+ }
+
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+@keyframes slideInRight {
+ from {
+ transform: translateX(100%);
+ opacity: 0;
+ }
+
+ to {
+ transform: translateX(0);
+ opacity: 1;
+ }
+}
+
+.slide-in-left {
+ animation: slideInLeft 1s ease-out forwards;
+}
+
+.slide-in-right {
+ animation: slideInRight 1s ease-out forwards;
+}
+
+.scrollbar-hide::-webkit-scrollbar {
+ display: none;
+}
+
+.scrollbar-hide {
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+}
+
+.last\:border-0:last-child {
+ border-width: 0px;
+}
+
+.hover\:scale-105:hover {
+ --tw-scale-x: 1.05;
+ --tw-scale-y: 1.05;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.hover\:bg-gray-100:hover {
+ --tw-bg-opacity: 1;
+ background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
+}
+
+.hover\:bg-gray-300:hover {
+ --tw-bg-opacity: 1;
+ background-color: rgb(209 213 219 / var(--tw-bg-opacity, 1));
+}
+
+.hover\:bg-red-600:hover {
+ --tw-bg-opacity: 1;
+ background-color: rgb(220 38 38 / var(--tw-bg-opacity, 1));
+}
+
+.hover\:text-pizza-red:hover {
+ --tw-text-opacity: 1;
+ color: rgb(255 56 80 / var(--tw-text-opacity, 1));
+}
+
+.hover\:text-status-green:hover {
+ --tw-text-opacity: 1;
+ color: rgb(16 185 129 / var(--tw-text-opacity, 1));
+}
+
+.hover\:text-status-green\/80:hover {
+ color: rgb(16 185 129 / 0.8);
+}
+
+.focus\:outline-none:focus {
+ outline: 2px solid transparent;
+ outline-offset: 2px;
+}
+
+.group:hover .group-hover\:-translate-y-1 {
+ --tw-translate-y: -0.25rem;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.group:hover .group-hover\:translate-y-1 {
+ --tw-translate-y: 0.25rem;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.group:hover .group-hover\:scale-110 {
+ --tw-scale-x: 1.1;
+ --tw-scale-y: 1.1;
+ transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
+}
+
+.group:hover .group-hover\:opacity-0 {
+ opacity: 0;
+}
+
+.group:hover .group-hover\:opacity-100 {
+ opacity: 1;
+}
+
+.dark\:block:is(.dark *) {
+ display: block;
+}
+
+.dark\:hidden:is(.dark *) {
+ display: none;
+}
+
+.dark\:border-gray-700:is(.dark *) {
+ --tw-border-opacity: 1;
+ border-color: rgb(55 65 81 / var(--tw-border-opacity, 1));
+}
+
+.dark\:border-pizza-dark:is(.dark *) {
+ --tw-border-opacity: 1;
+ border-color: rgb(26 29 36 / var(--tw-border-opacity, 1));
+}
+
+.dark\:bg-gray-900\/95:is(.dark *) {
+ background-color: rgb(17 24 39 / 0.95);
+}
+
+.dark\:bg-pizza-dark:is(.dark *) {
+ --tw-bg-opacity: 1;
+ background-color: rgb(26 29 36 / var(--tw-bg-opacity, 1));
+}
+
+.dark\:bg-pizza-dark\/90:is(.dark *) {
+ background-color: rgb(26 29 36 / 0.9);
+}
+
+.dark\:bg-pizza-darker:is(.dark *) {
+ --tw-bg-opacity: 1;
+ background-color: rgb(21 23 28 / var(--tw-bg-opacity, 1));
+}
+
+.dark\:bg-pizza-darker\/5:is(.dark *) {
+ background-color: rgb(21 23 28 / 0.05);
+}
+
+.dark\:bg-pizza-red\/20:is(.dark *) {
+ background-color: rgb(255 56 80 / 0.2);
+}
+
+.dark\:text-gray-100:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(243 244 246 / var(--tw-text-opacity, 1));
+}
+
+.dark\:text-gray-200:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(229 231 235 / var(--tw-text-opacity, 1));
+}
+
+.dark\:text-gray-300:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(209 213 219 / var(--tw-text-opacity, 1));
+}
+
+.dark\:text-gray-400:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(156 163 175 / var(--tw-text-opacity, 1));
+}
+
+.dark\:text-pizza-gray:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(156 163 175 / var(--tw-text-opacity, 1));
+}
+
+.dark\:text-white:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(255 255 255 / var(--tw-text-opacity, 1));
+}
+
+.dark\:opacity-0:is(.dark *) {
+ opacity: 0;
+}
+
+.dark\:opacity-100:is(.dark *) {
+ opacity: 1;
+}
+
+.dark\:hover\:bg-gray-800:hover:is(.dark *) {
+ --tw-bg-opacity: 1;
+ background-color: rgb(31 41 55 / var(--tw-bg-opacity, 1));
+}
+
+.dark\:hover\:bg-pizza-dark:hover:is(.dark *) {
+ --tw-bg-opacity: 1;
+ background-color: rgb(26 29 36 / var(--tw-bg-opacity, 1));
+}
+
+.dark\:hover\:text-status-green:hover:is(.dark *) {
+ --tw-text-opacity: 1;
+ color: rgb(16 185 129 / var(--tw-text-opacity, 1));
+}
+
+@media (min-width: 640px) {
+ .sm\:mx-0 {
+ margin-left: 0px;
+ margin-right: 0px;
+ }
+
+ .sm\:mb-8 {
+ margin-bottom: 2rem;
+ }
+
+ .sm\:mt-16 {
+ margin-top: 4rem;
+ }
+
+ .sm\:h-10 {
+ height: 2.5rem;
+ }
+
+ .sm\:h-16 {
+ height: 4rem;
+ }
+
+ .sm\:h-20 {
+ height: 5rem;
+ }
+
+ .sm\:space-y-6 > :not([hidden]) ~ :not([hidden]) {
+ --tw-space-y-reverse: 0;
+ margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
+ margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
+ }
+
+ .sm\:p-6 {
+ padding: 1.5rem;
+ }
+
+ .sm\:text-3xl {
+ font-size: 1.875rem;
+ line-height: 2.25rem;
+ }
+
+ .sm\:text-sm {
+ font-size: 0.875rem;
+ line-height: 1.25rem;
+ }
+}
+
+@media (min-width: 768px) {
+ .md\:flex {
+ display: flex;
+ }
+
+ .md\:hidden {
+ display: none;
+ }
+
+ .md\:grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .md\:grid-cols-3 {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .md\:grid-cols-4 {
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ }
+
+ .md\:text-2xl {
+ font-size: 1.5rem;
+ line-height: 2rem;
+ }
+
+ .md\:text-6xl {
+ font-size: 3.75rem;
+ line-height: 1;
+ }
+}
+
+@media (min-width: 1024px) {
+ .lg\:-ml-16 {
+ margin-left: -4rem;
+ }
+
+ .lg\:-mt-8 {
+ margin-top: -2rem;
+ }
+
+ .lg\:grid-cols-2 {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+}
\ No newline at end of file
diff --git a/static/icons/de.svg b/static/icons/de.svg
new file mode 100644
index 0000000..02c2384
--- /dev/null
+++ b/static/icons/de.svg
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/static/icons/gb.svg b/static/icons/gb.svg
new file mode 100644
index 0000000..c00b03a
--- /dev/null
+++ b/static/icons/gb.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/static/images/logo.webp b/static/images/logo.webp
new file mode 100644
index 0000000..a892557
Binary files /dev/null and b/static/images/logo.webp differ
diff --git a/static/images/pizza-aussen.webp b/static/images/pizza-aussen.webp
new file mode 100644
index 0000000..4c094a0
Binary files /dev/null and b/static/images/pizza-aussen.webp differ
diff --git a/static/images/pizza-innen.webp b/static/images/pizza-innen.webp
new file mode 100644
index 0000000..2844725
Binary files /dev/null and b/static/images/pizza-innen.webp differ
diff --git a/static/images/pizza.webp b/static/images/pizza.webp
new file mode 100644
index 0000000..de55e60
Binary files /dev/null and b/static/images/pizza.webp differ
diff --git a/static/images/team/Daisy.webp b/static/images/team/Daisy.webp
new file mode 100644
index 0000000..29cb24b
Binary files /dev/null and b/static/images/team/Daisy.webp differ
diff --git a/static/images/team/Luigi.webp b/static/images/team/Luigi.webp
new file mode 100644
index 0000000..5fb312b
Binary files /dev/null and b/static/images/team/Luigi.webp differ
diff --git a/static/images/team/Wario.webp b/static/images/team/Wario.webp
new file mode 100644
index 0000000..c065c2d
Binary files /dev/null and b/static/images/team/Wario.webp differ
diff --git a/static/js/header.js b/static/js/header.js
new file mode 100644
index 0000000..375a09f
--- /dev/null
+++ b/static/js/header.js
@@ -0,0 +1,38 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const header = document.querySelector('.header');
+ const navToggle = document.getElementById('nav-toggle');
+ const navMenu = document.getElementById('nav-menu');
+
+ // Scroll behavior
+ let lastScroll = 0;
+ window.addEventListener('scroll', () => {
+ const currentScroll = window.pageYOffset;
+
+ if (currentScroll <= 0) {
+ header.classList.remove('scrolled');
+ return;
+ }
+
+ if (currentScroll > lastScroll && !header.contains(document.activeElement)) {
+ header.style.transform = 'translateY(-100%)';
+ } else {
+ header.style.transform = 'translateY(0)';
+ header.classList.add('scrolled');
+ }
+ lastScroll = currentScroll;
+ });
+
+ // Close mobile menu when clicking outside
+ document.addEventListener('click', (e) => {
+ if (!header.contains(e.target)) {
+ navToggle.checked = false;
+ }
+ });
+
+ // Close mobile menu when window is resized to desktop
+ window.addEventListener('resize', () => {
+ if (window.innerWidth >= 1024) {
+ navToggle.checked = false;
+ }
+ });
+});
\ No newline at end of file
diff --git a/static/js/language.js b/static/js/language.js
new file mode 100644
index 0000000..cac183a
--- /dev/null
+++ b/static/js/language.js
@@ -0,0 +1,23 @@
+document.addEventListener('DOMContentLoaded', function() {
+ // Only run on the home page to avoid redirect loops
+ if (window.location.pathname === '/') {
+ const userLang = navigator.language || navigator.userLanguage;
+ const currentLang = document.documentElement.lang;
+
+ // Simple language mapping
+ const supportedLanguages = {
+ 'de': '/de/',
+ 'de-DE': '/de/',
+ 'de-AT': '/de/',
+ 'de-CH': '/de/',
+ 'en': '/en/',
+ 'en-US': '/en/',
+ 'en-GB': '/en/'
+ };
+
+ // Check if user's language is different from current and is supported
+ if (supportedLanguages[userLang] && currentLang !== userLang.substring(0,2)) {
+ window.location.href = supportedLanguages[userLang];
+ }
+ }
+});
\ No newline at end of file
diff --git a/static/js/main.js b/static/js/main.js
new file mode 100644
index 0000000..60de208
--- /dev/null
+++ b/static/js/main.js
@@ -0,0 +1,274 @@
+document.addEventListener('DOMContentLoaded', function() {
+ // Mobile menu toggle
+ const mobileMenuButton = document.querySelector('.mobile-menu-button');
+ const mobileMenu = document.querySelector('.mobile-menu');
+
+ mobileMenuButton.addEventListener('click', () => {
+ mobileMenu.classList.toggle('hidden');
+
+ // Update button state
+ mobileMenuButton.setAttribute('aria-expanded', !isExpanded);
+
+ // Toggle icons
+ menuIconOpen.classList.toggle('hidden');
+ menuIconClosed.classList.toggle('hidden');
+ });
+
+ // Close mobile menu when clicking outside
+ document.addEventListener('click', (e) => {
+ if (!mobileMenuButton.contains(e.target) && !mobileMenu.contains(e.target)) {
+ mobileMenu.classList.add('hidden');
+ mobileMenuButton.setAttribute('aria-expanded', 'false');
+ menuIconOpen.classList.remove('hidden');
+ menuIconClosed.classList.add('hidden');
+ }
+ });
+
+ // Theme toggle functionality
+ function updateTheme(isDark) {
+ const html = document.documentElement;
+ if (isDark) {
+ html.classList.add('dark');
+ } else {
+ html.classList.remove('dark');
+ }
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
+ }
+
+ // Desktop theme toggle
+ const darkModeToggle = document.getElementById('darkModeToggle');
+ darkModeToggle.addEventListener('click', () => {
+ const isDark = document.documentElement.classList.contains('dark');
+ updateTheme(!isDark);
+ });
+
+ // Mobile theme toggle
+ const darkModeToggleMobile = document.getElementById('darkModeToggleMobile');
+ darkModeToggleMobile.addEventListener('click', () => {
+ const isDark = document.documentElement.classList.contains('dark');
+ updateTheme(!isDark);
+ });
+
+ // Initialize theme
+ const savedTheme = localStorage.getItem('theme');
+ if (savedTheme) {
+ updateTheme(savedTheme === 'dark');
+ } else {
+ // Default to dark theme
+ updateTheme(true);
+ }
+
+ // Header scroll behavior
+ const header = document.querySelector('header');
+ let lastScroll = 0;
+
+ window.addEventListener('scroll', () => {
+ const currentScroll = window.pageYOffset;
+
+ if (currentScroll <= 0) {
+ header.classList.remove('shadow-lg', 'bg-white/95', 'dark:bg-gray-900/95');
+ header.style.transform = 'translateY(0)';
+ return;
+ }
+
+ if (currentScroll > lastScroll && !header.contains(document.activeElement)) {
+ // Scrolling down
+ header.style.transform = 'translateY(-100%)';
+ } else {
+ // Scrolling up
+ header.style.transform = 'translateY(0)';
+ header.classList.add('shadow-lg', 'bg-white/95', 'dark:bg-gray-900/95');
+ }
+
+ lastScroll = currentScroll;
+ });
+
+ // Menu tab functionality
+ const tabButtons = document.querySelectorAll('.tab-button');
+ const menuContents = document.querySelectorAll('.menu-content');
+
+ tabButtons.forEach(button => {
+ button.addEventListener('click', () => {
+ // Remove active state from all buttons
+ tabButtons.forEach(btn => {
+ btn.classList.remove('bg-pizza-red', 'text-white');
+ btn.classList.add('bg-gray-200', 'dark:bg-pizza-darker', 'text-gray-700', 'dark:text-white');
+ });
+
+ // Add active state to clicked button
+ button.classList.remove('bg-gray-200', 'dark:bg-pizza-darker', 'text-gray-700', 'dark:text-white');
+ button.classList.add('bg-pizza-red', 'text-white');
+
+ // Hide all content sections
+ menuContents.forEach(content => {
+ content.classList.add('hidden');
+ });
+
+ // Show selected content
+ const targetContent = document.getElementById(`${button.dataset.tab}-content`);
+ targetContent.classList.remove('hidden');
+ });
+ });
+
+ // Price group toggles
+ const priceGroups = document.querySelectorAll('.price-group-header');
+
+ priceGroups.forEach(group => {
+ group.addEventListener('click', () => {
+ const content = group.nextElementSibling;
+ const arrow = group.querySelector('svg');
+
+ // Toggle content visibility
+ content.classList.toggle('hidden');
+
+ // Rotate arrow
+ if (content.classList.contains('hidden')) {
+ arrow.style.transform = 'rotate(0deg)';
+ } else {
+ arrow.style.transform = 'rotate(180deg)';
+ }
+ });
+ });
+
+ // Auto-expand first price group
+ const firstPriceGroup = document.querySelector('.price-group-header');
+ if (firstPriceGroup) {
+ firstPriceGroup.click();
+ }
+
+ // Legend hover effect
+ const legendContainer = document.querySelector('.legend-container');
+ const legend = legendContainer.querySelector('.price-legend');
+
+ legendContainer.addEventListener('mouseenter', () => {
+ legend.style.opacity = '0';
+ });
+
+ legendContainer.addEventListener('mouseleave', () => {
+ legend.style.opacity = '1';
+ });
+
+ // Smooth scroll for menu links
+ const menuLinks = document.querySelectorAll('a[href*="#menu-section"]');
+
+ menuLinks.forEach(link => {
+ link.addEventListener('click', function(e) {
+ e.preventDefault();
+ console.log('Menu link clicked'); // Debug log
+
+ const menuSection = document.getElementById('menu-section');
+ if (menuSection) {
+ const headerHeight = document.querySelector('header').offsetHeight;
+ const menuPosition = menuSection.offsetTop - headerHeight;
+
+ window.scrollTo({
+ top: menuPosition,
+ behavior: 'smooth'
+ });
+ } else {
+ console.error('Menu section not found'); // Debug log
+ }
+ });
+ });
+
+ // Language dropdown functionality
+ const languageButton = document.getElementById('languageButton');
+ const languageDropdown = document.getElementById('languageDropdown');
+
+ if (languageButton && languageDropdown) {
+ // Toggle dropdown
+ languageButton.addEventListener('click', (e) => {
+ e.stopPropagation();
+ languageDropdown.classList.toggle('hidden');
+ });
+
+ // Close dropdown when clicking outside
+ document.addEventListener('click', (e) => {
+ if (!languageButton.contains(e.target) && !languageDropdown.contains(e.target)) {
+ languageDropdown.classList.add('hidden');
+ }
+ });
+
+ // Close dropdown when clicking a language option
+ languageDropdown.querySelectorAll('a').forEach(link => {
+ link.addEventListener('click', () => {
+ languageDropdown.classList.add('hidden');
+ });
+ });
+ }
+
+ // Auto-detect browser language
+ function detectLanguage() {
+ const browserLang = navigator.language.split('-')[0];
+ const supportedLangs = ['de', 'en']; // Add your supported languages here
+
+ if (!localStorage.getItem('userLanguage')) {
+ const detectedLang = supportedLangs.includes(browserLang) ? browserLang : 'de';
+ localStorage.setItem('userLanguage', detectedLang);
+
+ // Redirect if needed
+ const currentLang = document.documentElement.lang;
+ if (currentLang !== detectedLang) {
+ const newPath = window.location.pathname.replace(`/${currentLang}/`, `/${detectedLang}/`);
+ window.location.href = newPath;
+ }
+ }
+ }
+
+ detectLanguage();
+
+ function checkOpenStatus() {
+ const now = new Date();
+ const currentTime = now.toLocaleTimeString('de-DE', {
+ hour: '2-digit',
+ minute: '2-digit',
+ hour12: false
+ });
+ const currentDay = now.toLocaleDateString('de-DE', { weekday: 'long' });
+
+ // Get opening hours from data attributes
+ const hoursRows = document.querySelectorAll('.hours-row');
+ let isOpen = false;
+
+ hoursRows.forEach(row => {
+ const rowDay = row.dataset.day;
+ const openTime = row.dataset.open;
+ const closeTime = row.dataset.close;
+
+ // Convert times to comparable numbers (e.g., "14:30" -> 1430)
+ const currentNum = parseInt(currentTime.replace(':', ''));
+ const openNum = parseInt(openTime.replace(':', ''));
+ const closeNum = parseInt(closeTime.replace(':', ''));
+
+ if (rowDay === currentDay && currentNum >= openNum && currentNum <= closeNum) {
+ isOpen = true;
+ row.classList.add('border-2', 'border-status-green');
+ } else {
+ row.classList.remove('border-2', 'border-status-green');
+ }
+ });
+
+ // Update status bar
+ const statusBar = document.getElementById('status-bar');
+ const statusText = document.getElementById('status-text');
+
+ if (statusBar && statusText) {
+ if (isOpen) {
+ statusBar.classList.remove('bg-status-red');
+ statusBar.classList.add('bg-status-green');
+ statusText.textContent = statusText.dataset.textOpen;
+ } else {
+ statusBar.classList.remove('bg-status-green');
+ statusBar.classList.add('bg-status-red');
+ statusText.textContent = statusText.dataset.textClosed;
+ }
+ }
+
+ return { isOpen, currentDay, currentTime };
+ }
+
+ // Update status every minute
+ setInterval(checkOpenStatus, 60000);
+ // Initial check
+ checkOpenStatus();
+});
\ No newline at end of file
diff --git a/static/js/menu.js b/static/js/menu.js
new file mode 100644
index 0000000..055a51b
--- /dev/null
+++ b/static/js/menu.js
@@ -0,0 +1,29 @@
+// Menu category handling
+document.addEventListener('DOMContentLoaded', function() {
+ // Handle tab switching
+ const allTabButtons = document.querySelectorAll('[data-tab]');
+ allTabButtons.forEach(button => {
+ button.addEventListener('click', function() {
+ const tabId = this.getAttribute('data-tab');
+
+ // Hide all content
+ document.querySelectorAll('.menu-content').forEach(content => {
+ content.classList.add('hidden');
+ });
+
+ // Show selected content
+ document.getElementById(tabId + '-content').classList.remove('hidden');
+
+ // Update active states for all buttons with same data-tab
+ allTabButtons.forEach(btn => {
+ if (btn.getAttribute('data-tab') === tabId) {
+ btn.classList.add('bg-pizza-red', 'text-white');
+ btn.classList.remove('bg-gray-200', 'dark:bg-pizza-darker', 'text-gray-700');
+ } else {
+ btn.classList.remove('bg-pizza-red', 'text-white');
+ btn.classList.add('bg-gray-200', 'dark:bg-pizza-darker', 'text-gray-700');
+ }
+ });
+ });
+ });
+});
\ No newline at end of file
diff --git a/static/js/opening-status.js b/static/js/opening-status.js
new file mode 100644
index 0000000..1c9d527
--- /dev/null
+++ b/static/js/opening-status.js
@@ -0,0 +1,49 @@
+function updateTime() {
+ const now = new Date();
+ const currentTime = now.toLocaleTimeString('de-DE', {
+ hour: '2-digit',
+ minute: '2-digit',
+ hour12: false
+ });
+
+ // Update displayed time
+ const timeDisplay = document.getElementById('current-time');
+ if (timeDisplay) {
+ timeDisplay.textContent = currentTime;
+ }
+
+ // Check opening status
+ fetch('/api/check-open-status')
+ .then(response => response.json())
+ .then(status => {
+ // Update status bar
+ const statusBar = document.getElementById('status-bar');
+ const statusText = document.getElementById('status-text');
+
+ if (statusBar) {
+ statusBar.className = status.isOpen
+ ? 'bg-status-green transition-colors duration-300'
+ : 'bg-status-red transition-colors duration-300';
+ }
+
+ if (statusText) {
+ const textOpen = statusText.dataset.textOpen;
+ const textClosed = statusText.dataset.textClosed;
+ statusText.textContent = status.isOpen ? textOpen : textClosed;
+ }
+
+ // Update opening hours rows
+ document.querySelectorAll('.hours-row').forEach(row => {
+ const open = row.dataset.open;
+ const close = row.dataset.close;
+ const isCurrentTimeSlot = currentTime >= open && currentTime <= close;
+
+ row.classList.toggle('border-2', isCurrentTimeSlot && status.isOpen);
+ row.classList.toggle('border-status-green', isCurrentTimeSlot && status.isOpen);
+ });
+ });
+}
+
+// Update immediately and then every minute
+updateTime();
+setInterval(updateTime, 60000);
\ No newline at end of file
diff --git a/static/js/theme.js b/static/js/theme.js
new file mode 100644
index 0000000..48e7b93
--- /dev/null
+++ b/static/js/theme.js
@@ -0,0 +1,42 @@
+// Theme handling
+function getPreferredTheme() {
+ if (localStorage.getItem('theme') === 'dark' ||
+ (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
+ return 'dark';
+ }
+ return 'light';
+}
+
+function setTheme(theme) {
+ if (theme === 'dark') {
+ document.documentElement.classList.add('dark');
+ } else {
+ document.documentElement.classList.remove('dark');
+ }
+ localStorage.setItem('theme', theme);
+}
+
+function toggleTheme() {
+ const isDark = document.documentElement.classList.contains('dark');
+ setTheme(isDark ? 'light' : 'dark');
+}
+
+// Initialize theme
+if (getPreferredTheme() === 'dark') {
+ setTheme('dark');
+}
+
+// Add click event listener
+document.addEventListener('DOMContentLoaded', () => {
+ const darkModeToggle = document.getElementById('darkModeToggle');
+ if (darkModeToggle) {
+ darkModeToggle.addEventListener('click', toggleTheme);
+ }
+});
+
+// Watch for system theme changes
+window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
+ if (!localStorage.getItem('theme')) {
+ setTheme(e.matches ? 'dark' : 'light');
+ }
+});
\ No newline at end of file