pantrybase 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,8 +5,8 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>Pantrybase</title>
7
7
  <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='8' fill='%23c2410c'/><path d='M9 22V10h7a4 4 0 0 1 0 8h-7' stroke='white' stroke-width='3' fill='none' stroke-linecap='round'/></svg>" />
8
- <script type="module" crossorigin src="/assets/index-lHc1E7AV.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-Dsc3USAJ.css">
8
+ <script type="module" crossorigin src="/assets/index-PBzjTL7i.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index--7z6Fb_H.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="app"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pantrybase",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Local-first recipe knowledge base for Claude Code: capture meal-box recipe cards from photos, search by ingredient, tag, allergen or mood, match recipes to your pantry, explore them as a graph, and synthesize new ones.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: cook
3
- description: Answer "what can I cook?" from the pantrybase recipe collection and the user's pantry, find recipes by ingredient, tag, cuisine, allergen or mood, keep the pantry up to date, and invent new recipes grounded in the collection. Use when the user asks for meal ideas, what to make with what they have, recipes matching criteria, a new recipe in the style of their collection, or to update their pantry.
3
+ description: Answer "what can I cook?" from the pantrybase recipe collection and the user's pantry, find recipes by ingredient, tag, cuisine, allergen or mood, plan several meals around shared ingredients with one grocery list, keep the pantry up to date, and invent new recipes grounded in the collection. Use when the user asks for meal ideas, what to make with what they have, recipes matching criteria, a meal plan or shopping list, a new recipe in the style of their collection, or to update their pantry.
4
4
  ---
5
5
 
6
6
  # Cook from the collection
@@ -19,6 +19,14 @@ description: Answer "what can I cook?" from the pantrybase recipe collection and
19
19
  - Criteria → `pb_search` with `tags` (assigned: cuisine, diet, dish, protein, starch, flavor, texture, method, meal, time, season; derived: allergen, equipment, technique, chef, provider, plan). Parents expand: `cuisine: [asian]` includes thai and korean.
20
20
  - `pb_list_tags` shows which values exist.
21
21
 
22
+ ## Plan meals around shared ingredients
23
+ Goal: a few dinners that share their shopping, then one grocery list. Keep the pantry honest along the way.
24
+ 1. **Start.** The user names a recipe ("plan around the harissa chicken") → `pb_plan_suggest {seed}`; "plan me 4 dinners" with no favourite → `pb_pantry_match` or `pb_search` to find a starting point they like, then seed with it. Pass constraints as filters (`tags`, `exclude_allergens`, `max_total_min`).
25
+ 2. **Suggest.** Each suggestion shows `shares` (already on the list for a planned recipe), `from_pantry`, `new` (what it adds) and `reuse` (share already covered). Lead with the top 3–4, say in a phrase *why* each fits ("shares the peppers and coriander, adds only feta"), and flag `repeats` (same dish again). For a full week at once, `pb_plan_suggest {seed, auto: n}` picks the set that minimises the whole list — show it and let the user swap items.
26
+ 3. **Save.** When the user picks, `pb_plan {action: "add" | "set", slugs}`; `servings` scales quantities. The plan is shared with the web UI (`/plan`), so they can carry on there.
27
+ 4. **Confirm the pantry before the list.** `pb_plan_shopping_list` returns `pantry_check`: the pantry items the plan counts on, with the amount needed and what the pantry says it has. Ask the user to confirm those are really there — one short question listing them — then call again with `confirmed` for the ones they have and `out_of` for the ones they don't (`out_of` leaves the pantry and moves onto the list). Skip the question only when `needs_confirmation` is already empty.
28
+ 5. **Hand over the list.** Present `buy` grouped by `aisle` with amounts and which recipes use each item, mention the staples to check, and offer `format: "text"` for a paste-ready version. Don't add staples to the list.
29
+
22
30
  ## Invent a new recipe
23
31
  1. `pb_synthesis_context` with a `query` for what the user wants, `use_pantry: true` if it should use what they have, and any filters. Read the source recipes, shared ingredients, pairings and techniques.
24
32
  2. Write a genuinely new recipe: combine techniques and flavour patterns from the sources, prefer pantry ingredients, keep quantities realistic for the servings, and respect any diet or allergen constraints.
@@ -1 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),t.credentials=e.crossOrigin===`use-credentials`?`include`:e.crossOrigin===`anonymous`?`omit`:`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e,t,n,r,i,a,o,s,c,l,u,d={},f=[],p=/^m(i|n|o|s|text|space)$/,m=Array.isArray,h=f.slice,g=Object.assign;function _(e){e&&e.parentNode&&e.remove()}function v(e,t,n){var r,i,a,o={},s=arguments.length;for(a in t)a==`key`?r=t[a]:a==`ref`&&typeof e!=`function`?i=t[a]:o[a]=t[a];return s>2&&(o.children=s>3?h.call(arguments,2):n),b(e,o,r,i,null)}function y(e,t,n){var r,i,a,o=g({},e.props),s=arguments.length;for(a in t)a==`key`?r=t[a]:a==`ref`&&typeof e.type!=`function`?i=t[a]:o[a]=t[a];return s>2&&(o.children=s>3?h.call(arguments,2):n),b(e.type,o,r===void 0?e.key:r,i===void 0?e.ref:i,null)}function b(n,r,i,a,o){var s={type:n,props:r,key:i,ref:a,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:o||++t,__i:-1,__u:0};return!o&&e.vnode&&e.vnode(s),s}function x(e){return e.children}function S(e,t){this.props=e,this.context=t,this.__g=0}function C(e,t){if(t==null)return e.__?C(e.__,e.__i+1):null;for(var n;t<e.__k.length;t++)if((n=e.__k[t])&&n.__e)return n.__e;return typeof e.type!=`function`||e.props.__P?null:C(e)}function w(e){if((e=e.__)&&e.__c&&!e.props.__P)return e.__e=null,e.__k.some(function(t){return t&&(e.__e=t.__e)}),w(e)}function T(t){(8&t.__g||!(t.__g|=8)||!n.push(t)||i++)&&r==e.debounceRendering||((r=e.debounceRendering)||queueMicrotask)(E)}function E(){var t,r,o,s,c,l,u,d,f;try{for(r=1;n.length;)n.length>r&&n.sort(a),t=n.shift(),r=n.length,8&t.__g&&(s=void 0,c=void 0,l=(c=(o=t).__v).__e,u=[],d=[],(f=o.__P)&&((s=g({constructor:void 0},c)).__v=c.__v+1,e.vnode&&e.vnode(s),N(f,s,c,o.__n,f.namespaceURI,32&c.__u?[l]:null,u,l||C(c),32&c.__u,d),s.__v=c.__v,s.__.__k[s.__i]=s,P(u,s,d),c.__=c.__e=null,s.__e!=l&&w(s)))}finally{n.length=i=0}}function ee(e,t,n,r,i,a,o,s,c,l,u){var p,m,h,g,_,v,y=r.__k||f,b=t.length;for(c=D(n,t,y,c,b),p=0;p<b;p++)(h=n.__k[p])!=null&&(m=~h.__i&&y[h.__i]||d,h.__i=p,v=N(e,h,m,i,a,o,s,c,l,u),g=h.__e,(m.ref!=h.ref||8&m.__u)&&(m.ref&&F(m.ref,null,h,m),h.ref&&u.push(h.ref,h.__c||g,h)),_||=g,4&h.__u?(c=O(h,c,e,!m.__v),m.__e&&(m.__e=null)):typeof h.type==`function`&&v!==void 0?c=v:g&&(c=g.nextSibling),h.__u&=-7);return n.__e=_,c}function D(e,t,n,r,i){var a,o,s,c,l,u,d,f,p,h,g=n.length,_=g,v=0,y=!1,S=e.__k=Array(i);for(a=0;a<i;a++)(o=t[a])!=null&&typeof o!=`boolean`&&typeof o!=`function`?(typeof o!=`object`||o.constructor==String?o=S[a]=b(null,o):m(o)?o=S[a]=b(x,{children:o}):o.constructor===void 0&&o.__b?o=S[a]=b(o.type,o.props,o.key,o.ref,o.__v):S[a]=o,c=a+v,o.__=e,o.__b=e.__b+1,s=null,~(l=o.__i=A(o,n,c,_))&&(_--,(s=n[l])&&(s.__u|=2)),s&&s.__v?(o.__u|=2,l==c-1?v--:l==c+1?v++:l!=c&&(l>c?v--:v++,y=!0)):(~l||(i>g?v--:i<g&&v++),typeof o.type!=`function`&&(o.__u|=4))):S[a]=null;if(y){for(u=[],d=[],a=0;a<i;a++)if((o=S[a])&&2&o.__u){for(f=0,p=u.length;f<p;)u[h=f+p>>1]<o.__i?f=h+1:p=h;u[f]=o.__i,d[a]=f+1}for(v=u.length;a--;)d[a]&&(d[a]==v?v--:S[a].__u|=4)}if(_)for(a=0;a<g;a++)!(s=n[a])||2&s.__u||(s.__e==r&&(r=C(s)),ie(s,s));return r}function O(e,t,n,r){var i,a,o;if(typeof e.type==`function`){if(e.props.__P)return t;if(i=e.__k)for(a=0;a<i.length;a++)i[a]&&(i[a].__=e,t=O(i[a],t,n,!1));return t}for(t&&!t.parentNode&&(t=C(e))&&!t.parentNode&&(t=null),o=t;o&&o.nodeType==8;)o=o.nextSibling;for(e.__e!=o&&(!r&&n.moveBefore&&e.__e.parentNode?n.moveBefore(e.__e,t):n.insertBefore(e.__e,t||null)),t=e.__e;(t&&=t.nextSibling)&&t.nodeType==8;);return t}function k(e,t){return t||=[],e!=null&&typeof e!=`boolean`&&(m(e)?e.some(function(e){k(e,t)}):t.push(e)),t}function A(e,t,n,r){var i,a,o,s=e.key,c=e.type,l=t[n],u=l&&!(2&l.__u);if(l===null&&s==null||u&&s==l.key&&c==l.type)return n;if(r>+!!u){for(i=n-1,a=n+1;i>=0||a<t.length;)if((l=t[o=i>=0?i--:a++])&&!(2&l.__u)&&s==l.key&&c==l.type)return o}return-1}function j(e,t,n){n??=``,t[0]==`-`?e.setProperty(t,n):e[t]=n}function M(e,t,n,r,i){var a,o;n:if(t==`style`){if(typeof n==`string`)e.style.cssText=n;else{if(typeof r==`string`&&(e.style.cssText=r=``),r)for(t in r)n&&t in n||j(e.style,t,``);if(n)for(t in n)r&&n[t]==r[t]||j(e.style,t,n[t])}}else if(t[0]==`o`&&t[1]==`n`)(e.__e||={})[t]=n,n&&r||(o=l[t]||(l[t]=te(t)),(e.__a||={})[t]=c,a=t!=(t=t.replace(s,`$1`)),(t=t.slice(2))[0]<`a`&&(t=t.toLowerCase()),n?e.addEventListener(t,o,a):e.removeEventListener(t,o,a));else{if(i==`http://www.w3.org/2000/svg`)t=t.replace(/xlink(H|:h)/,`h`).replace(/sName$/,`s`);else if(t!=`width`&&t!=`height`&&t!=`href`&&t!=`list`&&t!=`form`&&t!=`tabIndex`&&t!=`download`&&t!=`rowSpan`&&t!=`colSpan`&&t!=`role`&&t!=`popover`&&t in e)try{e[t]=n??``;break n}catch{}typeof n==`function`||(n==null||!1===n&&t[4]!=`-`?e.removeAttribute(t):e.setAttribute(t,t==`popover`&&n==1?``:n))}}function te(t){return function(n){if(this.__e){var r=this.__e[t];if(n[o]==null)n[o]=c++;else if(n[o]<this.__a[t])return;return r(e.event?e.event(n):n)}}}function N(t,n,r,i,a,o,s,c,l,u){var d,p,h,v,y,b,w,T,E,D,O,k,A,j,M,te,N,P,F,I,L=n.type;if(n.constructor!==void 0)return null;if(128&r.__u&&(l=32&r.__u,d=r.__c.__z)){if(n.__u|=l,p=o=[],d.nodeType==8)for(h=1,v=d.nextSibling;v;v=v.nextSibling){if(v.nodeType==8){if(v.data.startsWith(`$s`))h++;else if(v.data.startsWith(`/$s`)&&!--h)break}o.push(v)}else o.push(d);c=o[0]}(d=e.__b)&&d(n);n:if(typeof L==`function`){y=s.length;try{if(D=n.props,O=(d=L.prototype)&&d.render,k=(d=L.contextType)&&i[d.__c],A=d?k?k.props.value:d.__:i,r.__c?2&(b=n.__c=r.__c).__g&&(b.__g|=1):(O?n.__c=b=new L(D,A):(n.__c=b=new S(D,A),b.constructor=L,b.render=ae),k&&k.sub(b),b.state||(b.state={}),b.__n=i,b.__g|=8,b.__h=[],b.__k=[]),O&&(b.__s||(b.__s=b.state),L.getDerivedStateFromProps&&(b.__s==b.state&&(b.__s=g({},b.__s)),g(b.__s,L.getDerivedStateFromProps(D,b.__s)))),w=b.props,T=b.state,b.__v=n,r.__c){if(O&&!L.getDerivedStateFromProps&&D!==w&&b.componentWillReceiveProps&&b.componentWillReceiveProps(D,A),n.__v==r.__v&&!(8&b.__g)||!(4&b.__g)&&b.shouldComponentUpdate&&!1===b.shouldComponentUpdate(D,b.__s,A)){n.__v!=r.__v&&(b.props=D,b.state=b.__s,b.__g&=-9),n.__e=r.__e,n.__k=r.__k,n.__k.some(function(e){e&&(e.__=n)}),f.push.apply(b.__h,b.__k),b.__k=[],b.__h.length&&s.push(b),c=C(r);break n}b.componentWillUpdate&&b.componentWillUpdate(D,b.__s,A),O&&b.componentDidUpdate&&b.__h.push(function(){b.componentDidUpdate(w,T,E)})}else O&&!L.getDerivedStateFromProps&&b.componentWillMount&&b.componentWillMount(),O&&b.componentDidMount&&b.__h.push(b.componentDidMount);if(b.context=A,b.props=D,b.__P=t,b.__g&=-5,j=e.__r,M=0,O)b.state=b.__s,b.__g&=-9,j&&j(n),d=b.render(b.props,b.state,b.context),f.push.apply(b.__h,b.__k),b.__k=[];else do b.__g&=-9,j&&j(n),d=b.render(b.props,b.state,b.context),b.state=b.__s;while(8&b.__g&&++M<25);b.state=b.__s,b.getChildContext&&(i=g({},i,b.getChildContext())),O&&r.__c&&b.getSnapshotBeforeUpdate&&(E=b.getSnapshotBeforeUpdate(w,T)),te=d&&d.type===x&&d.key==null?d.props.children:d,D.__P&&(d=c,a=(t=D.__P).namespaceURI,l=o=null,r.props&&r.props.__P!=t&&(r.__k.some(function(e){e&&ie(e,e)}),r.__k=null),c=r.__k?C(r,0):null),c=ee(t,m(te)?te:[te],n,r,i,a,o,s,c,l,u),D.__P&&(n.__e=null,c=d),n.__u&=-161,128&r.__u&&(b.__z=null),p&&p.some(_),b.__h.length&&s.push(b),1&b.__g&&(b.__g&=-4)}catch(t){if(s.length=y,n.__v=null,l||o){if(t.then){if(N=0,n.__u|=l?160:128,o){for(~(F=o.indexOf(c||void 0))||(F=o.length);(I=o[F-1])&&I.nodeType==8;)F--;for(;F<o.length;F++)if(I=o[F]){if(o[F]=null,I.nodeType==8){if(I.data.startsWith(`$s`))N++||(P=I);else if(N&&I.data.startsWith(`/$s`)&&!--N){c=I;break}}else if(!N)break}}if(!P){for(;c&&c.nodeType==8&&c.nextSibling;)c=c.nextSibling;P=c}n.__c.__z||(n.__c.__z=P),n.__e=c}else o&&o.some(_)}else n.__e=r.__e;n.__k||=r.__k||[],t.then||ne(n),e.__e(t,n,r)}}else c=n.__e=re(r.__e,n,r,i,a,o,s,l,u,t);return(d=e.diffed)&&d(n),128&n.__u?void 0:c}function ne(e){e&&(e.__c&&(e.__c.__g|=4),e.__k&&e.__k.some(ne))}function P(t,n,r){for(var i=0;i<r.length;)F(r[i++],r[i++],r[i++]);e.__c&&e.__c(n,t),t.some(function(n){try{t=n.__h,n.__h=[],t.some(function(e){e.call(n)})}catch(t){e.__e(t,n.__v)}})}function re(t,n,r,i,a,o,s,c,l,u){var f,g,v,y,b,x,S,w,T,E=r.props||d,D=n.props,O=n.type;if(O==`svg`?a=`http://www.w3.org/2000/svg`:O==`math`?a=`http://www.w3.org/1998/Math/MathML`:a||=`http://www.w3.org/1999/xhtml`,o){for(f=0;f<o.length;f++)if((b=o[f])&&(O?b.localName==O:b.nodeType==3)){t=b,o[f]=null;break}}if(!t){if(w=u.ownerDocument||document,!O)return w.createTextNode(D);t=w.createElementNS(a,O,D.is&&D),c&&=(e.__m&&e.__m(n,o),!1),o=null}if(O){if(u=O==`template`?t.content:t,o=O==`textarea`&&D.defaultValue!=null?null:o&&h.call(u.childNodes),!c&&o)for(E={},f=0;f<t.attributes.length;f++)E[(b=t.attributes[f]).name]=b.value;for(f in E)b=E[f],f==`dangerouslySetInnerHTML`?v=b:f==`children`||f in D||f==`value`&&`defaultValue`in D||f==`checked`&&`defaultChecked`in D||M(t,f,null,b,a);for(f in T=1&r.__u,D)b=D[f],f==`children`?y=b:f==`dangerouslySetInnerHTML`?g=b:f==`value`?x=b:f==`checked`?S=b:c&&typeof b!=`function`||!(E[f]!==b||T&&b!=null)||M(t,f,b,E[f],a);g?(c||v&&(g.__html==v.__html||g.__html==t.innerHTML)||(t.innerHTML=g.__html),n.__k=[]):(v&&(t.textContent=``),(O==`foreignObject`||a==`http://www.w3.org/1998/Math/MathML`&&p.test(O))&&(a=`http://www.w3.org/1999/xhtml`),ee(u,m(y)?y:[y],n,r,i,a,o,s,o?o[0]:r.__k&&C(r,0),c,l),o&&o.some(_)),c&&O!=`textarea`||(f=`value`,O==`progress`&&x==null?t.removeAttribute(f):x==null||x===t[f]&&(O!=`progress`||x)||M(t,f,x,E[f],a),f=`checked`,S!=null&&S!=t[f]&&M(t,f,S,E[f],a))}else E===D||c&&t.data==D||(t.data=D);return t}function F(t,n,r,i){try{typeof t==`function`?n?n.__x=t(n)||1:(i&&=i.__c||i.__e)&&(n=i.__x)&&(i.__x=null,typeof n==`function`?n():t(null)):t.current=n}catch(t){e.__e(t,r)}}function ie(t,n,r){var i,a;if(e.unmount&&e.unmount(t),!(i=t.ref)||i.current&&i.current!=t.__e||F(i,null,n,t),i=t.__c){if(i.componentWillUnmount)try{i.componentWillUnmount()}catch(t){e.__e(t,n)}i.__P=i.__n=null}if(i=t.__k)for(a=0;a<i.length;a++)i[a]&&ie(i[a],n,typeof t.type!=`function`||r&&!t.props.__P);(i=t.__e)&&(r||_(i),i.__e&&(i.__e=null)),t.__e=t.__c=t.__=null}function ae(e,t,n){return this.constructor(e,n)}function I(t,n){var r,i,a,o;e.__&&e.__(t,n),n.nodeType==9&&(n=n.documentElement),i=(r=t&&32&t.__u)?null:n.__k,n.__k=b(x,{children:[t]}),a=[],o=[],N(n,n.__k,i||d,d,n.namespaceURI,i?null:n.firstChild?h.call(n.childNodes):null,a,i?i.__e:n.firstChild,r,o),P(a,n.__k,o),n.__k.props.children=null}function L(e){function t(e){var n,r;return this.getChildContext||(n=new Set,(r={})[t.__c]=this,this.getChildContext=function(){return r},this.shouldComponentUpdate=function(e){this.props.value!=e.value&&n.forEach(function(e){e.__g|=4,T(e)})},this.sub=function(e){n.add(e);var t=e.componentWillUnmount;e.componentWillUnmount=function(){n.delete(e),t&&t.call(e)}}),e.children}return t.__c=`__cC`+u++,t.__=e,t.Provider=(t.Consumer=function(e,t){return e.children(t)}).contextType=t,t}e={__e:function(e,t,n,r){for(var a,o,s;t=t.__;)if((a=t.__c)&&!(1&a.__g)){a.__g|=4;try{if((o=a.constructor)&&o.getDerivedStateFromError&&(a.setState(o.getDerivedStateFromError(e)),s=8&a.__g),a.componentDidCatch&&(a.componentDidCatch(e,r||{}),s=8&a.__g),s)return void(a.__g|=2)}catch(t){e=t,s=0}}throw i=0,e}},t=0,S.prototype.setState=function(e,t){var n=this.__s;n&&n!=this.state||(n=this.__s=g({},this.state)),typeof e==`function`&&(e=e(g({},n),this.props)),e&&(g(n,e),this.__v&&(t&&this.__k.push(t),T(this)))},S.prototype.forceUpdate=function(e){this.__v&&(this.__g|=4,e&&this.__h.push(e),T(this))},S.prototype.render=x,n=[],i=0,a=function(e,t){return e.__v.__b-t.__v.__b},o=Symbol(),s=/(PointerCapture)$|Capture$/i,c=0,l={},u=0;var R,z,oe,se,ce=Object.is,le=0,ue=[],de=[],B=e,fe=B.__b,pe=B.__r,me=B.diffed,he=B.__c,ge=B.unmount,_e=B.__;function ve(e,t){B.__h&&B.__h(z,e,le||t),le=0;var n=z.__H||(z.__H={__:[],__h:[]});return e>=n.__.length&&n.__.push({}),n.__[e]}function V(e){return le=1,ye(je,e)}function ye(e,t,n){var r=ve(R++,2);if(r.t=e,!r.__c&&(r.__=[n?n(t):je(void 0,t),function(e){var t=r.__N?r.__N[0]:r.__[0],n=r.t(t,e);ce(t,n)||(r.__N=[n,r.__[1]],r.__c.setState({}))}],r.__c=z,!z.__f)){z.__f=!0;var i=z.shouldComponentUpdate;z.shouldComponentUpdate=function(e,t,n){var r=this.__H;if(!r)return!0;var a=!1,o=this.props!=e;if(r.__.some(function(e){e.__N&&(a=!0,ce(e.__[0],e.__N[0])||(o=!0))}),i){var s=i.call(this,e,t,n);return a?s||o:s}return!a||o}}return r.__}function be(e,t){var n=ve(R++,3);!B.__s&&Ae(n.__H,t)&&(n.__P=!0,n.__=e,n.u=t,z.__H.__h.push(n))}function xe(e,t){var n=ve(R++,4);!B.__s&&Ae(n.__H,t)&&(n.__P=!1,n.__=e,n.u=t,z.__h.push(n))}function H(e){return le=5,Se(function(){return{current:e}},[])}function Se(e,t){var n=ve(R++,7);return Ae(n.__H,t)&&(n.__=e(),n.__H=t),n.__}function Ce(e,t){return le=8,Se(function(){return e},t)}function we(e){var t=z.context[e.__c],n=ve(R++,9);return n.c=e,t?(n.__??(n.__=!0,t.sub(z)),t.props.value):e.__}function Te(){var e;do{for(;e=de.shift();)try{U(e)}catch(t){B.__e(t,{__:(e=e.__P)&&e.__v})}for(;e=ue.shift();){var t=e.__H;if(e.__P&&t)try{t.__h.some(U),t.__h.some(ke),t.__h=[]}catch(n){t.__h=[],B.__e(n,e.__v)}}}while(de.length)}B.__b=function(e){z=null,fe&&fe(e)},B.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),_e&&_e(e,t)},B.__r=function(e){pe&&pe(e),R=0;var t=(z=e.__c).__H;t&&(oe==z?z.__h=[]:(t.__h.some(U),t.__h.some(ke),R=0),t.__h=[],t.__.some(function(e){e.__N&&(e.__=e.__N),e.u=e.__N=void 0})),oe=z},B.diffed=function(e){me&&me(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&Oe(ue.push(t)),t.__H.__.some(function(e){e.u&&(e.__H=e.u)})),oe=z=null},B.__c=function(e,t){t.some(function(e){try{e.__h.some(U),e.__h=e.__h.filter(function(e){return!e.__||ke(e)})}catch(n){t.some(function(e){e.__h&&=[]}),t=[],B.__e(n,e.__v)}}),he&&he(e,t)},B.unmount=function(e){ge&&ge(e);var t,n,r=e.__c;r&&r.__H&&(r.__H.__.some(function(r){try{if(r.__P&&r.__c){if(n===void 0){for(n=e.__;n&&(!n.__c||!n.__c.__P);)n=n.__;n&&=n.__c}r.__P=n,Oe(de.push(r))}else U(r)}catch(e){t=e}}),r.__H=void 0,t&&B.__e(t,r.__v))};var Ee=typeof requestAnimationFrame==`function`;function De(e){var t,n=function(){clearTimeout(r),Ee&&cancelAnimationFrame(t),setTimeout(e)},r=setTimeout(n,35);Ee&&(t=requestAnimationFrame(n))}function Oe(e){e!=1&&se==B.requestAnimationFrame||((se=B.requestAnimationFrame)||De)(Te)}function U(e){var t=z,n=e.__c;typeof n==`function`&&(e.__c=void 0,n()),z=t}function ke(e){var t=z;e.__c=e.__(),z=t}function Ae(e,t){return!e||e.length!=t.length||t.some(function(t,n){return!ce(t,e[n])})}function je(e,t){return typeof t==`function`?t(e):t}var W,Me;function Ne(e){return!Me||(typeof Me==`string`?e.startsWith(Me):Me.test(e))}function Pe(e,t){let n=``;if(W=void 0,t&&t.type===`click`){if(t.ctrlKey||t.metaKey||t.altKey||t.shiftKey||t.button!==0)return e;let r=t.composedPath().find(e=>e.nodeName==`A`&&e.href),i=r&&r.getAttribute(`href`);if(!r||r.origin!=location.origin||/^#/.test(i)||!/^(_?self)?$/i.test(r.target)||!Ne(i)||r.download)return e;W=!0,t.preventDefault(),n=r.href.replace(location.origin,``)}else t&&t.url?(W=!t.replace,n=t.url):n=location.pathname+location.search;return W===!0?history.pushState(null,``,n):W===!1&&history.replaceState(null,``,n),n}var Fe=(e,t,n={})=>{e=e.split(`/`).filter(Boolean),t=(t||``).split(`/`).filter(Boolean),n.params||={};for(let r=0,i,a;r<Math.max(e.length,t.length);r++){let[,o,s,c]=(t[r]||``).match(/^(:?)(.*?)([+*?]?)$/);if(i=e[r],o||s!=i){if(!o&&i&&c==`*`){n.rest=`/`+e.slice(r).join(`/`);break}if(!o||!i&&c!=`?`&&c!=`*`)return;if(a=c==`+`||c==`*`,a?i=e.slice(r).map(decodeURIComponent).join(`/`)||void 0:i&&=decodeURIComponent(i),n.params[s]=i,s in n||(n[s]=i),a)break}}return n};function Ie(e){let[t,n]=ye(Pe,e.url||location.pathname+location.search);e.scope&&(Me=e.scope);let r=W===!0,i=Se(()=>{let e=new URL(t,location.origin),i=e.pathname.replace(/\/+$/g,``)||`/`;return{url:t,path:i,query:Object.fromEntries(e.searchParams),route:(e,t)=>n({url:e,replace:t}),back:()=>{history.back()},forward:()=>{history.forward()},wasPush:r}},[t]);return xe(()=>(addEventListener(`click`,n),addEventListener(`popstate`,n),()=>{removeEventListener(`click`,n),removeEventListener(`popstate`,n)}),[]),v(Ie.ctx.Provider,{value:i},e.children)}var Le=Promise.resolve();function Re(e){let[t,n]=ye(e=>e+1,0),{url:r,query:i,wasPush:a,path:o}=Ue();if(!r)throw Error(`preact-iso's <Router> must be used within a <LocationProvider>, see: https://github.com/preactjs/preact-iso#locationprovider`);let{rest:s=o,params:c={}}=we(He),l=H(!1),u=H(o),d=H(1),f=H(),p=H(),m=H(),h=H(!1),g=H();g.current=!1;let _,b,x;k(e.children).some(e=>{if(Fe(s,e.props.path,x={...e.props,path:s,query:i,params:Object.assign({},c),rest:``}))return _=y(e,x);e.props.default&&(b=y(e,x))});let S=_||b,C=f.current&&f.current.__u&ze&&f.current.__u&Be,w=f.current&&f.current.__h,T=Se(()=>{p.current=f.current,f.current=v(He.Provider,{value:x},S);let e=p.current&&p.current.props.children;return!e||!S||S.type!==e.type||S.props.component!==e.props.component?(d.current++,!0):!1},[r,JSON.stringify(x)]);C?(f.current.__u|=ze,f.current.__u|=Be):w&&(f.current.__h=!0);let E=p.current;return p.current=null,this.__c=(t,i)=>{g.current=!0,p.current=E,e.onLoadStart&&e.onLoadStart(r),l.current=!0;let a=d.current;t.then(()=>{a===d.current&&(p.current=null,f.current&&(i.__h&&(f.current.__h=i.__h),i.__u&Be&&(f.current.__u|=Be),i.__u&ze&&(f.current.__u|=ze)),Le.then(n))})},xe(()=>{let t=this.__v&&this.__v.__e;g.current?!h.current&&!m.current&&(m.current=t):(!h.current&&m.current&&(m.current!==t&&m.current.remove(),m.current=null),h.current=!0,u.current!==o&&(a&&scrollTo(0,0),e.onRouteChange&&e.onRouteChange(r),u.current=o),e.onLoadEnd&&l.current&&e.onLoadEnd(r),l.current=!1)},[o,a,t]),T?[v(Ve,{r:f,key:d.current}),v(Ve,{r:p,key:d.current-1})]:v(Ve,{r:f,key:d.current})}var ze=32,Be=128,Ve=({r:e})=>e.current;Re.Provider=Ie,Ie.ctx=L({});var He=L({}),G=e=>v(e.component,e),Ue=()=>we(Ie.ctx),We=()=>we(He),Ge=e.__b;e.__b=e=>{e.type&&e.type._forwarded&&e.ref&&(e.props.ref=e.ref,e.ref=null),Ge&&Ge(e)};function Ke(e){let t,n,r=()=>e().then(e=>n=e&&e.default||e),i=e=>{let[,i]=V(0),a=H(n);if(t||=r(),n!==void 0)return v(n,e);throw a.current||=t.then(()=>i(1)),t};return i.preload=()=>(t||=r(),t),i._forwarded=!0,i}var qe=e.__e;e.__e=(e,t,n)=>{if(e&&e.then){let r=t;for(;r=r.__;)if(r.__c&&r.__c.__c)return t.__e??(t.__c.__z=[n.__e],t.__e=n.__e,t.__k=n.__k),t.__k||=[],r.__c.__c(e,t)}qe&&qe(e,t,n)};var Je=`modulepreload`,Ye=function(e){return`/`+e},Xe={},Ze=function(e){return e.pathname.endsWith(`.css`)},Qe=function(e,t,n){if(t in e)return e[t];let r=n();if(!r){e[t]=void 0;return}let i=r.then(()=>{e[t]=void 0},n=>{throw e[t]=void 0,n});return e[t]=i,i},$e=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=Ye(t,n);let r=s(t),i=Ze(r);return Qe(Xe,r.href,()=>{if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let t=document.createElement(`link`);if(t.rel=i?`stylesheet`:Je,i||(t.as=`script`),t.crossOrigin=``,t.href=r.href,a&&t.setAttribute(`nonce`,a),document.head.appendChild(t),i)return new Promise((e,n)=>{t.addEventListener(`load`,e),t.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${r}`)))})})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};async function K(e,t,n,r={}){let i={method:e,headers:{...r}};e!==`GET`&&(i.headers[`X-Pantrybase`]=`1`),n instanceof Blob?i.body=n:n!==void 0&&(i.body=JSON.stringify(n),i.headers[`Content-Type`]=`application/json`);let a=await fetch(t,i),o=await a.json().catch(()=>({}));if(!a.ok)throw Error(o.error??`${a.status} ${a.statusText}`);return o}var et=e=>{let t=new URLSearchParams;for(let[n,r]of Object.entries(e))r!=null&&r!==``&&t.set(n,String(r));let n=t.toString();return n?`?${n}`:``},tt=e=>({tags:e.tags&&Object.keys(e.tags).length?JSON.stringify(e.tags):void 0,exclude_allergens:e.exclude_allergens?.length?e.exclude_allergens.join(`,`):void 0,max_total_min:e.max_total_min,needs_review:e.needs_review?`true`:void 0}),q=(e,t,n)=>{let r=new URLSearchParams;t&&r.set(`w`,String(t)),n&&r.set(`v`,String(n));let i=r.toString();return`/api/files/${e.split(`/`).map(encodeURIComponent).join(`/`)}${i?`?${i}`:``}`},J={stats:()=>K(`GET`,`/api/stats`),facets:()=>K(`GET`,`/api/facets`),search:(e,t,n=48)=>K(`GET`,`/api/search${et({q:e,limit:n,...tt(t)})}`),recipe:e=>K(`GET`,`/api/recipes/${encodeURIComponent(e)}`),pantry:()=>K(`GET`,`/api/pantry`),pantryAdd:e=>K(`POST`,`/api/pantry`,{items:e.map(e=>({name:e}))}),pantryRemove:e=>K(`DELETE`,`/api/pantry`,{names:e}),pantryClear:()=>K(`DELETE`,`/api/pantry`,{all:!0}),match:e=>K(`GET`,`/api/pantry/match${et({...tt(e),min_coverage:e.min_coverage,ingredients:e.ingredients?.join(`,`)})}`),ingredients:e=>K(`GET`,`/api/ingredients${et({q:e,limit:12})}`),graph:e=>K(`GET`,`/api/graph${et({categories:e.categories.join(`,`),ingredients:e.ingredients?`1`:`0`,min_degree:e.min_degree,cuisine:e.cuisine,similar:e.similar})}`),inbox:e=>K(`GET`,`/api/inbox${et({status:e,limit:300})}`),upload:e=>K(`POST`,`/api/inbox/upload`,e,{"X-Filename":encodeURIComponent(e.name)}),resolve:(e,t,n)=>K(`POST`,`/api/inbox/resolve`,{ids:e,status:t,reason:n}),rotate:(e,t)=>K(`POST`,`/api/inbox/rotate`,{id:e,degrees:t})},nt=0;Array.isArray;function Y(t,n,r,i,a,o){n||={};var s,c,l=n;if(`ref`in l&&typeof t!=`function`)for(c in l={},n)c==`ref`?s=n[c]:l[c]=n[c];var u={type:t,props:l,key:r,ref:s,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--nt,__i:-1,__u:0};return(a||o)&&(u.__source=a,u.__self=o),e.vnode&&e.vnode(u),u}function X(e,t){let[n,r]=V({loading:!0}),i=H(0),a=Ce(()=>{let t=++i.current;r(e=>({...e,loading:!0})),e().then(e=>t===i.current&&r({data:e,loading:!1}),e=>t===i.current&&r(t=>({...t,error:String(e instanceof Error?e.message:e),loading:!1})))},t);return be(()=>a(),[a]),{...n,reload:a}}function rt(e,t=250){let[n,r]=V(e);return be(()=>{let n=setTimeout(()=>r(e),t);return()=>clearTimeout(n)},[e,t]),n}function it(e){return e==null?``:e>=60?`${Math.floor(e/60)}h${e%60?` ${e%60}m`:``}`:`${e} min`}function Z(e){return e.replace(/-/g,` `)}function Q(e){let t=`chip${e.tone?` ${e.tone}`:``}`;return e.onClick?Y(`button`,{type:`button`,class:t,onClick:e.onClick,title:e.title,children:e.children}):Y(`span`,{class:t,title:e.title,children:e.children})}function at({r:e}){let t=e.images[0];return Y(`a`,{class:`card`,href:`/recipe/${e.slug}`,children:[t?Y(`div`,{class:`img`,style:{backgroundImage:`url("${q(t,480)}")`}}):Y(`div`,{class:`img none`,"aria-hidden":`true`,children:e.source_kind===`synthesized`?`✦`:`🍽`}),Y(`div`,{class:`body`,children:[Y(`div`,{class:`title`,children:e.title}),e.subtitle&&Y(`div`,{class:`sub`,children:e.subtitle}),Y(`div`,{class:`meta`,children:[e.total_min!=null&&Y(Q,{children:[`⏱ `,it(e.total_min)]}),e.tags.cuisine?.slice(0,1).map(e=>Y(Q,{children:Z(e)},e)),e.tags.diet?.slice(0,2).map(e=>Y(Q,{tone:`ok`,children:Z(e)},e)),e.needs_review&&Y(Q,{tone:`warn`,children:`needs review`})]})]})]})}function $({children:e}){return Y(`div`,{class:`empty`,children:e})}var ot=[`pending`,`done`,`skipped`,`failed`];function st(){let[e,t]=V(`pending`),n=X(()=>J.inbox(e),[e]),[r,i]=V(!1),[a,o]=V(null),[s,c]=V({}),l=async e=>{let r=[...e].filter(e=>/\.(jpe?g|png|webp|heic|heif|tiff?)$/i.test(e.name));if(!r.length)return;let i=[];o({done:0,total:r.length,errors:i});for(let[e,t]of r.entries()){try{await J.upload(t)}catch(e){i.push(`${t.name}: ${String(e)}`)}o({done:e+1,total:r.length,errors:i})}t(`pending`),n.reload()},u=async(e,t)=>{await J.resolve([e.id],t,s[e.id]),n.reload()},[d,f]=V(null),[p,m]=V(null),h=async(e,t)=>{f(e.id),m(null);try{await J.rotate(e.id,t),n.reload()}catch(t){m(`#${e.id}: ${String(t instanceof Error?t.message:t)}`)}finally{f(null)}},g=n.data?.counts;return Y(`div`,{class:`stack`,children:[Y(`label`,{class:`drop${r?` over`:``}`,onDragOver:e=>{e.preventDefault(),i(!0)},onDragLeave:()=>i(!1),onDrop:e=>{e.preventDefault(),i(!1),e.dataTransfer?.files&&l(e.dataTransfer.files)},children:[Y(`input`,{type:`file`,multiple:!0,accept:`image/*,.heic,.heif`,style:{display:`none`},onChange:e=>{let t=e.target.files;t&&l(t)}}),Y(`div`,{style:{fontSize:`1.1rem`,fontWeight:600},children:`Drop recipe card photos here, or click to choose`}),Y(`div`,{class:`small`,children:`JPEG, PNG, WebP or iPhone HEIC — fronts and backs. Exact duplicates are ignored automatically.`}),a&&Y(`div`,{class:`small`,style:{marginTop:`0.5rem`},children:[`Uploaded `,a.done,`/`,a.total,a.errors.map(e=>Y(`div`,{class:`error`,children:e},e))]})]}),g&&g.pending>0&&Y(`div`,{class:`notice`,children:[g.pending,` photo`,g.pending===1?``:`s`,` waiting. In Claude Code, run`,` `,Y(`b`,{children:`/pantrybase:ingest`}),` and Claude will read each card, pair fronts with backs, and save the recipes.`]}),Y(`div`,{class:`tabs`,children:ot.map(n=>Y(`button`,{type:`button`,class:n===e?`on`:``,onClick:()=>t(n),children:[n,` `,g?Y(`span`,{class:`muted`,children:g[n]}):null]},n))}),p&&Y(`p`,{class:`error small`,children:p}),n.data&&n.data.items.length===0?Y($,{children:[`Nothing `,e,`.`]}):Y(`div`,{class:`thumbgrid`,children:n.data?.items.map(e=>Y(`div`,{class:`thumb`,children:[Y(`a`,{href:q(e.path,1600,e.version),target:`_blank`,rel:`noreferrer`,children:Y(`img`,{src:q(e.path,360,e.version),alt:e.name,loading:`lazy`,style:d===e.id?{opacity:.4}:void 0})}),Y(`div`,{class:`tb`,children:[Y(`div`,{class:`row`,style:{justifyContent:`space-between`},children:[Y(`span`,{title:e.name,children:[`#`,e.id]}),Y(`span`,{class:`muted`,children:e.captured_at.slice(5,16).replace(`T`,` `)})]}),e.retake_of&&Y(Q,{tone:`warn`,title:`Looks like photo #${e.retake_of.id} (distance ${e.retake_of.distance})`,children:[`retake of #`,e.retake_of.id]}),e.rotation_hint&&Y(Q,{tone:`warn`,title:e.rotation_hint,children:`may be sideways`}),Y(`fieldset`,{class:`row bare`,"aria-label":`Rotate photo ${e.id}`,children:[[270,`↺`,`Rotate left`],[90,`↻`,`Rotate right`],[180,`180°`,`Turn upside down`]].map(([t,n,r])=>Y(`button`,{type:`button`,class:`small`,title:r,"aria-label":r,disabled:d!==null,onClick:()=>h(e,t),children:n},t))}),e.recipe_slug&&Y(`a`,{href:`/recipe/${e.recipe_slug}`,children:[`→ `,e.recipe_slug]}),e.reason&&Y(`span`,{class:`muted`,children:e.reason}),e.status!==`done`&&Y(x,{children:[e.status===`pending`&&Y(`input`,{type:`text`,placeholder:`reason (optional)`,value:s[e.id]??``,onInput:t=>c(n=>({...n,[e.id]:t.target.value}))}),Y(`div`,{class:`row`,children:e.status===`pending`?Y(x,{children:[Y(`button`,{type:`button`,class:`small`,onClick:()=>u(e,`skipped`),children:`Skip`}),Y(`button`,{type:`button`,class:`small`,onClick:()=>u(e,`failed`),children:`Unreadable`})]}):Y(`button`,{type:`button`,class:`small`,onClick:()=>u(e,`pending`),children:`Back to queue`})})]})]})]},e.id))})]})}function ct(){let e=X(()=>J.pantry(),[]),[t,n]=V(``),[r,i]=V(.5),[a,o]=V(null),s=rt(t,150),c=X(()=>s.trim().length>=2?J.ingredients(s.trim()):Promise.resolve([]),[s]),l=X(()=>J.match({min_coverage:r}),[r,e.data?.length]),u=async t=>{let r=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(r.length){o(null);try{await J.pantryAdd(r),n(``),e.reload()}catch(e){o(String(e))}}},d=async t=>{await J.pantryRemove([t]),e.reload()};return Y(`div`,{class:`layout`,style:{gridTemplateColumns:`minmax(280px, 380px) 1fr`},children:[Y(`section`,{class:`panel stack`,children:[Y(`h2`,{children:`Your pantry`}),Y(`form`,{onSubmit:e=>{e.preventDefault(),u(t)},class:`row`,style:{flexWrap:`nowrap`},children:[Y(`input`,{type:`text`,list:`ingredient-suggestions`,placeholder:`Add items, e.g. eggs, baby marrow, rice`,value:t,onInput:e=>n(e.target.value)}),Y(`datalist`,{id:`ingredient-suggestions`,children:c.data?.map(e=>Y(`option`,{value:e.canonical},e.canonical))}),Y(`button`,{type:`submit`,class:`primary`,children:`Add`})]}),a&&Y(`p`,{class:`error small`,children:a}),e.data?.length?Y(`div`,{class:`row`,children:e.data.map(e=>Y(Q,{onClick:()=>d(e.canonical),title:`Remove`,children:[e.canonical,e.qty==null?``:` ×${e.qty}${e.unit?` ${e.unit}`:``}`,` `,Y(`span`,{class:`x`,children:`✕`})]},e.canonical))}):Y(`p`,{class:`muted small`,children:`Nothing yet. Salt, oil, water and other kitchen staples never count against a recipe, so skip those.`}),e.data&&e.data.length>0&&Y(`button`,{type:`button`,class:`ghost small`,onClick:async()=>{await J.pantryClear(),e.reload()},children:`Clear pantry`})]}),Y(`section`,{class:`panel`,children:[Y(`div`,{class:`row`,style:{justifyContent:`space-between`},children:[Y(`h2`,{children:`What can I cook?`}),Y(`label`,{class:`row small`,children:[`at least `,Math.round(r*100),`% covered`,Y(`input`,{type:`range`,min:0,max:1,step:.1,value:r,onInput:e=>i(Number(e.target.value))})]})]}),l.data&&l.data.results.length===0?Y($,{children:`No recipes reach that coverage yet — add more to your pantry or lower the bar.`}):l.data?.results.map(e=>Y(`div`,{class:`list-row`,children:[Y(`div`,{children:[Y(`a`,{href:`/recipe/${e.slug}`,children:Y(`b`,{children:e.title})}),e.near_miss&&Y(Q,{tone:`warn`,title:`1–2 items short`,children:`near miss`}),Y(`div`,{class:`row small`,style:{marginTop:`0.25rem`},children:e.missing.length?Y(x,{children:[Y(`span`,{class:`muted`,children:`missing`}),e.missing.map(e=>Y(Q,{onClick:()=>u(e.canonical),title:`Add to pantry`,children:[`+ `,Z(e.canonical)]},e.canonical))]}):Y(`span`,{class:`muted`,children:`you have everything`})})]}),Y(`div`,{children:[Y(`div`,{class:`bar`,children:Y(`span`,{style:{width:`${Math.round(e.coverage*100)}%`}})}),Y(`div`,{class:`muted small`,style:{textAlign:`right`},children:[e.have,`/`,e.need,` · `,Math.round(e.coverage*100),`%`]})]})]},e.slug))]})]})}var lt=[[`energy_kj`,`Energy`,`kJ`],[`energy_kcal`,`Energy`,`kcal`],[`protein_g`,`Protein`,`g`],[`carbs_g`,`Carbs`,`g`],[`sugars_g`,`of which sugars`,`g`],[`fibre_g`,`Fibre`,`g`],[`fat_g`,`Fat`,`g`],[`saturated_g`,`of which saturated`,`g`],[`sodium_mg`,`Sodium`,`mg`]];function ut(e){return[e.qty,e.unit].filter(e=>e!=null&&e!==``).join(` `)}function dt(){let{params:e}=We(),t=e.slug??``,n=X(()=>J.recipe(t),[t]),[r,i]=V(0),[a,o]=V(!1);if(n.error)return Y($,{children:n.error});let s=n.data;if(!s)return Y($,{children:`Loading…`});let c=s.recipe,l=new Set(s.pantry_have),u=c.ingredients.filter(e=>e.source!==`kitchen`),d=c.ingredients.filter(e=>e.source===`kitchen`),f=u.filter(e=>!e.staple&&!e.optional&&!l.has(e.canonical)),p=async e=>{o(!0);try{await J.pantryAdd(e),n.reload()}finally{o(!1)}},m=e=>{let t=l.has(e.canonical);return Y(`li`,{children:[Y(`span`,{class:`tick`,title:t?`in your pantry`:e.staple?`staple`:`not in pantry`,children:t?`✓`:e.staple?`·`:`○`}),Y(`span`,{children:[Y(`span`,{title:ut(e)?`${ut(e)} ${e.canonical}`:e.canonical,children:e.raw}),e.prep&&Y(`span`,{class:`prep`,children:[` — `,e.prep]}),e.optional&&!/optional/i.test(e.raw)&&Y(`span`,{class:`muted small`,children:` (optional)`}),e.alternatives?.length?Y(`span`,{class:`muted small`,children:[` · or `,e.alternatives.join(`, `)]}):null,e.components?.length?Y(`div`,{class:`muted small`,children:e.components.map(e=>e.raw).join(` + `)}):null]})]},`${e.raw}-${e.canonical}`)},h=c.nutrition,g=c.provider?.wine;return Y(`article`,{children:[Y(`div`,{class:`hero`,children:[Y(`div`,{class:`gallery`,children:c.images.length?Y(x,{children:[Y(`img`,{class:`main`,src:q(c.images[r]??c.images[0]??``,1400),alt:c.title}),c.images.length>1&&Y(`div`,{class:`thumbs`,children:c.images.map((e,t)=>Y(`button`,{type:`button`,class:`ghost`,style:{padding:0},onClick:()=>i(t),"aria-label":`Photo ${t+1}`,children:Y(`img`,{src:q(e,200),class:t===r?`sel`:``,alt:``})},e))})]}):Y(`div`,{class:`panel empty`,children:`No photo`})}),Y(`div`,{class:`stack`,children:[Y(`div`,{children:[Y(`h1`,{children:c.title}),c.subtitle&&Y(`div`,{class:`muted`,children:c.subtitle})]}),Y(`div`,{class:`row`,children:[`cuisine`,`dish`,`diet`,`protein`,`flavor`,`texture`,`season`].flatMap(e=>(c.tags[e]??[]).map(t=>Y(`a`,{href:`/?tags=${encodeURIComponent(JSON.stringify({[e]:[t]}))}`,children:Y(Q,{tone:e===`diet`?`ok`:void 0,children:Z(t)})},`${e}${t}`)))}),c.extraction?.needs_review&&Y(`div`,{class:`notice`,children:[`Flagged for review`,c.extraction.uncertain?.length?`: couldn't read ${c.extraction.uncertain.join(`, `)}`:``,`.`,c.extraction.notes?` ${c.extraction.notes}`:``]}),c.blurb&&Y(`p`,{children:c.blurb}),Y(`div`,{class:`facts`,children:[c.time.active!=null&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Hands-on`}),it(c.time.active)]}),c.time.total!=null&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Total`}),it(c.time.total)]}),c.servings!=null&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Serves`}),c.servings]}),c.provider?.chef&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Chef`}),c.provider.chef]}),c.provider&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`From`}),c.provider.name??c.provider.id,c.provider.plan?` · ${c.provider.plan}`:``]}),c.provider?.eat_within_days!=null&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Eat within`}),c.provider.eat_within_days,` days`]}),g&&(g.name||g.producer)&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Wine`}),[g.producer,g.name,g.vintage].filter(Boolean).join(` · `)]}),c.source.kind===`synthesized`&&Y(`div`,{class:`fact`,children:[Y(`b`,{children:`Source`}),`Synthesized`]})]}),c.description&&Y(`p`,{class:`muted small`,children:c.description})]})]}),Y(`div`,{class:`cols`,children:[Y(`section`,{class:`panel`,children:[Y(`div`,{class:`row`,style:{justifyContent:`space-between`},children:[Y(`h2`,{children:`Ingredients`}),f.length>0&&Y(`button`,{type:`button`,class:`small`,disabled:a,onClick:()=>p(f.map(e=>e.canonical)),children:`I have these`})]}),Y(`ul`,{class:`ings`,children:u.map(m)}),d.length>0&&Y(x,{children:[Y(`h3`,{style:{marginTop:`1rem`},children:`From your kitchen`}),Y(`ul`,{class:`ings`,children:d.map(m)})]}),Y(`p`,{class:`muted small`,children:`✓ in your pantry · ○ missing · · staple`})]}),Y(`section`,{class:`panel`,children:[Y(`h2`,{children:`Method`}),Y(`ol`,{class:`steps`,children:c.steps.map((e,t)=>Y(`li`,{children:[e.title&&Y(`div`,{class:`stitle`,children:e.title}),Y(`div`,{children:e.text}),Y(`div`,{class:`row`,style:{marginTop:`0.3rem`},children:[e.techniques?.map(e=>Y(Q,{children:Z(e)},e)),e.temp_c!=null&&Y(Q,{children:[`🌡 `,e.temp_c,`°C`]}),e.minutes?.length?Y(Q,{children:[`⏱ `,e.minutes.join(`–`),` min`]}):null]})]},t))}),c.tips.length>0&&Y(x,{children:[Y(`h3`,{children:`Tips`}),c.tips.map(e=>Y(`p`,{class:`small`,children:e},e))]}),c.notes&&Y(x,{children:[Y(`h3`,{children:`Notes`}),Y(`p`,{class:`small`,children:c.notes})]})]}),Y(`aside`,{class:`stack`,children:[h&&Y(`section`,{class:`panel`,children:[Y(`h2`,{children:`Nutrition`}),Y(`div`,{class:`muted small`,children:h.basis===`per_100g`?`per 100 g`:`per serving`}),Y(`table`,{class:`nut`,children:Y(`tbody`,{children:lt.filter(([e])=>h[e]!=null).map(([e,t,n])=>Y(`tr`,{children:[Y(`td`,{children:t}),Y(`td`,{children:[h[e],` `,n]})]},e))})})]}),(c.allergens.length>0||c.equipment.length>0)&&Y(`section`,{class:`panel stack`,children:[c.allergens.length>0&&Y(`div`,{children:[Y(`h3`,{children:`Allergens`}),Y(`div`,{class:`row`,children:c.allergens.map(e=>Y(Q,{tone:`bad`,children:Z(e)},e))})]}),c.equipment.length>0&&Y(`div`,{children:[Y(`h3`,{children:`Equipment`}),Y(`div`,{class:`row`,children:c.equipment.map(e=>Y(Q,{children:Z(e)},e))})]})]}),s.sources.length>0&&Y(`section`,{class:`panel`,children:[Y(`h3`,{children:`Inspired by`}),s.sources.map(e=>Y(`div`,{children:Y(`a`,{href:`/recipe/${e.slug}`,children:e.title})},e.slug))]}),s.derived.length>0&&Y(`section`,{class:`panel`,children:[Y(`h3`,{children:`Recipes built on this`}),s.derived.map(e=>Y(`div`,{children:Y(`a`,{href:`/recipe/${e.slug}`,children:e.title})},e.slug))]})]})]}),s.similar.length>0&&Y(`section`,{style:{marginTop:`2rem`},children:[Y(`h2`,{children:`Similar recipes`}),Y(`div`,{class:`grid`,children:s.similar.map(e=>Y(at,{r:e},e.slug))})]})]})}var ft=[`diet`,`cuisine`,`dish`,`protein`,`starch`,`flavor`,`texture`,`method`,`meal`,`time`,`season`,`technique`,`equipment`,`chef`,`plan`,`provider`],pt=[0,20,30,45,60];function mt(e){let t={};try{t=e.tags?JSON.parse(e.tags):{}}catch{t={}}return{q:e.q??``,tags:t,exclude:e.exclude?e.exclude.split(`,`):[],max:e.max?Number(e.max):0,review:e.review===`1`}}function ht(){let e=Ue(),t=mt(e.query),[n,r]=V(t.q),[i,a]=V(t.tags),[o,s]=V(t.exclude),[c,l]=V(t.max),[u,d]=V(t.review),[f,p]=V({}),m=rt(n);be(()=>{let t=new URLSearchParams;m&&t.set(`q`,m),Object.keys(i).length&&t.set(`tags`,JSON.stringify(i)),o.length&&t.set(`exclude`,o.join(`,`)),c&&t.set(`max`,String(c)),u&&t.set(`review`,`1`);let n=`/${t.toString()?`?${t}`:``}`;n!==`${e.path}${e.url.includes(`?`)?e.url.slice(e.url.indexOf(`?`)):``}`&&e.route(n,!0)},[m,i,o,c,u]);let h={tags:i,exclude_allergens:o,max_total_min:c||void 0,needs_review:u||void 0},g=X(()=>J.search(m,h),[m,JSON.stringify(h)]),_=X(()=>J.facets(),[]),v=(e,t)=>a(n=>{let r=new Set(n[e]??[]);r.has(t)?r.delete(t):r.add(t);let i={...n,[e]:[...r]};return i[e]?.length||delete i[e],i}),y=e=>s(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e]),b=Object.entries(i).flatMap(([e,t])=>t.map(t=>[e,t])),x=_.data?.used??{};return Y(`div`,{class:`layout`,children:[Y(`aside`,{class:`panel`,children:[Y(`div`,{class:`facet`,children:[Y(`h3`,{children:`Total time`}),Y(`select`,{value:c,onChange:e=>l(Number(e.target.value)),children:pt.map(e=>Y(`option`,{value:e,children:e?`≤ ${e} min`:`Any`},e))})]}),x.allergen?.length?Y(`div`,{class:`facet`,children:[Y(`h3`,{children:`Leave out allergens`}),Y(`div`,{class:`chips`,children:x.allergen.map(e=>Y(Q,{tone:o.includes(e.name)?`bad`:void 0,onClick:()=>y(e.name),children:[o.includes(e.name)?`✕ `:``,Z(e.name)]},e.name))})]}):null,ft.filter(e=>x[e]?.length).map(e=>{let t=x[e]??[],n=f[e]?t:t.slice(0,8);return Y(`div`,{class:`facet`,children:[Y(`h3`,{children:e}),Y(`div`,{class:`chips`,children:n.map(t=>Y(Q,{tone:i[e]?.includes(t.name)?`on`:void 0,onClick:()=>v(e,t.name),children:[Z(t.name),` `,Y(`span`,{class:`muted`,children:t.count})]},t.name))}),t.length>8&&Y(`button`,{type:`button`,class:`ghost more`,onClick:()=>p(t=>({...t,[e]:!t[e]})),children:f[e]?`fewer`:`+${t.length-8} more`})]},e)}),Y(`label`,{class:`row small`,children:[Y(`input`,{type:`checkbox`,checked:u,onChange:e=>d(e.target.checked)}),`Only recipes needing review`]})]}),Y(`section`,{class:`stack`,children:[Y(`input`,{type:`search`,placeholder:`Search recipes — a dish, an ingredient, a mood (“cosy weeknight curry”)…`,value:n,onInput:e=>r(e.target.value)}),(b.length>0||o.length>0||c>0)&&Y(`div`,{class:`row`,children:[b.map(([e,t])=>Y(Q,{tone:`on`,onClick:()=>v(e,t),children:[e,`: `,Z(t),` `,Y(`span`,{class:`x`,children:`✕`})]},`${e}:${t}`)),o.map(e=>Y(Q,{tone:`bad`,onClick:()=>y(e),children:[`no `,Z(e),` `,Y(`span`,{class:`x`,children:`✕`})]},e)),Y(`button`,{type:`button`,class:`ghost small`,onClick:()=>{a({}),s([]),l(0),d(!1)},children:`Clear all`})]}),g.error&&Y(`p`,{class:`error`,children:g.error}),Y(`div`,{class:`muted small`,children:[g.data?`${g.data.results.length} recipes`:`Loading…`,g.data&&m?g.data.vector_used?` · semantic + keyword`:` · keyword (semantic index warming up)`:``]}),g.data&&g.data.results.length===0?Y($,{children:[`No recipes match.`,` `,m||b.length?`Try fewer filters.`:`Add some — drop card photos on the Inbox page, then ask Claude to /pantrybase:ingest them.`]}):Y(`div`,{class:`grid`,children:g.data?.results.map(e=>Y(at,{r:e},e.slug))})]})]})}var gt=[`cuisine`,`dish`,`diet`,`protein`,`starch`,`flavor`,`texture`,`method`,`meal`,`time`,`season`,`allergen`,`technique`,`equipment`,`chef`,`plan`,`provider`,`other`];function _t(){let e=X(()=>J.facets(),[]),t=e.data?.used??{},n=gt.filter(e=>t[e]?.length);return e.data&&!n.length?Y($,{children:`No tags yet — they appear as recipes are saved.`}):Y(`div`,{class:`grid`,style:{gridTemplateColumns:`repeat(auto-fill, minmax(300px, 1fr))`},children:n.map(n=>Y(`section`,{class:`panel`,children:[Y(`h3`,{children:[n,` `,Y(`span`,{class:`muted`,children:[`· `,t[n]?.length]})]}),Y(`div`,{class:`row`,children:t[n]?.map(e=>Y(`a`,{href:n===`allergen`?`/?exclude=${encodeURIComponent(e.name)}`:`/?tags=${encodeURIComponent(JSON.stringify({[n]:[e.name]}))}`,children:Y(Q,{children:[Z(e.name),` `,Y(`span`,{class:`muted`,children:e.count})]})},e.name))}),e.data?.vocabulary[n]?.mode===`closed`&&Y(`div`,{class:`muted small`,style:{marginTop:`0.5rem`},children:`Controlled vocabulary`})]},n))})}var vt=Ke(()=>$e(()=>import(`./graph-qSs25SSD.js`).then(e=>e.GraphPage),[]));function yt(){let{path:e}=Ue(),t=X(()=>J.stats(),[e]),n=(t,n,r)=>Y(`a`,{class:`link${(t===`/`?e===`/`:e.startsWith(t))?` active`:``}`,href:t,children:[n,r?Y(`span`,{class:`badge`,children:r}):null]}),r=t.data;return Y(`nav`,{class:`nav`,children:[Y(`a`,{class:`brand`,href:`/`,children:[Y(`i`,{}),` pantrybase`]}),n(`/`,`Recipes`),n(`/pantry`,`Pantry`),n(`/graph`,`Graph`),n(`/inbox`,`Inbox`,r?.inbox.pending),n(`/tags`,`Tags`),Y(`span`,{class:`spacer`}),r&&Y(`span`,{class:`stat`,children:[r.recipes,` recipes · `,r.ingredients,` ingredients`,r.needs_review?` · ${r.needs_review} to review`:``]})]})}function bt(){return Y(Ie,{children:[Y(yt,{}),Y(`main`,{children:Y(Re,{children:[Y(G,{path:`/`,component:ht}),Y(G,{path:`/recipe/:slug`,component:dt}),Y(G,{path:`/pantry`,component:ct}),Y(G,{path:`/graph`,component:vt}),Y(G,{path:`/inbox`,component:st}),Y(G,{path:`/tags`,component:_t}),Y(G,{default:!0,component:ht})]})})]})}var xt=document.getElementById(`app`);xt&&I(Y(bt,{}),xt);export{J as a,be as c,V as d,Y as i,H as l,Z as n,q as o,X as r,Ue as s,Q as t,Se as u};