Add Phase 1 Pocket Pascal UI: home, pantry, week plan, and plate.

Replace the hello-world shell with the elevated design system, bilingual screens, recipe/extras data, and the interactive Mein Teller view.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Steffi Müller
2026-08-04 12:22:32 +02:00
parent 3785d08e97
commit a482bf5b09
60 changed files with 7366 additions and 72 deletions

View File

@@ -0,0 +1,192 @@
/**
* Pocket Pascal — Elevated Surface Design Tokens
*
* Pivoted from heavy glassmorphism to a low-transparency, tactile system:
* cards read as solid raised surfaces (elevation shadow + faint top/bottom
* bevel), buttons visibly depress on press (inset shadow + 1px downward
* shift) instead of just scaling. `--glass-*` names kept for minimal diff
* across components — they now mean "surface fill / surface blur", not
* "see-through glass". Blur is low (8px) and opacity high (~88%): it softens
* whatever sits behind a card without reading as transparent.
*
* Toggle dark mode by adding/removing the `dark` class on <html>
* (matches Tailwind `darkMode: 'class'` — see README).
*
* Brand hues (protein/obstgem/fett/kh + ink) come from the WCAG-audited
* Pocket Pascal palette, not generic placeholders — see /docs/CONCEPT.html
* section 05/08 for the full rationale and contrast numbers.
*/
:root {
/* ---------- Elevated surface (formerly "glass") ---------- */
--glass-fill: rgba(255, 255, 255, 0.9);
--glass-blur: 8px;
/* top-light / bottom-shadow bevel instead of an even glass edge — reads as raised, not see-through */
--glass-border-from: rgba(255, 255, 255, 0.9);
--glass-border-to: rgba(0, 0, 0, 0.06);
/* ---------- Shadows (three states: resting, elevated/lifted, pressed-in) ---------- */
--shadow-resting: 0 1px 2px rgba(0, 0, 0, 0.06), 0 2px 6px rgba(0, 0, 0, 0.06);
--shadow-elevated: 0 4px 10px rgba(0, 0, 0, 0.10), 0 14px 28px rgba(0, 0, 0, 0.10);
--shadow-pressed: inset 0 2px 5px rgba(0, 0, 0, 0.28), inset 0 1px 1px rgba(0, 0, 0, 0.15);
/* kept for anything still referencing the old name */
--shadow-ambient: var(--shadow-elevated);
/* ---------- Brand ink / neutrals ---------- */
--ink: #191800;
--ink-soft: #5c5b48;
--ink-faint: #6b6a56;
--border: #e2e8f0;
/* ---------- Brand category colors (bright primary + dark accent pairs) ---------- */
--color-protein: #d9f227;
--color-protein-dk: #2e3200;
--color-obstgem: #ff6a3d;
--color-obstgem-dk: #3d1508;
--color-fett: #ffb300;
--color-fett-dk: #3d2900;
--color-kh: #1fd9c4;
--color-kh-dk: #04302b;
--color-pick: #0f7a37;
--color-caution: #c81e1e;
/* ---------- Surface gradients (subtle, sit UNDER glass layers) ---------- */
--surface-gradient: linear-gradient(160deg, #fafaf7 0%, #f0f0ea 100%);
--page-gradient: radial-gradient(120% 100% at 0% 0%, #fff9e0 0%, #ffffff 45%),
radial-gradient(120% 100% at 100% 100%, #e2fbf6 0%, #ffffff 45%);
/* ---------- Action gradients (vibrant, multi-stop) ---------- */
/* NOTE: brand hues are light/high-luminance by design (see contrast audit),
so action gradients pair with --ink text, not white — this keeps every
button at AA contrast without text-shadow hacks. Do not swap to white
text on these without re-checking contrast. */
--gradient-primary: linear-gradient(135deg, #d9f227 0%, #1fd9c4 100%);
--gradient-accent: linear-gradient(135deg, #ff6a3d 0%, #ffb300 100%);
--gradient-caution: linear-gradient(135deg, #ff6a3d 0%, #c81e1e 100%);
/* ---------- Dining Plate chart tokens ---------- */
--plate-rim-light: #ffffff;
--plate-rim-shadow: #d8d8d0;
--plate-well-center: #f7f7f2;
--plate-well-edge: #e6e6dd;
}
.dark {
--glass-fill: rgba(28, 28, 21, 0.88);
--glass-blur: 8px;
--glass-border-from: rgba(255, 255, 255, 0.10);
--glass-border-to: rgba(0, 0, 0, 0.35);
--shadow-resting: 0 1px 2px rgba(0, 0, 0, 0.4), 0 2px 6px rgba(0, 0, 0, 0.3);
--shadow-elevated: 0 4px 10px rgba(0, 0, 0, 0.45), 0 16px 32px rgba(0, 0, 0, 0.4);
--shadow-pressed: inset 0 2px 5px rgba(0, 0, 0, 0.6), inset 0 1px 1px rgba(0, 0, 0, 0.3);
--shadow-ambient: var(--shadow-elevated);
--ink: #f3f2e6;
--ink-soft: #c2c1ac;
--ink-faint: #8f8e7a;
--border: #33342a;
/* category primaries stay identical (they're the brand, not a theme) */
--color-protein: #d9f227;
--color-protein-dk: #2e3200;
--color-obstgem: #ff6a3d;
--color-obstgem-dk: #3d1508;
--color-fett: #ffb300;
--color-fett-dk: #3d2900;
--color-kh: #1fd9c4;
--color-kh-dk: #04302b;
--color-pick: #4ade80;
--color-caution: #ff6b60;
--surface-gradient: linear-gradient(160deg, #1c1c15 0%, #14140f 100%);
--page-gradient: radial-gradient(120% 100% at 0% 0%, #2a2a12 0%, #14140f 45%),
radial-gradient(120% 100% at 100% 100%, #0f2a26 0%, #14140f 45%);
--gradient-primary: linear-gradient(135deg, #d9f227 0%, #1fd9c4 100%);
--gradient-accent: linear-gradient(135deg, #ff6a3d 0%, #ffb300 100%);
--gradient-caution: linear-gradient(135deg, #ff6a3d 0%, #ff6b60 100%);
--plate-rim-light: #2a2a22;
--plate-rim-shadow: #0c0c09;
--plate-well-center: #1c1c15;
--plate-well-edge: #111109;
}
/* ---------- Fonts ---------- */
/* Download the two static woff2 files listed in README into /public/fonts,
then this block just works. Using local @font-face (not next/font) keeps
this file framework-agnostic for Cursor. */
@font-face {
font-family: "Unbounded";
font-weight: 700;
font-style: normal;
font-display: swap;
src: url("/fonts/unbounded-700.woff2") format("woff2");
}
@font-face {
font-family: "Unbounded";
font-weight: 900;
font-style: normal;
font-display: swap;
src: url("/fonts/unbounded-900.woff2") format("woff2");
}
@font-face {
font-family: "Albert Sans";
font-weight: 400;
font-style: normal;
font-display: swap;
src: url("/fonts/albert-sans-400.woff2") format("woff2");
}
@font-face {
font-family: "Albert Sans";
font-weight: 500;
font-style: normal;
font-display: swap;
src: url("/fonts/albert-sans-500.woff2") format("woff2");
}
@font-face {
font-family: "Albert Sans";
font-weight: 700;
font-style: normal;
font-display: swap;
src: url("/fonts/albert-sans-700.woff2") format("woff2");
}
.font-display {
font-family: "Unbounded", ui-sans-serif, sans-serif;
letter-spacing: -0.01em;
}
.font-body {
font-family: "Albert Sans", ui-sans-serif, "Segoe UI", Arial, sans-serif;
}
/* ---------- Glass border (gradient 1px border that respects border-radius) ---------- */
/* border-image ignores border-radius, so we use a masked pseudo-element instead.
Apply `.glass-border` to a `relative` container with `overflow-hidden` off
(the pseudo-element is inset:0 and radius:inherit). */
.glass-border {
border-radius: inherit;
padding: 1px;
/* top-light, bottom-shadow — reads as a raised bevel, not a glass sheen */
background: linear-gradient(180deg, var(--glass-border-from), var(--glass-border-to));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
}
/* Applied on top of --shadow-elevated/--shadow-resting to animate between them. */
.elevation-transition {
transition: box-shadow 120ms ease-out, transform 120ms ease-out, filter 120ms ease-out;
}
/* ---------- PWA polish ---------- */
html,
body {
-webkit-tap-highlight-color: transparent;
overscroll-behavior-y: contain;
}
.no-select {
-webkit-user-select: none;
user-select: none;
}