diff --git a/package-lock.json b/package-lock.json
index a68dede..048909d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,6 +8,7 @@
"name": "muslimpro-clone-phase1",
"version": "0.1.0",
"dependencies": {
+ "tesseract.js": "^5.1.1",
"vite-plugin-pwa": "^0.21.0",
"workbox-precaching": "^7.3.0"
},
@@ -2729,6 +2730,12 @@
"node": ">=6.0.0"
}
},
+ "node_modules/bmp-js": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz",
+ "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==",
+ "license": "MIT"
+ },
"node_modules/brace-expansion": {
"version": "5.0.9",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
@@ -3725,6 +3732,12 @@
"integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==",
"license": "ISC"
},
+ "node_modules/idb-keyval": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.3.0.tgz",
+ "integrity": "sha512-um+2dgAWmYsu615EXpWVwSmapJhON0G43t3Ka/EVaohzPQXSMqKEqeDK/oIW3Ow+BXaF2PvSc+oBTFp793A5Ow==",
+ "license": "Apache-2.0"
+ },
"node_modules/internal-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz",
@@ -3881,6 +3894,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-electron": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz",
+ "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==",
+ "license": "MIT"
+ },
"node_modules/is-finalizationregistry": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz",
@@ -4094,6 +4113,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-url": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz",
+ "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==",
+ "license": "MIT"
+ },
"node_modules/is-weakmap": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
@@ -4345,6 +4370,26 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
"node_modules/node-releases": {
"version": "2.0.52",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz",
@@ -4395,6 +4440,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/opencollective-postinstall": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+ "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+ "license": "MIT",
+ "bin": {
+ "opencollective-postinstall": "index.js"
+ }
+ },
"node_modules/own-keys": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz",
@@ -4566,6 +4620,12 @@
"node": ">=4"
}
},
+ "node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+ "license": "MIT"
+ },
"node_modules/regexp.prototype.flags": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz",
@@ -5168,6 +5228,31 @@
"node": ">=10"
}
},
+ "node_modules/tesseract.js": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/tesseract.js/-/tesseract.js-5.1.1.tgz",
+ "integrity": "sha512-lzVl/Ar3P3zhpUT31NjqeCo1f+D5+YfpZ5J62eo2S14QNVOmHBTtbchHm/YAbOOOzCegFnKf4B3Qih9LuldcYQ==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bmp-js": "^0.1.0",
+ "idb-keyval": "^6.2.0",
+ "is-electron": "^2.2.2",
+ "is-url": "^1.2.4",
+ "node-fetch": "^2.6.9",
+ "opencollective-postinstall": "^2.0.3",
+ "regenerator-runtime": "^0.13.3",
+ "tesseract.js-core": "^5.1.1",
+ "wasm-feature-detect": "^1.2.11",
+ "zlibjs": "^0.3.1"
+ }
+ },
+ "node_modules/tesseract.js-core": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-5.1.1.tgz",
+ "integrity": "sha512-KX3bYSU5iGcO1XJa+QGPbi+Zjo2qq6eBhNjSGR5E5q0JtzkoipJKOUQD7ph8kFyteCEfEQ0maWLu8MCXtvX5uQ==",
+ "license": "Apache-2.0"
+ },
"node_modules/tinyglobby": {
"version": "0.2.17",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz",
@@ -5184,6 +5269,12 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT"
+ },
"node_modules/type-fest": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz",
@@ -5513,6 +5604,28 @@
}
}
},
+ "node_modules/wasm-feature-detect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
+ "integrity": "sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5828,6 +5941,15 @@
"integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
"dev": true,
"license": "MIT"
+ },
+ "node_modules/zlibjs": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/zlibjs/-/zlibjs-0.3.1.tgz",
+ "integrity": "sha512-+J9RrgTKOmlxFSDHo0pI1xM6BLVUv+o0ZT9ANtCxGkjIVCCUdx9alUF8Gm+dGLKbkkkidWIHFDZHDMpfITt4+w==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
}
}
}
diff --git a/package.json b/package.json
index 11dee29..d25dfef 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"vite": "^6.2.0"
},
"dependencies": {
+ "tesseract.js": "^5.1.1",
"vite-plugin-pwa": "^0.21.0",
"workbox-precaching": "^7.3.0"
}
diff --git a/src/App.svelte b/src/App.svelte
index c67b688..dad4c91 100644
--- a/src/App.svelte
+++ b/src/App.svelte
@@ -5,9 +5,12 @@
import Hijri from './lib/Hijri.svelte';
import Tasbih from './lib/Tasbih.svelte';
import Names99 from './lib/Names99.svelte';
+ import HalalFoodFinder from './lib/HalalFoodFinder.svelte';
+ import IngredientScanner from './lib/IngredientScanner.svelte';
- const tabs = ['Prayer', 'Qibla', 'Quran', 'Hijri', 'Tasbih', '99 Names'];
- const icons = ['π', 'π§', 'π', 'π
', 'πΏ', 'π'];
+ const tabs = ['Prayer', 'Qibla', 'Quran', 'Hijri', 'Tasbih', 'Names', 'Food', 'Scan'];
+ const icons = ['π', 'π§', 'π', 'π
', 'πΏ', 'π', 'π½οΈ', 'π'];
+ const premiumTabs = new Set([6, 7]);
let activeTab = $state(0);
function handleKeydown(e) {
@@ -51,6 +54,10 @@
{:else if activeTab === 5}
+ {:else if activeTab === 6}
+
+ {:else if activeTab === 7}
+
{/if}
diff --git a/src/lib/HalalFoodFinder.svelte b/src/lib/HalalFoodFinder.svelte
new file mode 100644
index 0000000..484c30f
--- /dev/null
+++ b/src/lib/HalalFoodFinder.svelte
@@ -0,0 +1,208 @@
+
+
+
+
π½οΈ Halal Food Finder
+ {#if loading}
+
π Getting your locationβ¦
+ {:else if error}
+
{error}
+
+ {:else}
+
+
+
+
+
+
Radius:{#each radiusOptions as r}{/each}
+
+
+
+
+
+
+
{#each cuisineList as c}{/each}
+
+
{filtered.length} restaurant{filtered.length !== 1 ? 's' : ''} within {radius}km
+ {#if viewMode === 'list'}
+ {#if filtered.length === 0}
+
π No restaurants found
Try increasing radius or changing filters
+ {:else}
+
+ {#each filtered as resto (resto.id)}
+
+
+ {#if expandedId === resto.id}
+
+
π {resto.address}
+ {#if resto.phone}
π {resto.phone}
{/if}
+ {#if resto.certifications.length > 0}
+
Certifications:{#each resto.certifications as certId}{@const cert = getCert(certId)}{#if cert}
{'β'.repeat(cert.trustLevel)}{cert.name}({cert.country})
{/if}{/each}
+ {:else if resto.muslimOwned}
+
π€ Muslim-owned establishment. Awaiting or not yet pursuing halal certification.
+ {:else}
+
β No halal certification found. Exercise caution.
+ {/if}
+ {#if resto.userReviews.length > 0}
+
Community Reviews ({resto.userReviews.length}):{#each resto.userReviews as review}
{'β'.repeat(review.rating)}{review.comment}{review.date}
{/each}
+ {/if}
+
+ {/if}
+
+ {/each}
+
+ {/if}
+ {:else}
+
+ {/if}
+ {/if}
+
+
+
diff --git a/src/lib/IngredientScanner.svelte b/src/lib/IngredientScanner.svelte
new file mode 100644
index 0000000..70a0b97
--- /dev/null
+++ b/src/lib/IngredientScanner.svelte
@@ -0,0 +1,291 @@
+
+
+
+
π Halal Ingredient Scanner
+
+
+
+
+
+
+
+
+ {#if scanMode === 'paste'}
+
+
+
+
+ {#if ingredientText}
+
+ {/if}
+
+
+
+
+
+
Quick E-number lookup:
+
+ {#each ['E120','E322','E422','E441','E471','E542','E621','E631','E635','E904','E920'] as code}
+ {@const found = findByENumber(code)}
+
+ {/each}
+
+
+ {/if}
+
+
+ {#if scanMode === 'camera'}
+
+ {#if cameraState === 'idle' || cameraState === 'starting'}
+
+
π· {cameraState === 'starting' ? 'Starting cameraβ¦' : 'Tap to start camera'}
+ {#if cameraState === 'idle'}
{/if}
+
+ {:else if cameraState === 'active'}
+
+
+
+
+
+ {:else if cameraState === 'error'}
+
β {cameraError}
+ {/if}
+
+ {/if}
+
+
+ {#if scanned}
+
+
+
0} class:mushbooh={summary.haram === 0 && summary.mushbooh > 0} class:halal={summary.haram === 0 && summary.mushbooh === 0 && summary.halal > 0}>
+
{summary.verdict}
+
+ {#if summary.haram > 0}π« {summary.haram} Haram{/if}
+ {#if summary.mushbooh > 0}β {summary.mushbooh} Doubtful{/if}
+ {#if summary.halal > 0}β
{summary.halal} Halal{/if}
+ {#if summary.unknown > 0}β {summary.unknown} Unknown{/if}
+
+
+
+
+
+ {#each results as item (item.id)}
+
+
+ {#if item.ingredient}
+
+
Category: {item.ingredient.category}
+
{item.ingredient.explanation}
+
π {item.ingredient.scholarlyNote}
+
+ {:else}
+
Not found in our database. Check JAKIM portal or MUI.
+ {/if}
+
+ {/each}
+
+
+ {/if}
+
+
+ {#if history.length > 0}
+
+ π Recent Scans ({history.length})
+
+ {#each history as h}
+
+ {new Date(h.timestamp).toLocaleString()}
+ {h.results} ingredient{h.results !== 1 ? 's' : ''}
+
+ {/each}
+
+
+
+ {/if}
+
+
+
diff --git a/src/lib/halalDB.js b/src/lib/halalDB.js
new file mode 100644
index 0000000..adbc4dc
--- /dev/null
+++ b/src/lib/halalDB.js
@@ -0,0 +1,542 @@
+// Halal Food Finder & Ingredient Scanner β Shared Data Module
+// Nur Falah Muslim Companion β Premium Features
+
+export const CERTIFICATION_BODIES = [
+ { id: 'jakim', name: 'JAKIM', country: 'Malaysia', url: 'https://www.halal.gov.my', trustLevel: 5 },
+ { id: 'mui', name: 'MUI', country: 'Indonesia', url: 'https://www.halalmui.org', trustLevel: 5 },
+ { id: 'muis', name: 'MUIS', country: 'Singapore', url: 'https://www.muis.gov.sg', trustLevel: 5 },
+ { id: 'esma', name: 'ESMA', country: 'UAE', url: 'https://www.esma.gov.ae', trustLevel: 5 },
+ { id: 'hfa', name: 'HFA', country: 'UK', url: 'https://www.halalfoodauthority.com', trustLevel: 4 },
+ { id: 'hmc', name: 'HMC', country: 'UK', url: 'https://halalhmc.org', trustLevel: 4 },
+ { id: 'ifanca', name: 'IFANCA', country: 'USA', url: 'https://www.ifanca.org', trustLevel: 4 },
+ { id: 'sanha', name: 'SANHA', country: 'South Africa', url: 'https://www.sanha.org.za', trustLevel: 4 },
+ { id: 'gac', name: 'GAC', country: 'Philippines', url: 'https://halal.da.gov.ph', trustLevel: 4 },
+ { id: 'cicot', name: 'CICOT', country: 'Thailand', url: 'https://www.cicot.or.th', trustLevel: 4 },
+ { id: 'bpjph', name: 'BPJPH', country: 'Indonesia', url: 'https://bpjph.halal.go.id', trustLevel: 5 },
+ { id: 'halal_au',name: 'Halal Australia', country: 'Australia', url: 'https://halalaustralia.com.au', trustLevel: 3 },
+];
+
+export const INGREDIENT_ALIASES = {
+ 'carmine': 'E120', 'cochineal': 'E120', 'natural red 4': 'E120',
+ 'carminic acid': 'E120', 'crimson lake': 'E120',
+ 'shellac': 'E904', 'confectioners glaze': 'E904', 'resinous glaze': 'E904',
+ 'glycerin': 'E422', 'glycerine': 'E422', 'glycerol': 'E422',
+ 'lecithin': 'E322', 'soy lecithin': 'E322', 'soya lecithin': 'E322',
+ 'bone char': 'E542', 'bone phosphate': 'E542', 'edible bone phosphate': 'E542',
+ 'l-cysteine': 'E920', 'cysteine': 'E920', 'l cysteine': 'E920',
+ 'mono and diglycerides': 'E471', 'monoglycerides': 'E471', 'diglycerides': 'E471',
+ 'mono diglycerides': 'E471', 'mono- and diglycerides': 'E471',
+ 'stearic acid': 'E570', 'octadecanoic acid': 'E570',
+ 'sodium stearoyl lactylate': 'E481', 'ssl': 'E481',
+ 'calcium stearoyl lactylate': 'E482', 'csl': 'E482',
+ 'polysorbate 60': 'E435', 'polysorbate 65': 'E436', 'polysorbate 80': 'E433',
+ 'gelatin': 'E441', 'gelatine': 'E441',
+ 'lanolin': 'E913', 'wool fat': 'E913', 'wool grease': 'E913',
+ 'beeswax': 'E901', 'white beeswax': 'E901', 'yellow beeswax': 'E901',
+ 'xanthan': 'E415', 'xanthan gum': 'E415',
+ 'guar': 'E412', 'guar gum': 'E412',
+ 'citric acid': 'E330',
+ 'sorbic acid': 'E200',
+ 'benzoic acid': 'E210',
+ 'sodium benzoate': 'E211',
+ 'potassium sorbate': 'E202',
+ 'silicon dioxide': 'E551', 'silica': 'E551',
+ 'titanium dioxide': 'E171',
+ 'magnesium stearate': 'E470b',
+ 'propylene glycol': 'E1520',
+ 'sodium bicarbonate': 'E500', 'baking soda': 'E500',
+ 'msg': 'E621', 'monosodium glutamate': 'E621',
+ 'aspartame': 'E951',
+ 'acesulfame k': 'E950', 'acesulfame potassium': 'E950',
+ 'sucralose': 'E955',
+ 'saccharin': 'E954',
+ 'beta carotene': 'E160a', 'Ξ²-carotene': 'E160a',
+ 'carrageenan': 'E407',
+ 'carboxymethylcellulose': 'E466', 'cmc': 'E466',
+ 'sodium carboxymethylcellulose': 'E466',
+ 'acetic acid': 'E260',
+ 'lactic acid': 'E270',
+ 'malic acid': 'E296',
+ 'tartaric acid': 'E334',
+ 'phosphoric acid': 'E338',
+ 'ascorbic acid': 'E300', 'vitamin c': 'E300',
+ 'tocopherols': 'E306', 'vitamin e': 'E306',
+ 'riboflavin': 'E101', 'vitamin b2': 'E101',
+ 'curcumin': 'E100', 'turmeric': 'E100',
+ 'chlorophyll': 'E140',
+ 'annatto': 'E160b',
+ 'paprika extract': 'E160c',
+ 'lycopene': 'E160d',
+ 'beetroot red': 'E162', 'betanin': 'E162',
+ 'anthocyanins': 'E163',
+ 'calcium carbonate': 'E170',
+ 'agar': 'E406', 'agar agar': 'E406',
+ 'locust bean gum': 'E410', 'carob gum': 'E410',
+ 'gum arabic': 'E414', 'acacia gum': 'E414',
+ 'pectin': 'E440',
+ 'sodium alginate': 'E401',
+ 'potassium alginate': 'E402',
+ 'ammonium alginate': 'E403',
+ 'alginic acid': 'E400',
+ 'propylene glycol alginate': 'E405',
+ 'modified starch': 'E1404',
+ 'sorbitol': 'E420',
+ 'mannitol': 'E421',
+ 'maltitol': 'E965',
+ 'xylitol': 'E967',
+ 'erythritol': 'E968',
+ 'isomalt': 'E953',
+ 'lactitol': 'E966',
+ 'invertase': 'E1103',
+ 'lysozyme': 'E1105',
+ 'carbon dioxide': 'E290',
+ 'nitrogen': 'E941',
+ 'sodium carbonate': 'E500',
+ 'potassium carbonate': 'E501',
+ 'ammonium carbonate': 'E503',
+ 'magnesium carbonate': 'E504',
+ 'sodium hydroxide': 'E524',
+ 'potassium hydroxide': 'E525',
+ 'calcium hydroxide': 'E526',
+ 'hydrochloric acid': 'E507',
+ 'sulphuric acid': 'E513',
+};
+
+export const HARAM_INGREDIENTS = [
+ // ββ HARAM ββββββββββββββββββββββββββββββββββββββββββββββ
+ { eNumber: 'E120', name: 'Carmine / Cochineal', status: 'haram',
+ category: 'Colouring Agent',
+ explanation: 'Derived from crushed cochineal insects (Dactylopius coccus). All major schools of fiqh consider insects impure and impermissible to consume, except locusts.',
+ scholarlyNote: 'Fatwa by JAKIM and MUI: carmine is haram as it comes from insects which are najis.' },
+ { eNumber: 'E441', name: 'Gelatin', status: 'haram',
+ category: 'Gelling Agent',
+ explanation: 'Typically sourced from pig skin (Type A) or cattle bones (Type B). Unless explicitly certified halal (from zabiha-slaughtered cattle or fish), it is haram.',
+ scholarlyNote: 'If the source is confirmed halal (fish or Islamically slaughtered cattle), gelatin becomes halal. Look for halal certification on packaging.' },
+ { eNumber: 'E542', name: 'Edible Bone Phosphate', status: 'haram',
+ category: 'Anti-caking Agent',
+ explanation: 'Produced from animal bones, often from non-halal slaughtered animals.',
+ scholarlyNote: 'Derived from animal bones; haram unless sourced from halal-slaughtered animals.' },
+ { eNumber: 'E904', name: 'Shellac', status: 'haram',
+ category: 'Glazing Agent',
+ explanation: 'Secreted by the lac insect (Kerria lacca). Used to glaze confectionery, pills, and fruits. Considered impure by most scholars.',
+ scholarlyNote: 'JAKIM and MUI classify shellac as haram. Some Hanafi scholars permit it on the basis of istihala (complete transformation), but the majority position is haram.' },
+ { eNumber: 'E913', name: 'Lanolin', status: 'haram',
+ category: 'Glazing Agent',
+ explanation: 'Wool grease from sheep. While sheep is halal, lanolin is extracted in a way that may involve non-halal processing aids.',
+ scholarlyNote: 'Controversial β some scholars consider it halal as it comes from a halal animal, but its extraction often uses non-halal materials.' },
+ { eNumber: 'E920', name: 'L-Cysteine', status: 'haram',
+ category: 'Flour Treatment Agent',
+ explanation: 'Commonly derived from human hair, poultry feathers, or hog hair. Used in bread and bakery products as a dough conditioner.',
+ scholarlyNote: 'If sourced from human hair or pig, it is haram. Synthetic/fermentation-derived L-cysteine is halal but rarely labeled.' },
+ { eNumber: 'E921', name: 'L-Cystine', status: 'haram',
+ category: 'Flour Treatment Agent',
+ explanation: 'Oxidized form of L-cysteine. Same animal-derived sourcing concerns.',
+ scholarlyNote: 'Same ruling as E920.' },
+ { eNumber: 'LARD', name: 'Lard', status: 'haram',
+ category: 'Fat',
+ explanation: 'Rendered pig fat. Strictly haram under all circumstances in Islamic dietary law.',
+ scholarlyNote: 'Quran 2:173 explicitly forbids pork. Lard is pork-derived and carries unanimous prohibition across all madhabs.' },
+ { eNumber: 'CASTOR', name: 'Castoreum', status: 'haram',
+ category: 'Flavouring',
+ explanation: 'Exudate from castor sacs of beavers. Used in vanilla and raspberry flavourings.',
+ scholarlyNote: 'Derived from an animal not slaughtered Islamically; classified as haram.' },
+ { eNumber: 'CIVET', name: 'Civet', status: 'haram',
+ category: 'Flavouring',
+ explanation: 'Musk-like secretion from the civet cat. Used in some traditional flavourings.',
+ scholarlyNote: 'Impure secretion from a non-halal slaughtered source.' },
+ { eNumber: 'AMBER', name: 'Ambergris', status: 'haram',
+ category: 'Flavouring',
+ explanation: 'Waxy substance from sperm whale digestive tract. Debate exists among scholars.',
+ scholarlyNote: 'Some Maliki scholars permit it (sea creature, dies naturally). Majority Hanafi/Shafi\'i consider it impure.' },
+
+ // ββ MUSHBOOH (DOUBTFUL β NEEDS VERIFICATION) ββββββββββ
+ { eNumber: 'E471', name: 'Mono- and Diglycerides', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Can be derived from plant oils (soy, palm) OR animal fats. Very common in bread, ice cream, margarine, and processed foods.',
+ scholarlyNote: 'Check the source. Plant-derived E471 is halal. Animal-derived E471 is haram unless from halal-slaughtered animals. Halal certification determines the ruling.' },
+ { eNumber: 'E472a', name: 'Acetic Acid Esters of MG', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Esters of mono- and diglycerides. The fatty acid source determines halal status.',
+ scholarlyNote: 'Same ruling as E471 β depends on the fatty acid source.' },
+ { eNumber: 'E472b', name: 'Lactic Acid Esters of MG', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Lactic acid esters. Fatty acid source may be animal or plant.',
+ scholarlyNote: 'Dependent on the source of the fatty acids used.' },
+ { eNumber: 'E472c', name: 'Citric Acid Esters of MG', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Citric acid esters. The glycerol/fat source needs verification.',
+ scholarlyNote: 'Depends on the origin of the raw materials.' },
+ { eNumber: 'E472d', name: 'Tartaric Acid Esters of MG', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Tartaric acid esters, common in bakery products.',
+ scholarlyNote: 'Source of fatty acids determines halal status.' },
+ { eNumber: 'E472e', name: 'MAG of Diacetyl Tartaric Acid', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'DATEM β a dough strengthener used in bread-making.',
+ scholarlyNote: 'Plant-derived DATEM is halal. Verify with manufacturer or halal certification.' },
+ { eNumber: 'E472f', name: 'Mixed Acetic & Tartaric Esters', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Mixed esters. Common emulsifier blend.',
+ scholarlyNote: 'Check source. Plant-based = halal.' },
+ { eNumber: 'E473', name: 'Sucrose Esters of Fatty Acids', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Sugar ester. Fatty acid source may be animal or plant.',
+ scholarlyNote: 'Must verify the fatty acid source.' },
+ { eNumber: 'E474', name: 'Sucroglycerides', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Combination of sucrose esters and glycerides.',
+ scholarlyNote: 'Same verification needed as E471/E473.' },
+ { eNumber: 'E475', name: 'Polyglycerol Esters of FA', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Polyglycerol esters. Used in margarine, cakes, and desserts.',
+ scholarlyNote: 'Animal or plant source β halal certification recommended.' },
+ { eNumber: 'E476', name: 'Polyglycerol Polyricinoleate', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'PGPR β used in chocolate to reduce cocoa butter content. The glycerol source determines status.',
+ scholarlyNote: 'The glycerol backbone may be animal or plant-derived. With halal certification on chocolate, PGPR is typically plant-based.' },
+ { eNumber: 'E477', name: 'Propylene Glycol Esters of FA', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Propylene glycol esters. Fatty acid component needs verification.',
+ scholarlyNote: 'Verify source of fatty acids.' },
+ { eNumber: 'E478', name: 'Lactylated Fatty Acid Esters', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Glycerol and fatty acid esters, lactylated.',
+ scholarlyNote: 'Dependent on source materials.' },
+ { eNumber: 'E479b', name: 'Thermally Oxidized Soy Bean Oil', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Used as a release agent in frying. Soy is halal, but processing aids may not be.',
+ scholarlyNote: 'Generally halal if no cross-contamination with haram oils.' },
+ { eNumber: 'E481', name: 'Sodium Stearoyl Lactylate', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'SSL β a common dough strengthener in commercial bread. The stearic acid may be animal or plant-derived.',
+ scholarlyNote: 'Stearic acid source determines halal status. Most commercial SSL is plant-derived but verification is recommended.' },
+ { eNumber: 'E482', name: 'Calcium Stearoyl Lactylate', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'CSL β same concerns as SSL (E481).',
+ scholarlyNote: 'Same ruling as E481.' },
+ { eNumber: 'E483', name: 'Stearyl Tartrate', status: 'mushbooh',
+ category: 'Flour Treatment Agent',
+ explanation: 'Dough strengthener. The stearyl component may be from animal fat.',
+ scholarlyNote: 'Verify source with manufacturer.' },
+ { eNumber: 'E491', name: 'Sorbitan Monostearate', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'The stearic acid portion may be animal or plant-derived.',
+ scholarlyNote: 'Plant-based = halal. Animal-based requires halal slaughter.' },
+ { eNumber: 'E492', name: 'Sorbitan Tristearate', status: 'mushbooh',
+ category: 'Emulsifier', explanation: 'Same concerns as E491.', scholarlyNote: 'Same ruling as E491.' },
+ { eNumber: 'E493', name: 'Sorbitan Monolaurate', status: 'mushbooh',
+ category: 'Emulsifier', explanation: 'Lauric acid from coconut or palm. Generally plant-based.',
+ scholarlyNote: 'Likely halal β lauric acid is typically from coconut/palm kernel oil.' },
+ { eNumber: 'E494', name: 'Sorbitan Monooleate', status: 'mushbooh',
+ category: 'Emulsifier', explanation: 'Oleic acid component.', scholarlyNote: 'Verify oleic acid source.' },
+ { eNumber: 'E495', name: 'Sorbitan Monopalmitate', status: 'mushbooh',
+ category: 'Emulsifier', explanation: 'Palmitic acid component.', scholarlyNote: 'Verify palmitic acid source.' },
+ { eNumber: 'E570', name: 'Stearic Acid', status: 'mushbooh',
+ category: 'Anti-caking Agent',
+ explanation: 'Can be derived from animal fat (tallow) or plant oils (palm, coconut). Very widely used.',
+ scholarlyNote: 'Plant-derived stearic acid is halal. Animal-derived requires halal slaughter. Halal certification clarifies this.' },
+ { eNumber: 'E322', name: 'Lecithin', status: 'mushbooh',
+ category: 'Emulsifier',
+ explanation: 'Commonly from soy (halal) or egg yolk (halal if from halal chicken). Rarely animal-derived. Most commercial lecithin is soy-based.',
+ scholarlyNote: 'Soy lecithin is halal. Egg lecithin is halal. Only concern is if animal-derived (rare).' },
+ { eNumber: 'E422', name: 'Glycerol / Glycerin', status: 'mushbooh',
+ category: 'Humectant',
+ explanation: 'Can be from plant oils, animal fats, or petroleum. Used as a sweetener, humectant, and solvent.',
+ scholarlyNote: 'Plant/petroleum glycerol is halal. Animal-derived requires halal slaughter. Halal-certified products use plant glycerol.' },
+ { eNumber: 'E626', name: 'Guanylic Acid', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'May use animal enzymes in production.',
+ scholarlyNote: 'Check with manufacturer if animal enzymes were used.' },
+ { eNumber: 'E627', name: 'Sodium Guanylate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Sodium salt of guanylic acid. Same concerns.',
+ scholarlyNote: 'Same ruling as E626.' },
+ { eNumber: 'E628', name: 'Potassium Guanylate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Potassium salt of guanylic acid.',
+ scholarlyNote: 'Same ruling as E626.' },
+ { eNumber: 'E629', name: 'Calcium Guanylate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Calcium salt of guanylic acid.',
+ scholarlyNote: 'Same ruling as E626.' },
+ { eNumber: 'E630', name: 'Inosinic Acid', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'May be produced using animal enzymes.',
+ scholarlyNote: 'Verify production method with manufacturer.' },
+ { eNumber: 'E631', name: 'Sodium Inosinate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Common in instant noodles and snacks. Often produced with animal enzymes.',
+ scholarlyNote: 'JAKIM requires halal-certified E631. Without certification, it is doubtful.' },
+ { eNumber: 'E632', name: 'Potassium Inosinate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Same concerns as E631.',
+ scholarlyNote: 'Same ruling as E631.' },
+ { eNumber: 'E633', name: 'Calcium Inosinate', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Same concerns.',
+ scholarlyNote: 'Same ruling as E631.' },
+ { eNumber: 'E634', name: 'Calcium 5-Ribonucleotides', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Blend of guanylate and inosinate.',
+ scholarlyNote: 'Halal certification recommended due to potential animal enzymes.' },
+ { eNumber: 'E635', name: 'Disodium 5-Ribonucleotides', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'I+G β very common in snacks, chips, instant noodles.',
+ scholarlyNote: 'Commonly uses animal enzymes. Look for halal logo or avoid if uncertified.' },
+ { eNumber: 'E640', name: 'Glycine', status: 'mushbooh',
+ category: 'Flavour Enhancer', explanation: 'Can be from animal or plant protein.',
+ scholarlyNote: 'Plant-derived glycine is halal. Verify source.' },
+ { eNumber: 'E901', name: 'Beeswax', status: 'mushbooh',
+ category: 'Glazing Agent',
+ explanation: 'Natural wax from honeybees. Generally considered halal by most scholars as it is a plant/insect secretion, not the insect itself.',
+ scholarlyNote: 'Majority of scholars (Shafi\'i, Hanafi) consider beeswax halal. Some scholars are cautious.' },
+ { eNumber: 'E1103', name: 'Invertase', status: 'mushbooh',
+ category: 'Enzyme', explanation: 'May be animal or microbial source.',
+ scholarlyNote: 'Microbial invertase is halal. Animal-derived needs verification.' },
+ { eNumber: 'E1105', name: 'Lysozyme', status: 'mushbooh',
+ category: 'Preservative',
+ explanation: 'Usually derived from egg white. Halal if from halal chicken eggs. Rarely from other animal sources.',
+ scholarlyNote: 'Egg-derived lysozyme from halal sources is halal. Check source.' },
+
+ // ββ NON-E-NUMBER MUSHBOOH ββββββββββββββββββββββββββββββ
+ { eNumber: 'RENNET', name: 'Rennet', status: 'mushbooh',
+ category: 'Enzyme',
+ explanation: 'Used in cheese-making. Can be animal-derived (calf stomach), microbial, or plant-based. Animal rennet requires halal slaughter.',
+ scholarlyNote: 'Microbial/plant rennet is halal. Animal rennet from non-halal-slaughtered animals is haram. Many commercial cheeses now use microbial rennet.' },
+ { eNumber: 'WHEY', name: 'Whey', status: 'mushbooh',
+ category: 'Dairy Derivative',
+ explanation: 'By-product of cheese-making. Halal status depends on the rennet used in the cheese production.',
+ scholarlyNote: 'If made with microbial/plant rennet or halal animal rennet, whey is halal. If made with haram rennet, whey is haram.' },
+ { eNumber: 'PEPSIN', name: 'Pepsin', status: 'mushbooh',
+ category: 'Enzyme',
+ explanation: 'Digestive enzyme, commonly from pig stomach. Can also be synthetic.',
+ scholarlyNote: 'Porcine pepsin is haram. Synthetic or plant-derived alternatives exist β verify source.' },
+ { eNumber: 'TRYPSIN', name: 'Trypsin', status: 'mushbooh',
+ category: 'Enzyme', explanation: 'Digestive enzyme from animal pancreas.',
+ scholarlyNote: 'Animal-derived trypsin from non-halal sources is haram. Microbial alternatives are halal.' },
+ { eNumber: 'LIPASE', name: 'Lipase', status: 'mushbooh',
+ category: 'Enzyme',
+ explanation: 'Fat-digesting enzyme. Can be from animal pancreas, calf stomach, or microbial sources.',
+ scholarlyNote: 'Microbial lipase is halal. Animal-derived lipase requires verification of halal slaughter.' },
+
+ // ββ HALAL (CONFIRMED SAFE) βββββββββββββββββββββββββββββ
+ { eNumber: 'E100', name: 'Curcumin', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Natural yellow colour from turmeric root. Plant-derived.',
+ scholarlyNote: 'Universally halal β pure plant extract.' },
+ { eNumber: 'E101', name: 'Riboflavin (Vitamin B2)', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Naturally present in many foods. Synthetically produced for food use.',
+ scholarlyNote: 'Halal β synthetic production avoids animal concerns.' },
+ { eNumber: 'E140', name: 'Chlorophyll', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Green pigment from plants (alfalfa, nettles).',
+ scholarlyNote: 'Pure plant derivative β halal.' },
+ { eNumber: 'E150a', name: 'Plain Caramel', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Caramelized sugar. No animal products involved.',
+ scholarlyNote: 'Halal β sugar-based.' },
+ { eNumber: 'E160a', name: 'Beta-Carotene', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Orange pigment from carrots, sweet potatoes, or synthetic production.',
+ scholarlyNote: 'Halal β plant-derived or synthetic.' },
+ { eNumber: 'E162', name: 'Beetroot Red', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Natural red colour from beetroot.',
+ scholarlyNote: 'Pure plant extract β halal.' },
+ { eNumber: 'E163', name: 'Anthocyanins', status: 'halal',
+ category: 'Colouring Agent', explanation: 'Red/blue/purple pigments from grape skins and other fruits.',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E170', name: 'Calcium Carbonate', status: 'halal',
+ category: 'Colouring Agent / Mineral', explanation: 'Natural mineral (limestone, chalk).',
+ scholarlyNote: 'Mineral source β halal.' },
+ { eNumber: 'E200', name: 'Sorbic Acid', status: 'halal',
+ category: 'Preservative', explanation: 'Synthetic or from rowan berries.',
+ scholarlyNote: 'Halal β no animal involvement.' },
+ { eNumber: 'E201', name: 'Sodium Sorbate', status: 'halal',
+ category: 'Preservative', explanation: 'Sodium salt of sorbic acid.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E202', name: 'Potassium Sorbate', status: 'halal',
+ category: 'Preservative', explanation: 'Potassium salt of sorbic acid.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E203', name: 'Calcium Sorbate', status: 'halal',
+ category: 'Preservative', explanation: 'Calcium salt of sorbic acid.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E210', name: 'Benzoic Acid', status: 'halal',
+ category: 'Preservative', explanation: 'Synthetic preservative.',
+ scholarlyNote: 'Halal β synthetic.' },
+ { eNumber: 'E211', name: 'Sodium Benzoate', status: 'halal',
+ category: 'Preservative', explanation: 'Sodium salt of benzoic acid.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E260', name: 'Acetic Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Vinegar component. Synthetically produced for food use.',
+ scholarlyNote: 'Halal β synthetic or fermentation-derived.' },
+ { eNumber: 'E270', name: 'Lactic Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Fermentation-derived, typically from plant sugars.',
+ scholarlyNote: 'Halal unless specifically from animal milk in a non-halal context (extremely rare).' },
+ { eNumber: 'E290', name: 'Carbon Dioxide', status: 'halal',
+ category: 'Propellant', explanation: 'The gas that makes drinks fizzy.',
+ scholarlyNote: 'Universally halal.' },
+ { eNumber: 'E296', name: 'Malic Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Fruit acid from apples. Synthetic production common.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E300', name: 'Ascorbic Acid (Vitamin C)', status: 'halal',
+ category: 'Antioxidant', explanation: 'Synthetic vitamin C. No animal source.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E306', name: 'Tocopherols (Vitamin E)', status: 'halal',
+ category: 'Antioxidant', explanation: 'From plant oils (soy, sunflower, corn).',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E330', name: 'Citric Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Fermented from molasses or corn. Most common food acid.',
+ scholarlyNote: 'Universally halal β fermentation product.' },
+ { eNumber: 'E334', name: 'Tartaric Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'From grapes (wine industry by-product).',
+ scholarlyNote: 'Halal β the acid is chemically distinct from alcohol and does not intoxicate.' },
+ { eNumber: 'E338', name: 'Phosphoric Acid', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Mineral acid. Used in cola drinks.',
+ scholarlyNote: 'Mineral source β halal.' },
+ { eNumber: 'E400', name: 'Alginic Acid', status: 'halal',
+ category: 'Thickener', explanation: 'From brown seaweed.',
+ scholarlyNote: 'Plant/marine source β halal.' },
+ { eNumber: 'E401', name: 'Sodium Alginate', status: 'halal',
+ category: 'Thickener', explanation: 'Sodium salt of alginic acid.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E406', name: 'Agar', status: 'halal',
+ category: 'Gelling Agent', explanation: 'From red algae (seaweed). Common in Asian desserts.',
+ scholarlyNote: 'Universally halal β pure seaweed extract.' },
+ { eNumber: 'E407', name: 'Carrageenan', status: 'halal',
+ category: 'Thickener', explanation: 'From red seaweed (Irish moss).',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E410', name: 'Locust Bean Gum', status: 'halal',
+ category: 'Thickener', explanation: 'From carob tree seeds.',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E412', name: 'Guar Gum', status: 'halal',
+ category: 'Thickener', explanation: 'From guar beans.',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E414', name: 'Gum Arabic', status: 'halal',
+ category: 'Thickener', explanation: 'From acacia tree sap.',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E415', name: 'Xanthan Gum', status: 'halal',
+ category: 'Thickener', explanation: 'Fermentation product from corn sugar.',
+ scholarlyNote: 'Halal β fermentation-derived from plant sugars.' },
+ { eNumber: 'E440', name: 'Pectin', status: 'halal',
+ category: 'Gelling Agent', explanation: 'From apple pomace and citrus peel.',
+ scholarlyNote: 'Universally halal β pure fruit extract.' },
+ { eNumber: 'E466', name: 'Carboxymethylcellulose', status: 'halal',
+ category: 'Thickener', explanation: 'Modified plant cellulose.',
+ scholarlyNote: 'Plant-derived β halal.' },
+ { eNumber: 'E500', name: 'Sodium Carbonates', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Baking soda, soda ash. Mineral source.',
+ scholarlyNote: 'Mineral source β halal.' },
+ { eNumber: 'E501', name: 'Potassium Carbonates', status: 'halal',
+ category: 'Acidity Regulator', explanation: 'Mineral source.',
+ scholarlyNote: 'Halal β mineral-derived.' },
+ { eNumber: 'E509', name: 'Calcium Chloride', status: 'halal',
+ category: 'Firming Agent', explanation: 'Mineral salt.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E551', name: 'Silicon Dioxide', status: 'halal',
+ category: 'Anti-caking Agent', explanation: 'Silica β sand-derived mineral.',
+ scholarlyNote: 'Mineral β halal.' },
+ { eNumber: 'E621', name: 'MSG (Monosodium Glutamate)', status: 'halal',
+ category: 'Flavour Enhancer', explanation: 'Fermented from molasses, tapioca, or corn. Plant-based fermentation.',
+ scholarlyNote: 'Halal β fermentation product. Note: not the same as E631/E635 which are often animal-derived.' },
+ { eNumber: 'E901', name: 'Beeswax', status: 'mushbooh',
+ category: 'Glazing Agent', explanation: 'See mushbooh section.',
+ scholarlyNote: 'Majority halal per JAKIM/MUI. Some scholars more cautious.' },
+ { eNumber: 'E950', name: 'Acesulfame K', status: 'halal',
+ category: 'Sweetener', explanation: 'Synthetic sweetener.',
+ scholarlyNote: 'Halal β synthetic.' },
+ { eNumber: 'E951', name: 'Aspartame', status: 'halal',
+ category: 'Sweetener', explanation: 'Synthetic dipeptide sweetener.',
+ scholarlyNote: 'Halal β synthetic. No animal-derived components.' },
+ { eNumber: 'E954', name: 'Saccharin', status: 'halal',
+ category: 'Sweetener', explanation: 'Synthetic sweetener.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E955', name: 'Sucralose', status: 'halal',
+ category: 'Sweetener', explanation: 'Chlorinated sugar derivative.',
+ scholarlyNote: 'Halal β synthetic.' },
+ { eNumber: 'E965', name: 'Maltitol', status: 'halal',
+ category: 'Sweetener', explanation: 'Sugar alcohol from starch.',
+ scholarlyNote: 'Halal β plant starch source.' },
+ { eNumber: 'E967', name: 'Xylitol', status: 'halal',
+ category: 'Sweetener', explanation: 'Sugar alcohol from birch bark or corn.',
+ scholarlyNote: 'Halal β plant source.' },
+ { eNumber: 'E968', name: 'Erythritol', status: 'halal',
+ category: 'Sweetener', explanation: 'Fermented sugar alcohol.',
+ scholarlyNote: 'Halal.' },
+ { eNumber: 'E1404', name: 'Oxidized Starch', status: 'halal',
+ category: 'Thickener', explanation: 'Modified plant starch.',
+ scholarlyNote: 'Halal β plant source.' },
+ { eNumber: 'E1520', name: 'Propylene Glycol', status: 'halal',
+ category: 'Humectant', explanation: 'Synthetic. Not to be confused with animal-derived glycerol.',
+ scholarlyNote: 'Halal β petrochemical derivative, not animal-based.' },
+];
+
+/** Look up an ingredient by E-number (case-insensitive) */
+export function findByENumber(code) {
+ const upper = String(code).toUpperCase().trim();
+ return HARAM_INGREDIENTS.find(i => i.eNumber.toUpperCase() === upper) || null;
+}
+
+/** Look up ingredient by name (fuzzy) */
+export function findByName(name) {
+ const lower = name.toLowerCase().trim();
+ return HARAM_INGREDIENTS.find(i => i.name.toLowerCase().includes(lower))
+ || HARAM_INGREDIENTS.find(i => lower.includes(i.name.toLowerCase()))
+ || null;
+}
+
+/** Resolve an ingredient string (E-number, alias, or name) to its DB entry */
+export function resolveIngredient(raw) {
+ const trimmed = raw.trim();
+ if (!trimmed) return null;
+
+ // Try direct E-number match
+ const enMatch = findByENumber(trimmed);
+ if (enMatch) return enMatch;
+
+ // Try alias lookup
+ const key = trimmed.toLowerCase();
+ const canonical = INGREDIENT_ALIASES[key];
+ if (canonical) {
+ const aliasMatch = findByENumber(canonical);
+ if (aliasMatch) return aliasMatch;
+ }
+
+ // Try name match
+ return findByName(trimmed);
+}
+
+/** Get certification body by ID */
+export function getCert(id) {
+ return CERTIFICATION_BODIES.find(c => c.id === id) || null;
+}
+
+/** Calculate halal confidence score (0-100) */
+export function calculateConfidence(restaurant) {
+ if (!restaurant) return 0;
+ const certs = (restaurant.certifications || []).map(c => getCert(c)).filter(Boolean);
+ const maxTrust = certs.length > 0 ? Math.max(...certs.map(c => c.trustLevel)) : 0;
+ const certScore = maxTrust * 15;
+ const ratingScore = (restaurant.rating || 0) * 4;
+ const reviewCount = (restaurant.userReviews || []).length;
+ const communityScore = Math.min(reviewCount * 2, 20);
+ const ownerClaimScore = restaurant.muslimOwned ? 5 : 0;
+ return Math.min(Math.round(certScore + ratingScore + communityScore + ownerClaimScore), 100);
+}
+
+/** Get confidence color class */
+export function confidenceColor(score) {
+ if (score >= 80) return '#16a34a';
+ if (score >= 50) return '#d97706';
+ if (score >= 30) return '#f59e0b';
+ return '#9ca3af';
+}
+
+/** Get certification badge color */
+export function certBadgeColor(restaurant) {
+ const certs = (restaurant.certifications || []).map(c => getCert(c)).filter(Boolean);
+ if (certs.some(c => c.trustLevel >= 4)) return '#16a34a';
+ if (certs.length > 0) return '#d97706';
+ if (restaurant.muslimOwned) return '#d97706';
+ return '#9ca3af';
+}
+
+/** Get certification status label */
+export function certStatusLabel(restaurant) {
+ const certs = (restaurant.certifications || []).map(c => getCert(c)).filter(Boolean);
+ if (certs.some(c => c.trustLevel >= 4)) {
+ const names = certs.filter(c => c.trustLevel >= 4).map(c => c.name).join(', ');
+ return `β
Certified: ${names}`;
+ }
+ if (certs.length > 0) {
+ const names = certs.map(c => c.name).join(', ');
+ return `π Self-Claimed: ${names}`;
+ }
+ if (restaurant.muslimOwned) return 'π€ Muslim-Owned (Uncertified)';
+ return 'β Status Unknown';
+}
diff --git a/vite.config.js b/vite.config.js
index c8d4d51..b5678e0 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -27,6 +27,21 @@ export default defineConfig({
urlPattern: /^https:\/\/api\.alquran\.cloud\/.*/i,
handler: 'StaleWhileRevalidate',
options: { cacheName: 'quran-api', expiration: { maxEntries: 50, maxAgeSeconds: 86400 * 7 } }
+ },
+ {
+ urlPattern: /^https:\/\/unpkg\.com\/leaflet.*/i,
+ handler: 'CacheFirst',
+ options: { cacheName: 'leaflet-lib', expiration: { maxEntries: 5, maxAgeSeconds: 86400 * 30 } }
+ },
+ {
+ urlPattern: /^https:\/\/.*\.tile\.openstreetmap\.org\/.*/i,
+ handler: 'StaleWhileRevalidate',
+ options: { cacheName: 'osm-tiles', expiration: { maxEntries: 200, maxAgeSeconds: 86400 * 7 } }
+ },
+ {
+ urlPattern: /^https:\/\/cdn\.jsdelivr\.net\/npm\/tesseract\.js.*/i,
+ handler: 'CacheFirst',
+ options: { cacheName: 'tesseract', expiration: { maxEntries: 10, maxAgeSeconds: 86400 * 30 } }
}
]
}