# Handoff: Emma's Schatzkiste — Startseite, Hilfe Verein, Shop ## Overview Website für **Emma's Schatzkiste**, einen Baby- und Kinder-Second-Hand-Laden in Rottenburg a.d. Laaber (Bayern), plus den zugehörigen **Hilfe Verein** ("Hilfe. Herz. Hoffnung."), der sich noch im Aufbau befindet. Three pages: 1. **Startseite** — shop introduction, story, Opa Martin, family value props, song player, teaser to the Hilfe Verein. 2. **Hilfe Verein** — the association: song, three ways to help, the shop's origin story, contact. 3. **Shop** — deliberately parked: an "im Aufbau" (under construction) placeholder page. The online shop is NOT to be built yet. ## About the Design Files The files in `design/` are **design references created in HTML** — prototypes showing intended look and behavior, not production code to copy directly. They are authored in a custom in-house HTML component format (`.dc.html` = template + a small logic class) and will not drop into a normal build as-is. The task is to **recreate these designs in the target codebase's existing environment** (React, Vue, Astro, WordPress, etc.) using its established patterns and libraries. If no environment exists yet, pick the most appropriate stack — this is a small, mostly static marketing site for a local shop, so a static-site generator or a light React/Astro setup is more appropriate than a heavy app framework. ## Fidelity **High fidelity.** Colors, typography, spacing, radii and shadows are all final and come from a bound design system (see *Design Tokens*). Recreate the UI faithfully using the codebase's existing component library where one exists; otherwise implement against the token values listed below. Two things are explicitly unfinished and must not be treated as final: - **Audio files** for the two songs do not exist yet. The players render disabled with an "Audio folgt" badge. - The **Opa Martin photo** is a drop-target placeholder; the real photo is pending. ## Design System All three pages are built on the **Emmas Schatzkiste Design System** (namespace `EmmasSchatzkisteDesignSystem_3da4b6`). The pages compose its components rather than styling raw HTML. Components used, with the props these pages pass: | Component | Used for | Props passed | |---|---|---| | `SiteHeader` | sticky 64px top nav on all 3 pages | `items`, `active`, `onNavigate` | | `SiteFooter` | footer on all 3 pages | `columns` | | `Button` | all CTAs | `as`, `href`, `size`, `variant`, `icon` | | `IconButton` | audio play button (disabled) | `label`, `disabled`, `size` | | `Icon` | Lucide icon wrapper | `name`, `size` | | `Badge` | "Audio folgt", "Im Aufbau" | `tone` | | `SectionHeader` | every section heading | `title`, `icon` | | `InfoTile` | value props + ways-to-help cards | `title`, `body`, `tone`, `cta` | | `TrustBadge` | hero badges | `icon`, `title`, `sub` | | `ImagePlaceholder` | Opa Martin drop slot | `slotId`, `label`, `tone`, `ratio`, `radius` | | `Decor` | flat decorative layer | `variant`, `opacity` | Language and tone rules from the design system, followed throughout: **German, informal "du"**, sentence case, no emoji, prices in German format. Uppercase labels are 11px with 0.08em tracking. --- ## Screens / Views ### 1. Startseite (`design/Startseite.dc.html`) **Purpose.** First contact. Explain what the shop is, build trust, and hand visitors off to the Hilfe Verein. **Layout.** Single column, content constrained to `--page-max` (1180px) with 24px side padding, sections separated by `--space-16` (64px). Full-bleed hero and header. **Sections top to bottom:** **a) SiteHeader** — sticky, 64px, `items: ['Start', 'Shop', 'Hilfe Verein', 'Kontakt']`, `active: 'Start'`. `onNavigate` routes: Shop → Shop page, Hilfe Verein → Verein page, Kontakt → Verein page `#kontakt`. **b) Hero** — full-bleed, `min-height: clamp(540px, 64vw, 680px)`, `display: grid`, content vertically centered. - Background: a full-cover photo, `position: absolute; inset: 0; object-fit: cover; object-position: 74% 45%`. Currently a hot-linked free Pexels photo of children with wooden toys (see *Assets*). - Scrim above it: `linear-gradient(98deg, #FFF 0, #FFF 430px, rgba(255,255,255,.9) 560px, rgba(255,255,255,0) 820px)` — opaque white on the left so text stays readable, fading to clear over the photo on the right. **Note:** this is a fixed-px gradient, deliberately, so the text column always sits fully on solid white regardless of viewport width. - Content column: `max-width: min(100%, 540px)`, left-aligned, `gap: --space-5`. - Shop logo image, `max-width: 200px`, `mix-blend-mode: multiply` (removes the logo JPEG's white box). - **H1**, `font: --text-display-xl` overridden to `font-size: clamp(32px, 7.5vw, 56px); line-height: 1.05`, as a `display: grid` of three lines, each individually rotated for a lively hand-placed feel: - "Gebraucht," — `--sky-500 #2E86D0`, `rotate(-2.5deg)` - "geliebt," — `--sun-600 #A87811`, `rotate(1.5deg) translateX(14px)` - "weitergegeben!" — `--coral-500 #DB513A`, `rotate(-1deg)` - Sub, `--text-body-l`, `--ink-700`, `max-width: 34ch`: "Baby- und Kindersachen aus zweiter Hand — preiswert, gut erhalten, mitten in Rottenburg." - Primary `Button` size `l` with arrow icon → Hilfe Verein page: **"Hilfe Verein ansehen"** - Two `TrustBadge`s in a wrapping flex row, `gap: --space-4`: - sparkles / "Einzelstücke" / "nur 1× vorhanden" - badge-check / "Sehr gut erhalten" / "wir prüfen jedes Teil" **c) "Wie alles angefangen hat"** — `SectionHeader` with a `heart` icon, then a two-column auto-fit grid (`minmax(min(100%,280px),1fr)`, gap `--gutter-grid`) of two `--text-body-l` paragraphs, each `max-width: 52ch`: > Im September haben wir den Second-Hand-Laden übernommen — eine Herzensangelegenheit. Kinder und Jugendliche sollen Spielsachen bekommen, die ein zweites Leben verdient haben: nachhaltig, familienfreundlich und für jeden Geldbeutel. > Bei uns findest du Einzelstücke — vom Strampler bis zum Bobbycar. Jedes Teil gibt es nur 1× vorhanden, und jedes hat schon eine Geschichte hinter sich. **d) Opa Martin** — a deliberately quiet, centered block, `max-width: 560px`, `justify-items: center`. - `ImagePlaceholder` `slotId="opa-martin"`, `tone="sun"`, `ratio="1 / 1"`, `radius: --radius-xl`, label "Bild von Opa Martin hier ablegen". - Below it the name **"Opa Martin"** in `--text-display-m`, `--sky-500`. - **No body text by client instruction** — image and name only. Opa Martin is the owner and the name is important to the brand; do not add a caption or bio. **e) "Für Familien"** — `SectionHeader` with `heart-handshake`, then three `InfoTile`s in an auto-fit grid (`minmax(min(100%,260px),1fr)`): 1. tone `cool` — "Preise für Familien" / "Second-Hand-Preise, die zum Familienbudget passen." 2. tone `band` — "Sehr gut erhalten" / "Auch aus zweiter Hand: geprüft, sauber, in gutem Zustand." 3. tone `soft` — "Wir suchen mit" / "Sag uns, was du brauchst — wir helfen beim Suchen." **f) "Unser Lied"** — `SectionHeader` with `music`. One centered card, `max-width: 520px; margin: 0 auto`. - Card: `--surface-card`, 1px `--line-soft` border, `--radius-l`, `--shadow-card`, `--space-5` padding, grid `gap: --space-4`. - Header row: "Lied vom Laden" in `--text-subheading`/`--sky-500` + `Badge tone="warning"` reading "Audio folgt". - Player row: disabled 44px `IconButton` with a `play` icon, then a flex-1 column with an 8px `--surface-sunk` pill as the progress track and "0:00" in `--text-small`/`--text-muted`. - Footnote: "Sobald die Datei da ist, spielt der Player sie hier ab." - **Gated behind the `audioSichtbar` prop** (boolean, default `true`) so the whole section can be hidden until audio exists. **g) Hilfe-Verein teaser band** — `--surface-band` (`#FDF4DC`), `--radius-band` (24px), `--space-10` padding, two-column auto-fit grid. - Left: uppercase `--text-label` eyebrow "Hilfe. Herz. Hoffnung." in `--sun-600`; H2 "Unser Hilfe Verein ist im Aufbau." in `--text-display-l`/`--sky-500`; paragraph "Soziale Hilfe für unsere Region. Dafür brauchen wir finanzielle und menschliche Hilfe — in jeder Form, die du geben kannst." (`max-width: 46ch`); `Button` size `l` "So kannst du helfen". - Right: the Verein logo, `max-width: 380px`, `--radius-xl`, `--shadow-card`. **h) SiteFooter** + a §19 UStG legal line (see *Legal*). --- ### 2. Hilfe Verein (`design/Hilfe Verein.dc.html`) **Purpose.** Explain the association and convert visitors into donors or volunteers. Client requirement: this page must look and feel **distinctly different** from the Startseite — it is the yellow page, the shop is the blue page. **a) SiteHeader** — same items, `active: 'Hilfe Verein'`. **b) Hero** — the yellow counterpart to the shop hero. Same full-bleed structure, `min-height: clamp(520px, 62vw, 660px)`, but visually differentiated: - Background photo of children playing together (Pexels, hot-linked), `object-position: 72% 40%`. - Scrim: `linear-gradient(100deg, var(--sun-100) 0, var(--sun-100) 430px, rgba(253,244,220,.9) 560px, rgba(253,244,220,0) 820px)` — cream-yellow instead of white. - `border-bottom: 6px solid var(--sun-400)` — a solid yellow edge the shop hero does not have. - Eyebrow is a **rotated yellow pill**, not plain text: `background: --sun-400`, `--ink-700` text, `--text-label` uppercase with `--ls-caps`, `padding: 6px 14px`, `--radius-pill`, `rotate(-2deg)`, reading "Hilfe. Herz. Hoffnung." - **H1**, same clamp scale and rotation treatment, different words and colour order: - "Helfen," — `--sun-600`, `rotate(-2deg)` - "teilen," — `--coral-500`, `rotate(1.5deg) translateX(12px)` - "zusammenhalten!" — `--sky-500`, `rotate(-1deg)` - Sub (`max-width: 34ch`): "Soziale Hilfe vor der Haustür. Der Verein ist gerade im Aufbau — und jede Hand zählt." - **Two** buttons, not one: primary "So kannst du helfen" (→ `#helfen`) and secondary "Kontakt" (→ `#kontakt`). - Two `TrustBadge`s: hand-heart / "Im Aufbau" / "wir fangen gerade an"; map-pin / "Rottenburg a.d. Laaber" / "für Familien hier". - Verein logo positioned `absolute` bottom-right, `width: clamp(110px, 16vw, 180px)`, `mix-blend-mode: multiply`, `rotate(-3deg)`. **c) "Unser Lied"** — identical card pattern to the Startseite, centered, but titled **"Lied vom Hilfe Verein"**. Client requirement: **the two songs must not both appear on both pages** — shop song on the Startseite only, Verein song on this page only. **d) "Wir brauchen Hilfe"** (`id="helfen"`) — `SectionHeader` with `hand-heart`, intro paragraph (`max-width: 56ch`): "Ein Verein im Aufbau braucht beides: Mittel, um wirklich helfen zu können, und Menschen, die mit anpacken. Finanziell und menschlich — in jeder Form." Then three `InfoTile`s, two of which carry a CTA: 1. tone `soft`, "Geldspenden" / "Jeder Betrag hilft — für Ware, Miete und Familien, die gerade nichts übrig haben." / CTA primary "Spenden" → `mailto:` with subject `Spende Hilfe Verein` 2. tone `cool`, "Ehrenamtlich mithelfen" / "Sortieren, verkaufen, aufbauen, mitdenken — regelmäßig oder ab und zu." / CTA secondary "Anrufen" → `tel:` 3. tone `band`, "Weitersagen" / "Reichweite kostet nichts: erzähl von uns und bring Familien vorbei." / no CTA These three are exactly the help types the client asked for: **Geldspenden, ehrenamtliche Helfer, Reichweite/Weitersagen**. Do not add donation tiers, a payment form or a membership flow — the association is not incorporated yet. **e) "Wo alles angefangen hat"** — `--surface-band` band, two columns: copy left with a secondary `Button` "Mehr über den Laden" → Startseite; shop logo right, `max-width: 360px`. Copy: > Im September haben wir den Second-Hand-Laden übernommen — eine Herzensangelegenheit. Kinder und Jugendliche bekommen bei uns Spielsachen, die ein zweites Leben verdient haben. > Die Sachen sind preiswert, sehr gut erhalten und von guter Qualität. Und wir suchen mit, bis du findest, was du brauchst. **f) "Schreib uns"** (`id="kontakt"`) — `SectionHeader` with `mail`, then three white cards in an auto-fit grid (`minmax(min(100%,240px),1fr)`). Each: uppercase `--text-label` `--text-muted` label + value in `--text-body-l`. - Adresse — "84056 Rottenburg a.d. Laaber" - Telefon — `tel:015751479212` → "0157 51479212" - E-Mail — `mailto:emmas.schatzkiste.hilft@gmail.com` (`word-break: break-word`) **g) SiteFooter** + §19 UStG line. --- ### 3. Shop (`design/Shop.dc.html`) **Purpose.** The online shop is **intentionally parked**. The nav link stays visible so visitors know a shop is coming, but the page only announces that it is under construction. **Do not implement a storefront, cart or checkout.** **Layout.** `min-height: 100vh`, flex column; header, a flex-1 centered `
`, footer pinned at the bottom. **Content**, centered, `max-width: 620px`, `gap: --space-5`: - `Badge tone="warning"` — "Im Aufbau" - H1 `--text-display-l`/`--sky-500` — "Der Online-Shop ist noch im Aufbau." - Paragraph `max-width: 48ch` — "Wir richten ihn gerade ein. Bis dahin findest du unsere Sachen im Laden in Rottenburg a.d. Laaber — oder du rufst an und wir suchen mit." - Two `Button`s size `l`, centered flex row: primary `tel:` "0157 51479212", secondary "Zurück zur Startseite". --- ## Interactions & Behavior **Navigation.** `SiteHeader` is controlled — it does not contain links. It calls `onNavigate(itemLabel)` and each page maps the label to a destination. When porting, replace this with the target framework's router and mark the active item from the current route. | Label | Destination | |---|---| | Start | Startseite | | Shop | Shop page | | Hilfe Verein | Hilfe Verein page | | Kontakt | Hilfe Verein page, `#kontakt` anchor | Client instruction: the nav is exactly these four items. An earlier "Unser Laden" item was removed on request — do not reintroduce it. **Audio players.** Both are non-functional by design: the play `IconButton` is `disabled`, the progress track is a static pill, the time reads `0:00`, and a "Audio folgt" badge explains why. When the two MP3s arrive, wire each card to a real audio element, enable the button, and drive the progress pill from `timeupdate`. Persist playback position in `localStorage` and restore on load. Keep the one-song-per-page split. **Hover / press / focus** come from the design system and should be preserved: - Hover: lift 3px, deepen shadow; buttons darken one step (coral 400 → 500). Never lighten, never change hue. - Press: `scale(0.97)`, shadow drops to `--shadow-xs`, fill darkens one further step. - Focus: double ring — `--ring-focus` = `0 0 0 3px var(--sky-100), 0 0 0 5px var(--sky-400)`. On everything. - Disabled: cream fill, muted ink, no shadow, no lift. **Motion.** 120ms for state colour, 200ms for lift, 340ms for anything larger. `--ease-standard` for most things; `--ease-bounce` only on category discs and colour swatches (neither appears on these pages). No load fade-ins, no parallax, no looping animation. **Responsive.** Everything is fluid; there are no media queries. Columns use `repeat(auto-fit, minmax(min(100%, Npx), 1fr))` so they collapse to one column on narrow viewports. Headline sizes use `clamp()`. The heroes use `min-height: clamp(...)` so they shrink on phones. ⚠️ **Known weak point to fix when porting:** the hero scrims use fixed-pixel gradient stops (430px / 560px / 820px). On viewports narrower than ~820px the photo is almost entirely covered by the scrim. Consider swapping to a vertical stack below ~768px: photo on top, text block below on solid colour. ## State Management Minimal — these are marketing pages. - `Startseite`: one prop, `audioSichtbar` (boolean, default `true`), toggles the entire "Unser Lied" section. Port as a feature flag or CMS field. - All three pages hold a small `dsReady` flag used only to wait for the design-system bundle before rendering icons. **This is an artifact of the prototype environment — drop it entirely** and import icons normally. - No data fetching. No forms. Contact is via `tel:` and `mailto:` links only. ## Design Tokens **Colour — brand** | Token | Hex | Role | |---|---|---| | `--sky-400` | `#4A9FE0` | header, secondary buttons | | `--sky-500` | `#2E86D0` | headings, links | | `--sky-600` | `#1F6BAB` | link hover | | `--sky-50` | `#EAF4FC` | cool band | | `--sky-100` | `#CFE6F8` | focus halo | | `--sun-400` | `#F5C13B` | highlight, Verein hero edge + pill | | `--sun-600` | `#A87811` | yellow-on-light text (contrast-safe) | | `--sun-100` | `#FDF4DC` | band + footer cream, Verein hero scrim | | `--coral-400` | `#F4715A` | action colour (buy/press) | | `--coral-500` | `#DB513A` | action hover, coral-on-light text | | `--coral-50` | `#FFF1EE` | soft band | **Colour — neutrals & semantics** `--surface-page`/`--surface-card` `#FFFFFF` · `--surface-sunk` `#F5F7FA` · `--surface-band` `#FDF4DC` · `--surface-footer` `#FDF4DC` · `--ink-300` `#8B94A0` (muted) · `--ink-500` `#4A5560` (body) · `--ink-700` `#232A33` (prices, strong) · `--line-soft` `#EDEFF2` (card borders) · `--line` `#DFE3E8` **Typography.** Display: **Fredoka** (Google Fonts). Body: **Nunito** (Google Fonts), 15px base, 1.6 leading. Two families only. Both are substitutions for an unsupplied brand font — swap in real binaries if they exist. | Token | Size / line-height | Weight | |---|---|---| | `--text-display-xl` | 56px / 1.02 | 700 | | `--text-display-l` | 42px / 1.06 | 700 | | `--text-display-m` | 32px / 1.12 | 600 | | `--text-heading-s` | 24px / 1.2 | 600 | | `--text-subheading` | 19px / 1.3 | 600 | | `--text-body-l` | 17px / 1.6 | 400 | | `--text-body-m` | 15px / 1.6 | 400 | | `--text-small` | 13px / 1.5 | 400 | | `--text-label` | 11px / 1.4 | 700 | Display tracking `--ls-display: -0.01em`; uppercase labels `--ls-caps: 0.08em`. Both H1s override `--text-display-xl` to `font-size: clamp(32px, 7.5vw, 56px); line-height: 1.05`. **Spacing** — 4px base: 0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 80, 96px (`--space-0` … `--space-24`). Layout: `--page-max: 1180px`, `--page-pad-x: 24px`, `--gutter-grid: 20px`, `--section-gap: 56px`, `--header-h: 64px`. ⚠️ `--space-14` does **not** exist — an earlier draft used it and silently broke the hero padding. **Radius** — 6 / 10 / 14 / 20 / 28px (`--radius-xs` … `--radius-xl`), `--radius-band: 24px`, `--radius-pill: 999px`, `--radius-circle: 50%`. **Nothing is square.** Every button, input, badge and select is a full pill. **Shadows** — warm, blue-tinted, never black, never coloured: `--shadow-xs: 0 1px 2px rgba(35,52,74,.06)` · `--shadow-card: 0 2px 10px rgba(35,52,74,.07)` · `--shadow-card-hover: 0 10px 24px rgba(35,52,74,.13)` · `--shadow-band: 0 4px 22px rgba(35,52,74,.09)` · `--shadow-pop: 0 16px 40px rgba(35,52,74,.18)` · `--shadow-button: 0 2px 0 rgba(35,52,74,.10)` (bottom-only, buttons at rest) · `--shadow-inset-sunk: inset 0 1px 2px rgba(35,52,74,.06)` ## Assets **Logos** (`design/` references `./assets/`, included in this bundle): - `assets/logo-shop.jpeg` — "Emma's Schatzkiste, Baby & Kind Second Hand". Supplied by the client. - `assets/logo-verein.jpeg` — "Emma's Schatzkiste Hilfe Verein — Hilfe. Herz. Hoffnung." Supplied by the client. Both are **JPEGs with a baked-in white background**. The pages hide that box with `mix-blend-mode: multiply`, which works because they sit on white or pale cream. **Ask the client for transparent PNG or SVG versions** and drop the blend mode — the current approach will break on any darker background. **Hero photography — placeholders, replace before launch.** Two free Pexels photos are **hot-linked, not licensed or downloaded**: - Startseite: `https://images.pexels.com/photos/3661386/pexels-photo-3661386.jpeg` (children with wooden toys) - Hilfe Verein: `https://images.pexels.com/photos/8435803/pexels-photo-8435803.jpeg` (children playing together) Pexels images are free for commercial use, but hot-linking a third-party CDN in production is not acceptable. Either self-host them or — preferred — replace both with real photos from the shop. Check current Pexels terms before shipping either one. **Opa Martin photo — missing.** Renders as a labelled drop-target placeholder (`ImagePlaceholder slotId="opa-martin"`). Client has confirmed a photo is coming. Image and name only, no caption. **Audio — missing.** Two songs, one per page. Neither file has been delivered. **Icons** — **Lucide**, 2px stroke, `currentColor`, via `https://unpkg.com/lucide@0.451.0/dist/umd/lucide.js`, wrapped by the design system's `Icon` component. Names used: `heart`, `heart-handshake`, `hand-heart`, `music`, `mail`, `map-pin`, `play`, `sparkles`, `badge-check`, `search`, `arrow-right`. Sizes: 15px in trust badges, 17–18px in nav/buttons, 22px in section headings. Stroke weight stays 2 at every size. Use a proper Lucide package rather than the CDN UMD build in production. ## Legal **Kleinunternehmerregelung nach § 19 UStG.** All three pages carry this line beneath the footer, on `--surface-footer` in `--text-small`/`--text-muted`: > Kleinunternehmerregelung nach § 19 UStG: Als Kleinunternehmer berechnen wir keine Umsatzsteuer und weisen sie daher auch nicht aus. Keep it on every page. If a shop is ever built, this wording must also appear at checkout and on invoices. Note the site currently has **no Impressum and no Datenschutzerklärung** — both are legally required for a German commercial site and must be added before launch. The footer's "Impressum" link is a label only and does not resolve. ## Still open (client-side) 1. Opa Martin photo 2. Two audio files (shop song, Verein song) 3. Opening hours and full street address — only postcode and town are known 4. Transparent logo files 5. Legal name / status of the association (not yet incorporated; currently referred to only as "Hilfe Verein") 6. Impressum and Datenschutzerklärung content ## Files ``` design/Startseite.dc.html Startseite design/Hilfe Verein.dc.html Hilfe Verein page design/Shop.dc.html "Im Aufbau" shop placeholder design/support.js prototype runtime — reference only, do not port design/image-slot.js drag-and-drop image placeholder — reference only assets/logo-shop.jpeg shop logo (client-supplied) assets/logo-verein.jpeg Verein logo (client-supplied) ``` Each `.dc.html` is a single file: an HTML template followed by a small logic class in a `