Hardcoded secure: true silently drops the cookie on HTTP (localhost),
causing the post-join redirect to bounce back to /login. Use $app/environment
dev flag so the cookie works in development while remaining Secure in production.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SecurityConfig: /** covers /v1/invites/{code}/accept (two path segments);
/* only matched one segment so the accept endpoint was returning 401
- HouseholdIdentityPanel + page: use --green-dark bg (matching BrandPanel
on login) instead of --green-tint; text updated to white/--green-light
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- handleInviteClick: show toast and bail early when POST /invites fails
- handleRegenerate: show toast when regeneration POST fails
- handleRoleChange: add Content-Type: application/json header on PATCH
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
POST /members/invites was returning the full ApiResponseInviteResponse
wrapper. The client set activeInvite directly from the response body,
so shareUrl/inviteCode/expiresAt were missing (nested under .data).
Fixed to return data?.data — the inner InviteResponse — matching the
shape that InvitePanel and page.server.ts already expect.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When activeInvite is null and the user clicks the invite card, POST to
/members/invites first to generate a code, then toggle the panel open.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MemberCard: white bg, 1px border + shadow-card, centered column layout,
avatar color by role (green-dark/blue), role badge with role-specific colors,
join date "seit DD.MM.YYYY", Du-badge below join date, ⋯ kebab with icons
and divider, inline role-control with Abbrechen, blue editing border #B5D4F4
- InviteCard: white bg, 1.5px dashed border, min-height 180px, plus circle,
label "Mitglied einladen", full hover state (green border/bg/icon/label)
- InvitePanel: white bg, title "Einladelink teilen", description, mono link
box, yellow expiry pill when ≤ 24h, text-link "Neuen Link generieren"
- RemoveDialog: white bg, padding 28px 32px, "?" in title, updated body text
- +page.server.ts: expose householdName from locals.haushalt
- +page.svelte: subtitle "{n} Mitglieder · {householdName}"
- Tests: add join date format test, Abbrechen test, InvitePanel title test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add --color-border-hover to the design system neutrals and replace the
hardcoded hex in all three card definitions (settings hub ×2, SettingsCard).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The green left border was removed from the design — the accent prop,
data-accent attribute, and inline style were never used on the hub page.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The outer {:else} already guarantees isOnboarding is false — inner guards
were always-true dead conditions unreachable by tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds beforeEach(vi.clearAllMocks) to prevent shared vi.fn() state in
baseProps from leaking across tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds regression test for the {#if slot.id} guard on the remove button —
QA flagged the missing negative test case for optimistic slots.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- border-radius: 10px → var(--radius-lg) in both tile components
- opacity: 0.42 → var(--opacity-dimmed) in DesktopDayTile
- var(--yellow) → var(--color-ring-today) for today ring and date circle
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces (t: any) with (t: TagItem) so the API response shape is
validated against the shared TagItem interface.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extracts sanitizeForCssUrl helper that strips '"()\ before the URL
is embedded in url("..."). Prevents CSS injection via the hero image
field in inline style bindings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes local TagItem, Recipe, SlotRecipe, Slot, SlotMap definitions
and imports Recipe, Slot, SlotMap from types.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes local TagItem, SuggestionRecipe, TopSuggestion, Slot interfaces
and imports Suggestion, SlotMap from types.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes local TagItem, SlotRecipe, Slot, Suggestion interfaces and
imports Recipe, Slot, Suggestion from types.ts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds shared Slot and SlotMap interfaces so DesktopDayTile,
EmptyDayTile, and reasoningTags can import rather than re-declare.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
transform-style:preserve-3d on a parent with box-shadow/transition
causes Chrome to fail backface-visibility:hidden. Replace with
independent per-face rotateY transforms:
front: 0deg → -180deg (flipped)
back: 180deg → 0deg (flipped)
No preserve-3d needed — each face is its own compositing layer.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
overflow:hidden on direct children of preserve-3d flattens the 3D
context in Chrome, causing backface-visibility:hidden to fail.
Move border-radius + overflow to inner wrapper divs (.card-front-inner,
.card-back-inner) and keep the face elements themselves free of those
properties. Also add -webkit-backface-visibility:hidden and
will-change:transform for consistent GPU compositing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- backface-visibility hides elements visually but not to pointer events;
disable pointer events on the hidden face explicitly so the X button
on the back face is clickable and the front face doesn't intercept clicks
- Add .scene-selected:hover rule so green ring is not overwritten by the
higher-specificity .scene:hover box-shadow
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Front face:
- Full dual gradient overlay (dark top 32% → transparent → dark bottom 55%)
- Day abbreviation + date number pill at top of each tile
- Recipe name 13px/weight-300 with text-shadow
- Meta line (cookTimeMin · effort) below name
- Glassmorphism tag pills (protein + cuisine only)
- State rings via box-shadow (yellow for today, green for selected)
- Dimming (opacity 0.42) on non-selected filled tiles
Back face:
- Koch-Modus as green primary button
- Entfernen as red outline (transparent bg)
- All buttons 11px / weight 500
EmptyDayTile: add day header + spec-aligned suggestion list layout
Page: remove external column header (now rendered inside each tile)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SlotRecipe from the week-plan API carries no tags, so the protein
gradient lookup in DesktopDayTile always fell through to --color-surface.
Build a recipeById lookup from data.recipes and spread tags onto each
slot's recipe when constructing slotMap.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename --gradient-protein-ei → --gradient-protein-eier (tag is 'Eier')
- Add --gradient-protein-kaese for tag 'Käse' (was missing entirely)
The only protein tags in seed data are Käse, Hülsenfrüchte, Eier.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The CSS variable key must match the actual tag name after umlaut
transliteration. 'veg' would never match a real tag named 'vegetarisch'.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'Hähnchen'.toLowerCase() → 'hähnchen' which never matched the CSS var
--gradient-protein-haehnchen. Add toCssKey() to replace ä→ae, ö→oe,
ü→ue, ß→ss so gradient fallbacks actually resolve.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add dark gradient scrim on card front so recipe name is always readable
over images and protein/cuisine gradients
- Style card-back actions as proper buttons (border, padding, border-radius)
instead of unstyled browser defaults
- Add meta chips for cookTimeMin and effort
- Scope Entfernen inside isPlanner guard alongside Gericht tauschen
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>