* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; } :root { --bg: #111; --fg: #eee; --surface: #1a1a1a; --surface-2: #2a2a2a; --surface-3: #3a3a3a; --border: #444; --border-soft: #333; --pfand: #9ab; --danger: #ff8a8a; } :root[data-theme="light"] { --bg: #f4f4f5; --fg: #18181b; --surface: #ffffff; --surface-2: #e7e7ea; --surface-3: #d8d8dc; --border: #bcbcc2; --border-soft: #dddde2; --pfand: #4a6a8a; --danger: #c0392b; } html, body, #app { margin: 0; padding: 0; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: var(--bg); color: var(--fg); font-weight: 600; overscroll-behavior: none; -webkit-user-select: none; user-select: none; } button { font: inherit; font-weight: 700; color: inherit; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 12px 16px; cursor: pointer; } button:active { background: var(--surface-3); } button:disabled { opacity: 0.4; } button.danger { background: #5a2a2a; border-color: #7a3a3a; color: #fff; } /* ---------- Tablet UI (portrait) ---------- */ .tablet { display: flex; flex-direction: column; height: 100%; max-width: 100vw; overflow: hidden; } .bar-picker { display: flex; flex-direction: column; gap: 16px; justify-content: center; align-items: center; height: 100%; padding: 24px; } .bar-picker h1 { margin: 0 0 16px; } .bar-picker button { width: 280px; height: 96px; font-size: 30px; } .theme-toggle { margin-top: 24px; background: transparent; border: 1px solid var(--border); font-size: 18px; padding: 10px 18px; } .topbar { display: flex; justify-content: space-between; align-items: center; padding: 10px 16px; background: var(--surface); border-bottom: 1px solid var(--border-soft); flex: 0 0 auto; } .topbar .brand { display: flex; align-items: center; gap: 10px; min-width: 0; overflow: hidden; } .topbar .logo { flex: 0 0 auto; } .topbar .bar-name { font-size: 26px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .topbar .change { font-size: 17px; padding: 10px 14px; } /* Drink grid: 3 equal columns. Rows no longer assume a fixed count (the old "exactly 5 rows fill the area" formula squeezed every row into 1/5 of the height regardless of how many rows actually existed — 4 rows of drinks looked cramped, with a wasted empty row's worth of space below them). `minmax(min-content, 1fr)`: the floor is each row's own natural content height (name + price + Pfand at whatever font-size is active — this already tracks the smaller mobile font sizes below with no separate number needed) rather than a guessed pixel value, and 1fr means rows are equal height and stretch to fill any leftover space when there's room — but never shrink below that content-derived floor. When there are enough rows that even their natural height doesn't fit the visible area, the grid holds every row at that floor and the whole thing scrolls (overflow-y: auto) instead of cramming rows smaller — "otherwise go for what fits". */ .grid { --gap: 8px; flex: 1 1 0; min-height: 0; display: grid; grid-template-columns: repeat(3, 1fr); grid-auto-rows: minmax(min-content, 1fr); align-content: start; gap: var(--gap); padding: var(--gap); overflow-y: auto; -webkit-overflow-scrolling: touch; } @media (max-width: 480px) { .grid { grid-template-columns: repeat(2, 1fr); } .topbar { padding: 8px 12px; } .topbar .bar-name { font-size: 20px; } .topbar .change { font-size: 15px; padding: 8px 10px; } .drink { font-size: 17px; padding: 6px; } .drink .price { font-size: 17px; } .drink .pfand { font-size: 12px; } .cart { flex: 0 0 34vh; padding: 6px 12px; } .cart-line { font-size: 16px; } .cart-total { font-size: 38px; padding: 2px 0 6px; } .actions button { height: 52px; font-size: 18px; } } .drink { display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; padding: 8px; font-size: 22px; overflow: hidden; } .drink .name { font-weight: 800; line-height: 1.25; max-width: 100%; word-break: break-word; overflow-wrap: break-word; } .drink .price { font-size: 22px; font-weight: 700; margin-top: 8px; } .drink .pfand { font-size: 15px; font-weight: 600; color: var(--pfand); margin-top: 4px; } .drink.pfand-return { background: #5a2a2a; border-color: #7a3a3a; color: #fff; } .picker-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.55); display: flex; align-items: center; justify-content: center; z-index: 10; } .picker { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 20px; width: min(320px, 86vw); display: flex; flex-direction: column; align-items: stretch; gap: 14px; } .picker-title { font-size: 22px; font-weight: 800; text-align: center; } .picker-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; } .picker-count { height: 64px; font-size: 26px; font-weight: 800; } .picker-cancel { background: transparent; border-color: var(--border-soft); } .cart { flex: 0 0 38vh; background: var(--surface); border-top: 1px solid var(--border-soft); padding: 8px 16px; display: flex; flex-direction: column; min-height: 0; } /* #39 follow-up: overflow-y: auto directly on a flex column that also has justify-content: flex-end doesn't reliably scroll in WebKit/Safari (the iOS 12+ targets this app builds for) — the flex-end-justified overflow gets clipped instead of becoming a scrollable region, so from the user's side it looked identical to the original overflow: hidden bug. Standard workaround: the overflow/scroll and the flex-end alignment can't live on the same element — .cart-items is now a plain scroll container (no justify-content), and .cart-items-inner is the flex column that actually bottom-anchors short lists via min-height: 100% (a floor, not a fixed height, so it still grows past 100% and scrolls normally once content overflows it). */ .cart-items { flex: 1 1 0; min-height: 0; overflow-y: auto; margin-bottom: 6px; } .cart-items-inner { min-height: 100%; display: flex; flex-direction: column; justify-content: flex-end; } .cart-line { display: flex; justify-content: space-between; align-items: center; padding: 3px 0; font-size: 20px; font-weight: 600; } .cart-line.pfand { color: var(--pfand); } .cart-line.return { color: var(--danger); } .cart-line.muted { opacity: 0.5; } .cart-line-label { display: flex; align-items: center; gap: 8px; } .qty-btn { flex: 0 0 auto; width: 28px; height: 28px; padding: 0; line-height: 1; font-size: 18px; border-radius: 6px; } .cart-total { font-size: 56px; font-weight: 800; text-align: right; line-height: 1.1; padding: 4px 0 8px; } .cart-total.negative { color: var(--danger); } .actions { display: flex; gap: 8px; } .actions button { flex: 1; height: 64px; font-size: 22px; font-weight: 800; color: #fff; } .actions .cancel { background: #5a2a2a; border-color: #7a3a3a; } .actions .confirm { background: #2a5a2a; border-color: #3a7a3a; } .actions .crew { background: #2a3a5a; border-color: #3a4a7a; } /* ---------- Admin ---------- */ .admin { max-width: 960px; margin: 0 auto; padding: 16px; } .admin h1, .admin h2 { margin-top: 24px; } .admin table { width: 100%; border-collapse: collapse; margin-bottom: 16px; } .admin th, .admin td { padding: 6px 8px; border-bottom: 1px solid var(--border-soft); text-align: left; } .admin input, .admin select { background: var(--surface); color: var(--fg); border: 1px solid var(--border); border-radius: 4px; padding: 6px; } .admin .row { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; flex-wrap: wrap; } .admin .muted { opacity: 0.6; } .admin .login { max-width: 320px; margin: 80px auto; display: flex; flex-direction: column; gap: 12px; } .admin .chart { background: var(--surface); border: 1px solid var(--border-soft); border-radius: 8px; padding: 12px 12px 4px; margin-bottom: 16px; } .dnd-list { list-style: none; padding: 0; margin: 0 0 8px; } .dnd-item { display: flex; align-items: center; gap: 8px; padding: 6px 8px; margin-bottom: 4px; background: var(--surface); border: 1px solid var(--border-soft); border-radius: 6px; cursor: grab; } .dnd-item:active { cursor: grabbing; } .dnd-item.drop-target { border-color: #6aa; background: var(--surface-2); } .dnd-item .grip { opacity: 0.4; cursor: grab; user-select: none; } .dnd-item .dnd-name { flex: 1; } .dnd-item button { padding: 2px 8px; font-size: 13px; } .dnd-list li.muted { padding: 6px 8px; }